Files
RomWBW/Source/HBIOS/spk.asm
2020-05-09 22:27:59 +08:00

381 lines
9.6 KiB
NASM
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
;======================================================================
;
; BIT MODE SOUND DRIVER FOR SBC V2 USING BIT 0 OF RTC DRIVER
;
;======================================================================
;
; DRIVER FUNCTION TABLE AND INSTANCE DATA
;
SP_FNTBL:
.DW SP_RESET
.DW SP_VOLUME
.DW SP_PERIOD
.DW SP_NOTE
.DW SP_PLAY
.DW SP_QUERY
;
#IF (($ - SP_FNTBL) != (SND_FNCNT * 2))
.ECHO "*** INVALID SND FUNCTION TABLE ***\n"
!!!!!
#ENDIF
;
SP_IDAT .EQU 0 ; NO INSTANCE DATA ASSOCIATED WITH THIS DEVICE
;
SP_TONECNT .EQU 1 ; COUNT NUMBER OF TONE CHANNELS
SP_NOISECNT .EQU 0 ; COUNT NUMBER OF NOISE CHANNELS
;
SP_PENDING_PERIOD .DW SP_NOTE_C8 ; PENDING PERIOD (16 BITS)
SP_PENDING_VOLUME .DB $FF ; PENDING VOL (8 BITS)
;
;======================================================================
; DRIVER INITIALIZATION
;======================================================================
;
SP_INIT:
LD IY, SP_IDAT ; SETUP FUNCTION TABLE
LD BC, SP_FNTBL ; POINTER TO INSTANCE DATA
LD DE, SP_IDAT ; BC := FUNCTION TABLE ADDRESS
CALL SND_ADDENT ; DE := INSTANCE DATA PTR
;
CALL NEWLINE ; ANNOUNCE DEVICE
PRTS("SPK: IO=0x$")
LD A,RTCIO
CALL PRTHEXBYTE
CALL SP_SETTBL ; SETUP TONE TABLE
CALL SP_PLAY ; PLAY DEFAULT NOTE
XOR A
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - RESET
;======================================================================
;
SP_RESET:
; XOR A ; SUCCESSFULL RESET
; RET
;
;======================================================================
; SOUND DRIVER FUNCTION - VOLUME
;======================================================================
;
SP_VOLUME:
XOR A ; SIGNAL SUCCESS
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - PERIOD
;======================================================================
;
SP_PERIOD:
LD (SP_PENDING_PERIOD), HL ; SAVE AND RETURN SUCCESSFUL
XOR A
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - NOTE
;======================================================================
;
SP_NOTE:
PUSH HL
PUSH DE ; ON ENTRY L IS A NOTE INDEX
LD H,0 ; CONVERT THIS NOTE INDEX
ADD HL,HL ; TO THE ASSOCIATED ENTRY
ADD HL,HL ; IN THE TUNE ABLE.
LD DE,SP_TUNTBL ; SAVE THIS ADDRESS AS
ADD HL,DE ; THE PERIOD
LD (SP_PENDING_PERIOD),HL
POP DE
POP HL
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - QUERY AND SUBFUNCTIONS
;======================================================================
;
SP_QUERY:
LD A, E
CP BF_SNDQ_CHCNT ; SUB FUNCTION 01
JR Z, SP_QUERY_CHCNT
;
CP BF_SNDQ_VOLUME ; SUB FUNCTION 02
JR Z, SP_QUERY_VOLUME
;
CP BF_SNDQ_PERIOD ; SUB FUNCTION 03
JR Z, SP_QUERY_PERIOD
;
CP BF_SNDQ_DEV ; SUB FUNCTION 04
JR Z, SP_QUERY_DEV
;
OR $FF ; SIGNAL FAILURE
RET
;
SP_QUERY_CHCNT:
LD BC,(SP_TONECNT*256)+SP_NOISECNT ; RETURN NUMBER OF
XOR A ; TONE AND NOISE
RET ; CHANNELS IN BC
;
SP_QUERY_PERIOD:
LD HL, (SP_PENDING_PERIOD) ; RETURN 16-BIT PERIOD
XOR A ; IN HL REGISTER
RET
;
SP_QUERY_VOLUME:
LD L, 255 ; RETURN 8-BIT VOLUME
XOR A ; IN L REGISTER
RET
;
SP_QUERY_DEV:
LD B, BF_SND_BITMODE ; RETURN DEVICE IDENTIFIER
LD DE, 0 ; AND ADDRESS AND DATA PORT
XOR A
RET
;
;======================================================================
; INITIALIZE THE TONE TABLE
;======================================================================
;
SP_SETTBL:
LD A,(CB_CPUMHZ) ; GET CPU SPEED.
LD C,A
LD B,SP_NOTCNT ; SET NUMBER OF NOTES TO
LD HL,SP_TUNTBL+2 ; ADJUST AND START POINT
;
SP_SETTBL2:
PUSH HL
LD E,(HL) ; READ IN
INC HL ; THE 1MHZ
LD D,(HL) ; NOTE
;
PUSH BC
LD B,C
LD HL,0 ; MULTIPLY
SP_SETTBL1: ; 1MHZ NOTE
ADD HL,DE ; VALUE BY
DJNZ SP_SETTBL1 ; SYSTEM MHZ
POP BC
;
LD DE,30 ; ADD OVERHEAD
ADD HL,DE ; COMPENSATION
;
POP DE ; RECALL NOTE
EX DE,HL ; ADDRESS
;
LD (HL),E ; SAVE
INC HL ; THE
LD (HL),D ; NEW
INC HL ; NOTE
INC HL ; AND MOVE
INC HL ; TO NEXT
;
DJNZ SP_SETTBL2 ; NEXT NOTE
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - PLAY
;======================================================================
;
SP_PLAY:
LD HL,(SP_PENDING_PERIOD) ; SELECT NOTE
;
LD E,(HL) ; LOAD 1ST ARG
INC HL ; IN DE
LD D,(HL)
INC HL
LD C,(HL) ; LOAD 2ND ARG
INC HL ; IN BC
LD B,(HL)
INC HL
;
PUSH BC ; SETUP ARG IN HL
POP HL
;
CALL SP_BEEPER ; PLAY
;
RET
;
; The following SP_BEEPER routine is a modification of code from
; "The Complete SPECTRUM ROM DISSASSEMBLY" by Dr Ian Logan & Dr Frank OHara
;
; https://www.esocop.org/docs/CompleteSpectrumROMDisassemblyThe.pdf
;
; DE Number of passes to make through the sound generation loop
; HL Loop delay parameter
;
SP_BEEPER:
PUSH IX
DI ; Disable the interrupt for the duration of a 'beep'.
LD A,L ; Save L temporarily.
SRL L ; Each '1' in the L register is to count 4 T states, but take INT (L/4) and count 16 T states instead.
SRL L
CPL ; Go back to the original value in L and find how many were lost by taking 3-(A mod 4).
AND $03
LD C,A
LD B,$00
LD IX,SPK_DLYADJ ; The base address of the timing loop.
ADD IX,BC ; Alter the length of the timing loop. Use an earlier starting point for each '1' lost by taking INT (L/4).
LD A,(RTCVAL) ; Fetch the present border colour from BORDCR and move it to bits 2, 1 and 0 of the A register.
;
; The HL register holds the 'length of the timing loop' with 16 T states being used for each '1' in the L register and 1024 T states for each '1' in the H register.
;
SPK_DLYADJ:
NOP ; Add 4 T states for each earlier entry point that is used.
NOP
NOP
INC B ; The values in the B and C registers will come from the H and L registers - see below.
INC C
BE_H_L_LP:
DEC C ; The 'timing loop', i.e. BC*4 T states. (But note that at the half-cycle point, C will be equal to L+1.)
JR NZ,BE_H_L_LP
LD C,$3F
DEC B
JP NZ,BE_H_L_LP
;
; The loudspeaker is now alternately activated and deactivated.
;
XOR %00000100 ; Flip bit 2.
OUT (RTCIO),A ; Perform the 'OUT' operation, leaving other bits unchanged.
LD B,H ; Reset the B register.
LD C,A ; Save the A register.
BIT 4,A ; Jump if at the half-cycle point.
JR NZ,BE_AGAIN
;
; After a full cycle the DE register pair is tested.
;
LD A,D ; Jump forward if the last complete pass has been made already.
OR E
JR Z,BE_END
LD A,C ; Fetch the saved value.
LD C,L ; Reset the C register.
DEC DE ; Decrease the pass counter.
JP (IX) ; Jump back to the required starting location of the loop.
;
; The parameters for the second half-cycle are set up.
;
BE_AGAIN:
LD C,L ; Reset the C register.
INC C ; Add 16 T states as this path is shorter.
JP (IX) ; Jump back.
BE_END:
EI
POP IX
RET
;
; STANDARD ONE SECOND TONE TABLES AT 1MHZ (UNCOMPENSATED). FOR SP_BEEPER, FIRST WORD LOADED INTO DE, SECOND INTO HL
;
; EXCEL SPREADSHEET FOR CALCULATION CAN BE FOUND HERE:
;
; https://www.retrobrewcomputers.org/lib/exe/fetch.php?media=boards:sbc:sbc_v2:sbc_v2-004:spk_beep_tuntbl.xlsx
;
SP_TUNTBL:
.DW $13, $191A ; D
.DW $14, $17B3 ; E0
.DW $15, $165E ; F0
.DW $17, $151E ; F
.DW $18, $13EE ; G0
.DW $19, $12CF ; G
.DW $1B, $11C1 ; A0
.DW $1D, $10C1 ; A
.DW $1E, $FD1 ; B0
.DW $20, $EEE ; C1
.DW $22, $E17 ; C
.DW $24, $D4D ; D1
.DW $26, $C8E ; D
.DW $29, $BD9 ; E1
.DW $2B, $B2F ; F1
.DW $2E, $A8E ; F
.DW $31, $9F7 ; G1
.DW $33, $968 ; G
.DW $37, $8E0 ; A1
.DW $3A, $861 ; A
.DW $3D, $7E8 ; B1
.DW $41, $777 ; C2
.DW $45, $70B ; C
.DW $49, $6A6 ; D2
.DW $4D, $647 ; D
.DW $52, $5EC ; E2
.DW $57, $597 ; F2
.DW $5C, $547 ; F
.DW $62, $4FB ; G2
.DW $67, $4B3 ; G
.DW $6E, $470 ; A2
.DW $74, $430 ; A
.DW $7B, $3F4 ; B2
.DW $82, $3BB ; C3
.DW $8A, $385 ; C
.DW $92, $353 ; D3
.DW $9B, $323 ; D
.DW $A4, $2F6 ; E3
.DW $AE, $2CB ; F3
.DW $B9, $2A3 ; F
.DW $C4, $27D ; G3
.DW $CF, $259 ; G
.DW $DC, $238 ; A3
.DW $E9, $218 ; A
.DW $F6, $1FA ; B3
.DW $105, $1DD ; C4
.DW $115, $1C2 ; C
.DW $125, $1A9 ; D4
.DW $137, $191 ; D
.DW $149, $17B ; E4
.DW $15D, $165 ; F4
.DW $171, $151 ; F
.DW $188, $13E ; G4
.DW $19F, $12C ; G
.DW $1B8, $11C ; A4
.DW $1D2, $10C ; A
.DW $1ED, $FD ; B4
.DW $20B, $EE ; C5
.DW $22A, $E1 ; C
.DW $24B, $D4 ; D5
.DW $26E, $C8 ; D
.DW $293, $BD ; E5
.DW $2BA, $B2 ; F5
.DW $2E3, $A8 ; F
.DW $30F, $9F ; G5
.DW $33E, $96 ; G
.DW $370, $8E ; A5
.DW $3A4, $86 ; A
.DW $3DB, $7E ; B5
.DW $416, $77 ; C6
.DW $454, $70 ; C
.DW $496, $6A ; D6
.DW $4DC, $64 ; D
.DW $526, $5E ; E6
.DW $574, $59 ; F6
.DW $5C7, $54 ; F
.DW $61F, $4F ; G6
.DW $67D, $4B ; G
.DW $6E0, $47 ; A6
.DW $748, $43 ; A
.DW $7B7, $3F ; B6
.DW $82D, $3B ; C7
.DW $8A9, $38 ; C
.DW $92D, $35 ; D7
.DW $9B9, $32 ; D
.DW $A4D, $2F ; E7
.DW $AE9, $2C ; F7
.DW $B8F, $2A ; F
.DW $C3F, $27 ; G7
.DW $CFA, $25 ; G
.DW $DC0, $23 ; A7
.DW $E91, $21 ; A
.DW $F6F, $1F ; B7
SP_NOTE_C8:
.DW $105A, $1D ; C8
.DW $1152, $1C ; C
.DW $125A, $1A ; D8
.DW $1372, $19 ; D
.DW $149A, $17 ; E8
.DW $15D3, $16 ; F8
.DW $171F, $15 ; F
.DW $187F, $13 ; G8
.DW $19F4, $12 ; G
.DW $1B80, $11 ; A8
.DW $1D22, $10 ; A
.DW $1EDE, $F ; B8
;
SP_NOTCNT .EQU ($-SP_TUNTBL-1) / 4
;