You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

660 lines
15 KiB

;======================================================================
;
; AY-3-8910 / YM2149 SOUND DRIVER
;
;======================================================================
;
#IF (AYMODE == AYMODE_SCG)
AY_RSEL .EQU $9A
AY_RDAT .EQU $9B
AY_ACR .EQU $9C
#ENDIF
;
#IF (AYMODE == AYMODE_N8)
AY_RSEL .EQU $9C
AY_RDAT .EQU $9D
AY_ACR .EQU N8_DEFACR
#ENDIF
;
#IF (AYMODE == AYMODE_RCZ80)
AY_RSEL .EQU $D8
AY_RDAT .EQU $D0
#ENDIF
;
#IF (AYMODE == AYMODE_RCZ180)
AY_RSEL .EQU $68
AY_RDAT .EQU $60
#ENDIF
;
;======================================================================
;
; REGISTERS
;
AY_R0CHAP .EQU $00
AY_R1CHAP .EQU $01
AY_R2CHBP .EQU $02
AY_R3CHBP .EQU $03
AY_R7ENAB .EQU $07
AY_R8AVOL .EQU $08
AY_R9BVOL .EQU $09
;
;======================================================================
;
; DRIVER FUNCTION TABLE AND INSTANCE DATA
;
AY_FNTBL:
.DW AY_RESET
.DW AY_VOLUME
.DW AY_PERIOD
.DW AY_NOTE
.DW AY_PLAY
.DW AY_QUERY
#IF (($ - AY_FNTBL) != (SND_FNCNT * 2))
.ECHO "*** INVALID SND FUNCTION TABLE ***\n"
!!!!!
#ENDIF
;
AY_IDAT .EQU 0 ; NO INSTANCE DATA ASSOCIATED WITH THIS DEVICE
;
;======================================================================
;
; DEVICE CAPABILITIES AND CONFIGURATION
AY_TONECNT .EQU 3 ; COUNT NUMBER OF TONE CHANNELS
AY_NOISECNT .EQU 1 ; COUNT NUMBER OF NOISE CHANNELS
;
AY_CLKDIVIDER .EQU 2
AY_CLK .EQU CPUOSC / AY_CLKDIVIDER
SN7RATIO .EQU AY_CLK * 100 / 32
AY_FIRST_NOTE .EQU 5827 ; A1#
AY_LAST_NOTE .EQU 209300 ; C7
A1S .EQU SN7RATIO / AY_FIRST_NOTE
C7 .EQU SN7RATIO / AY_LAST_NOTE
.ECHO "AY-3-8910: range of A1# (period: "
.ECHO A1S
.ECHO ") to C7 (period: "
.ECHO C7
.ECHO ")\n"
#INCLUDE "audio.inc"
;======================================================================
;
; DRIVER INITIALIZATION (THERE IS NO PRE-INITIALIZATION)
;
; ANNOUNCE DEVICE ON CONSOLE. ACTIVATE DEVICE IF REQUIRED.
; SETUP FUNCTION TABLES. SETUP THE DEVICE.
; ANNOUNCE DEVICE WITH BEEP. SET VOLUME OFF.
; RETURN SUCCESS STATUS
;
AY38910_INIT:
CALL NEWLINE ; ANNOUNCE
PRTS("AY: IO=0x$")
LD A,AY_RSEL
CALL PRTHEXBYTE
;
#IF ((AYMODE == AYMODE_SCG) | (AYMODE == AYMODE_N8))
; ACTIVATE DEVICE
LD A,$FF ; BIT 4 IS AY RESET CONTROL, BIT 3 IS ACTIVE LED
OUT (AY_ACR),A ; SET INIT AUX CONTROL REG
#ENDIF
;
LD IY, AY_IDAT ; SETUP FUNCTION TABLE
LD BC, AY_FNTBL ; POINTER TO INSTANCE DATA
LD DE, AY_IDAT ; BC := FUNCTION TABLE ADDRESS
CALL SND_ADDENT ; DE := INSTANCE DATA PTR
;
CALL AY_RESET ; SET DEFAULT CHIP CONFIGURATION
; CALL AY_BEEP ; PLAY INITIALIZATION BEEP
; CALL AY_VOLUME_OFF ; MAKE QUIET
;
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - RESET
;======================================================================
;
AY_RESET:
AUDTRACE(TRACE_INIT)
;
LD D,AY_R7ENAB ; SET MIXER CONTROL / IO ENABLE
LD E,$FF ; $FF - 11 111 111
CALL AY_WRTPSG ; I/O PORTS = OUTPUT, NOISE CHANNEL C, B, A DISABLE, TONE CHANNEL C, B, A DISABLE
; CALL AY_VOLUME_OFF ; TURN VOLUME OFF
; RET ; AND RETURN SUCCESS
AY_VOLUME_OFF:
AUDTRACE(TRACE_VOLUME_OFF)
LD B,AY_TONECNT ; NUMBER OF CHANNELS
LD D,AY_R8AVOL ; BASE REGISTER FOR VOLUME
LD E,$00 ; AMPLITUDE 0
AY_V:
CALL AY_WRTPSG ; CYCLING THROUGH ALL CHANNELS
INC D
DJNZ AY_V
;
XOR A ; SIGNAL SUCCESS
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - VOLUME
;======================================================================
;
AY_VOLUME:
AUDDEBUG("AY3VOL ")
AUDTRACE_L
AUDDEBUG("\r\n")
LD A,L ; SAVE VOLUME
LD (PENDING_VOLUME), A
;
XOR A ; SIGNAL SUCCESS
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - PERIOD
;======================================================================
;
AY_PERIOD:
AUDDEBUG("AY3PRD ")
AUDTRACE_HL
AUDDEBUG("\r\n")
INC HL ; MAXIMUM TONE PERIOD IS 12-BITS
LD A, H ; ALLOWED RANGE IS 0001-0FFF (4095)
CP $10 ; SO OFFSET AND CHECK OF OVERFLOW
JP NC, AY_QUERY_PERIOD1 ; RETURN NZ IF NUMBER TOO LARGE
LD (PENDING_PERIOD), HL ; SAVE AND
XOR A ; SIGNAL SUCCESS
RET
AY_QUERY_PERIOD1:
LD L, $FF
LD H, L ; REQUESTED PERIOD IS LARGER
LD (PENDING_PERIOD), HL ; THAN THE DEVICE CAN SUPPORT
OR L ; SO SIGNAL FAILURE
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - NOTE
;======================================================================
;
AY_NOTE:
AUDDEBUG("AY3NOT ")
AUDTRACE_L
AUDDEBUG("\r\n")
ADD HL, HL ; SHIFT RIGHT (MULT 2) -INDEX INTO AY3NOTETBL TABLE OF WORDS
; TEST IF HL IS LARGER THAN AY3NOTETBL SIZE
OR A ; CLEAR CARRY FLAG
LD DE, SIZ_AY3NOTETBL
SBC HL, DE
JR NC, AY_NOTE1 ; INCOMING HL DOES NOT MAP INTO AY3NOTETBL
ADD HL, DE ; RESTORE HL
LD E, L ; HL = AY3NOTETBL + HL
LD D, H
LD HL, AY3NOTETBL
ADD HL, DE
LD A, (HL) ; RETRIEVE PERIOD COUNT FROM AY3NOTETBL
INC HL
LD H, (HL)
LD L, A
JR AY_PERIOD ; APPLY PERIOD
AY_NOTE1:
OR $FF ; NOT IMPLEMENTED YET
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - PLAY
;======================================================================
;
AY_PLAY:
AUDDEBUG("AY3PLY ")
AUDTRACE_D
AUDDEBUG("\r\n")
;
LD A, (PENDING_PERIOD + 1) ; CHECK THE HIGH BYTE OF THE PERIOD
CP $FF
JR Z, AY_PLAY1 ; PERIOD IS TOO LARGE, UNABLE TO PLAY
CALL AY_APPLY_VOL
CALL AY_APPLY_PRD
;
XOR A ; SIGNAL SUCCESS
RET
;
AY_PLAY1: ; TURN CHANNEL VOL TO OFF AND STOP PLAYING
LD A, (PENDING_VOLUME)
PUSH AF
XOR A
LD (PENDING_VOLUME), A
CALL AY_APPLY_VOL
POP AF
LD (PENDING_VOLUME), A
;
OR $FF ; SIGNAL FAILURE
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - QUERY AND SUBFUNCTIONS
;======================================================================
;
AY_QUERY:
LD A, E
CP BF_SNDQ_CHCNT ; SUB FUNCTION 01
JR Z, AY_QUERY_CHCNT
;
CP BF_SNDQ_VOLUME ; SUB FUNCTION 02
JR Z, AY_QUERY_VOLUME
;
CP BF_SNDQ_PERIOD ; SUB FUNCTION 03
JR Z, AY_QUERY_PERIOD
;
CP BF_SNDQ_DEV ; SUB FUNCTION 04
JR Z, AY_QUERY_DEV
;
OR $FF ; SIGNAL FAILURE
RET
;
AY_QUERY_CHCNT:
LD B, AY_TONECNT ; RETURN NUMBER OF
LD C, AY_NOISECNT ; TONE AND NOISE
XOR A ; CHANNELS IN BC
RET
;
AY_QUERY_PERIOD:
LD HL, (PENDING_PERIOD) ; RETURN 16-BIT PERIOD
XOR A ; IN HL REGISTER
RET
;
AY_QUERY_VOLUME:
LD A, (PENDING_VOLUME) ; RETURN 8-BIT VOLUME
LD L, A ; IN L REGISTER
XOR A
LD H, A
RET
;
AY_QUERY_DEV:
LD B, BF_SND_AY38910 ; RETURN DEVICE IDENTIFIER
LD DE, (AY_RSEL*256)+AY_RDAT ; AND ADDRESS AND DATA PORT
XOR A
RET
;
;======================================================================
; APPLY VOLUME TO CHANNEL IN D REGISTER
;======================================================================
;
AY_APPLY_VOL:
PUSH DE
PUSH BC
PUSH AF
;
LD A,D ; LIMIT CHANNEL 0-2
AND $3 ; AND INDEX TO THE
ADD A,AY_R8AVOL ; CHANNEL VOLUME
LD D,A ; REGISTER
;
AUDTRACE(TRACE_REG_WR)
AUDTRACE_A
AUDTRACE(TRACE_NEWLINE)
;
LD A, (PENDING_VOLUME) ; MAP THE VOLUME
RRCA ; FROM 00-FF
RRCA ; TO 00-0F
RRCA
RRCA
AND $0F
LD E,A
;
CALL AY_WRTPSG ; SET VOL (E) IN CHANNEL REG (D)
;
POP AF
POP BC
POP DE
RET
;
;======================================================================
; APPLY PERIOD TO CHANNEL IN D REGISTER
;======================================================================
;
AY_APPLY_PRD:
PUSH DE
PUSH BC
PUSH AF
;
LD A,D ; LIMIT CHANNEL 0-2
AND $3 ; AND INDEX TO THE
ADD A,A ; CHANNEL REGISTER
LD D,A ; FOR THE TONE PERIOD
;
AUDTRACE(TRACE_REG_WR)
AUDTRACE_A
AUDTRACE(TRACE_NEWLINE)
;
LD HL,(PENDING_PERIOD) ; WRITE THE LOWER
LD E,L ; 8-BITS OF THE PERIOD
CALL AY_WRTPSG
INC D
LD E,H ; WRITE THE UPPER
CALL AY_WRTPSG ; 8-BITS OF THE PERIOD
;
POP AF
POP BC
POP DE
RET
;
;======================================================================
;
; WRITE DATA IN E REGISTER TO DEVICE REGISTER D
; INTERRUPTS DISABLE DURING WRITE. WRITE IN SLOW MODE IF Z180 CPU.
;
;======================================================================
;
AY_WRTPSG:
HB_DI
#IF (CPUFAM == CPU_Z180)
IN0 A,(Z180_DCNTL) ; GET WAIT STATES
PUSH AF ; SAVE VALUE
OR %00110000 ; FORCE SLOW OPERATION (I/O W/S=3)
OUT0 (Z180_DCNTL),A ; AND UPDATE DCNTL
#ENDIF
LD A,D ; SELECT THE REGISTER WE
OUT (AY_RSEL),A ; WANT TO WRITE TO
LD A,E ; WRITE THE VALUE TO
OUT (AY_RDAT),A ; THE SELECTED REGISTER
#IF (CPUFAM == CPU_Z180)
POP AF ; GET SAVED DCNTL VALUE
OUT0 (Z180_DCNTL),A ; AND RESTORE IT
#ENDIF
HB_EI
RET
;
;======================================================================
;
PENDING_PERIOD
.DW 0 ; PENDING PERIOD (10 BITS)
PENDING_VOLUME
.DB 0 ; PENDING VOL (8 BITS -> DOWNCONVERTED TO 4 BITS AND INVERTED)
#IF AUDIOTRACE
TRACE_INIT .DB "\r\nAY_INIT CALLED\r\n$"
TRACE_VOLUME_OFF .DB "\r\nAY_VOLUME_OFF\r\n$"
TRACE_VOLUME_SET .DB "\r\nAY_VOLUME_SET CH: $"
TRACE_PLAY .DB "\r\nPLAY\r\n$"
TRACE_VOLUME .DB ", VOL: $"
TRACE_PORT_WR .DB "\r\nOUT AY-3-8910 $"
TRACE_PERIOD_SET .DB "\r\nAY_PERIOD_SET CH: $"
TRACE_PERIOD .DB ", PERIOD: $"
TRACE_NEWLINE .DB "\r\n$"
#ENDIF
; THE FREQUENCY BY QUATER TONE STARTING AT A1#
AY3NOTETBL:
.DW A1S
.DW SN7RATIO / 5912
.DW SN7RATIO / 5998
.DW SN7RATIO / 6085
.DW SN7RATIO / 6174
.DW SN7RATIO / 6264
.DW SN7RATIO / 6355
.DW SN7RATIO / 6447
.DW SN7RATIO / 6541
.DW SN7RATIO / 6636
.DW SN7RATIO / 6733
.DW SN7RATIO / 6831
.DW SN7RATIO / 6930
.DW SN7RATIO / 7031
.DW SN7RATIO / 7133
.DW SN7RATIO / 7237
.DW SN7RATIO / 7342
.DW SN7RATIO / 7449
.DW SN7RATIO / 7557
.DW SN7RATIO / 7667
.DW SN7RATIO / 7778
.DW SN7RATIO / 7891
.DW SN7RATIO / 8006
.DW SN7RATIO / 8122
.DW SN7RATIO / 8241
.DW SN7RATIO / 8361
.DW SN7RATIO / 8482
.DW SN7RATIO / 8606
.DW SN7RATIO / 8731
.DW SN7RATIO / 8858
.DW SN7RATIO / 8987
.DW SN7RATIO / 9118
.DW SN7RATIO / 9250
.DW SN7RATIO / 9385
.DW SN7RATIO / 9521
.DW SN7RATIO / 9660
.DW SN7RATIO / 9800
.DW SN7RATIO / 9943
.DW SN7RATIO / 10087
.DW SN7RATIO / 10234
.DW SN7RATIO / 10383
.DW SN7RATIO / 10534
.DW SN7RATIO / 10687
.DW SN7RATIO / 10843
.DW SN7RATIO / 11000
.DW SN7RATIO / 11160
.DW SN7RATIO / 11322
.DW SN7RATIO / 11487
.DW SN7RATIO / 11654
.DW SN7RATIO / 11824
.DW SN7RATIO / 11995
.DW SN7RATIO / 12170
.DW SN7RATIO / 12347
.DW SN7RATIO / 12527
.DW SN7RATIO / 12709
.DW SN7RATIO / 12894
.DW SN7RATIO / 13081
.DW SN7RATIO / 13271
.DW SN7RATIO / 13464
.DW SN7RATIO / 13660
.DW SN7RATIO / 13859
.DW SN7RATIO / 14061
.DW SN7RATIO / 14265
.DW SN7RATIO / 14473
.DW SN7RATIO / 14683
.DW SN7RATIO / 14897
.DW SN7RATIO / 15113
.DW SN7RATIO / 15333
.DW SN7RATIO / 15556
.DW SN7RATIO / 15782
.DW SN7RATIO / 16012
.DW SN7RATIO / 16245
.DW SN7RATIO / 16481
.DW SN7RATIO / 16721
.DW SN7RATIO / 16964
.DW SN7RATIO / 17211
.DW SN7RATIO / 17461
.DW SN7RATIO / 17715
.DW SN7RATIO / 17973
.DW SN7RATIO / 18234
.DW SN7RATIO / 18500
.DW SN7RATIO / 18769
.DW SN7RATIO / 19042
.DW SN7RATIO / 19319
.DW SN7RATIO / 19600
.DW SN7RATIO / 19885
.DW SN7RATIO / 20174
.DW SN7RATIO / 20468
.DW SN7RATIO / 20765
.DW SN7RATIO / 21067
.DW SN7RATIO / 21373
.DW SN7RATIO / 21684
.DW SN7RATIO / 22000
.DW SN7RATIO / 22320
.DW SN7RATIO / 22645
.DW SN7RATIO / 22974
.DW SN7RATIO / 23308
.DW SN7RATIO / 23647
.DW SN7RATIO / 23991
.DW SN7RATIO / 24340
.DW SN7RATIO / 24694
.DW SN7RATIO / 25053
.DW SN7RATIO / 25418
.DW SN7RATIO / 25787
.DW SN7RATIO / 26163
.DW SN7RATIO / 26544
.DW SN7RATIO / 26930
.DW SN7RATIO / 27321
.DW SN7RATIO / 27718
.DW SN7RATIO / 28121
.DW SN7RATIO / 28530
.DW SN7RATIO / 28945
.DW SN7RATIO / 29366
.DW SN7RATIO / 29793
.DW SN7RATIO / 30226
.DW SN7RATIO / 30666
.DW SN7RATIO / 31113
.DW SN7RATIO / 31566
.DW SN7RATIO / 32025
.DW SN7RATIO / 32490
.DW SN7RATIO / 32963
.DW SN7RATIO / 33442
.DW SN7RATIO / 33929
.DW SN7RATIO / 34422
.DW SN7RATIO / 34923
.DW SN7RATIO / 35431
.DW SN7RATIO / 35946
.DW SN7RATIO / 36469
.DW SN7RATIO / 36999
.DW SN7RATIO / 37537
.DW SN7RATIO / 38083
.DW SN7RATIO / 38637
.DW SN7RATIO / 39200
.DW SN7RATIO / 39770
.DW SN7RATIO / 40349
.DW SN7RATIO / 40936
.DW SN7RATIO / 41530
.DW SN7RATIO / 42134
.DW SN7RATIO / 42747
.DW SN7RATIO / 43369
.DW SN7RATIO / 44000
.DW SN7RATIO / 44640
.DW SN7RATIO / 45289
.DW SN7RATIO / 45948
.DW SN7RATIO / 46616
.DW SN7RATIO / 47294
.DW SN7RATIO / 47982
.DW SN7RATIO / 48680
.DW SN7RATIO / 49388
.DW SN7RATIO / 50106
.DW SN7RATIO / 50835
.DW SN7RATIO / 51575
.DW SN7RATIO / 52325
.DW SN7RATIO / 53086
.DW SN7RATIO / 53858
.DW SN7RATIO / 54642
.DW SN7RATIO / 55437
.DW SN7RATIO / 56243
.DW SN7RATIO / 57061
.DW SN7RATIO / 57891
.DW SN7RATIO / 58733
.DW SN7RATIO / 59587
.DW SN7RATIO / 60454
.DW SN7RATIO / 61333
.DW SN7RATIO / 62225
.DW SN7RATIO / 63130
.DW SN7RATIO / 64048
.DW SN7RATIO / 64980
.DW SN7RATIO / 65925
.DW SN7RATIO / 66884
.DW SN7RATIO / 67857
.DW SN7RATIO / 68844
.DW SN7RATIO / 69846
.DW SN7RATIO / 70862
.DW SN7RATIO / 71893
.DW SN7RATIO / 72938
.DW SN7RATIO / 73999
.DW SN7RATIO / 75075
.DW SN7RATIO / 76167
.DW SN7RATIO / 77275
.DW SN7RATIO / 78399
.DW SN7RATIO / 79539
.DW SN7RATIO / 80696
.DW SN7RATIO / 81870
.DW SN7RATIO / 83061
.DW SN7RATIO / 84269
.DW SN7RATIO / 85495
.DW SN7RATIO / 86738
.DW SN7RATIO / 88000
.DW SN7RATIO / 89280
.DW SN7RATIO / 90579
.DW SN7RATIO / 91896
.DW SN7RATIO / 93233
.DW SN7RATIO / 94589
.DW SN7RATIO / 95965
.DW SN7RATIO / 97361
.DW SN7RATIO / 98777
.DW SN7RATIO / 100214
.DW SN7RATIO / 101671
.DW SN7RATIO / 103150
.DW SN7RATIO / 104650
.DW SN7RATIO / 106172
.DW SN7RATIO / 107716
.DW SN7RATIO / 109283
.DW SN7RATIO / 110873
.DW SN7RATIO / 112486
.DW SN7RATIO / 114122
.DW SN7RATIO / 115782
.DW SN7RATIO / 117466
.DW SN7RATIO / 119175
.DW SN7RATIO / 120908
.DW SN7RATIO / 122667
.DW SN7RATIO / 124451
.DW SN7RATIO / 126261
.DW SN7RATIO / 128098
.DW SN7RATIO / 129961
.DW SN7RATIO / 131851
.DW SN7RATIO / 133769
.DW SN7RATIO / 135715
.DW SN7RATIO / 137689
.DW SN7RATIO / 139691
.DW SN7RATIO / 141723
.DW SN7RATIO / 143784
.DW SN7RATIO / 145876
.DW SN7RATIO / 147998
.DW SN7RATIO / 150151
.DW SN7RATIO / 152335
.DW SN7RATIO / 154550
.DW SN7RATIO / 156798
.DW SN7RATIO / 159079
.DW SN7RATIO / 161393
.DW SN7RATIO / 163740
.DW SN7RATIO / 166122
.DW SN7RATIO / 168538
.DW SN7RATIO / 170990
.DW SN7RATIO / 173477
.DW SN7RATIO / 176000
.DW SN7RATIO / 178560
.DW SN7RATIO / 181157
.DW SN7RATIO / 183792
.DW SN7RATIO / 186466
.DW SN7RATIO / 189178
.DW SN7RATIO / 191930
.DW SN7RATIO / 194722
.DW SN7RATIO / 197553
.DW SN7RATIO / 200426
.DW SN7RATIO / 203342
.DW SN7RATIO / 206299
.DW C7
SIZ_AY3NOTETBL .EQU $ - AY3NOTETBL
.ECHO "SN76489 approx "
.ECHO SIZ_AY3NOTETBL / 2 / 4 /12
.ECHO " Octaves. Last note index supported: "
.ECHO SIZ_AY3NOTETBL / 2
.ECHO "\n"