Browse Source

Merge pull request #134 from b1ackmai1er/dev

audio update
pull/138/head
Wayne Warthen 6 years ago
committed by GitHub
parent
commit
15563adbb2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 64
      Source/Doc/Architecture.md
  2. 123
      Source/HBIOS/ay38910.asm
  3. 89
      Source/HBIOS/hbios.asm
  4. 1
      Source/HBIOS/hbios.inc
  5. 11
      Source/HBIOS/sn76489.asm
  6. 340
      Source/HBIOS/spk.asm
  7. 2
      Source/HBIOS/time.asm
  8. 8
      Source/HBIOS/util.asm

64
Source/Doc/Architecture.md

@ -1429,25 +1429,34 @@ Increase by steps of 48 to select the same note in next octave.
If the driver is able to generate the requested note, a success (0) is
returned, otherwise a non-zero error state will be returned.
The sound chip resolution and its oscillator limit the range and
accuracy of the notes played. The typically range of the AY-3-8910
is six octaves, Bb2/A#2-A7, where each value is a unique tone. Values
above and below can still be played but each quarter tone step may not
result in a note change.
The following table shows the mapping of the input value in HL
to the corresponding octave and note.
| Note | Octave 0 | Octave 1 | Octave 2 | Octave 3 | Octave 4 | Octave 5 | Octave 6 |
|-------|----------|----------|----------|----------|----------|----------|----------|
| Bb/A# | 0 | 48 | 96 | 144 | 192 | 240 | 288 |
| B | 4 | 52 | 100 | 148 | 196 | 244 | 292 |
| C | 8 | 56 | 104 | 152 | 200 | 248 | 296 |
| C#/Db | 12 | 60 | 108 | 156 | 204 | 252 | 300 |
| D | 16 | 64 | 112 | 160 | 208 | 256 | 304 |
| Eb/D# | 20 | 68 | 116 | 164 | 212 | 260 | 308 |
| E | 24 | 72 | 120 | 168 | 216 | 264 | 312 |
| F | 28 | 76 | 124 | 172 | 220 | 268 | 316 |
| F#/Gb | 32 | 80 | 128 | 176 | 224 | 272 | 320 |
| G | 36 | 84 | 132 | 180 | 228 | 276 | 324 |
| Ab/G# | 40 | 88 | 136 | 184 | 232 | 280 | 328 |
| A | 44 | 92 | 140 | 188 | 236 | 284 | 332 |
### Function 0x54 -- Sound Play (SNDPLAY)
+-------+---------------------------------------------------------------+
| | OCTAVE |
| Note +---------------------------------------------------------------+
| | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|-------+-------|-------|-------|-------|-------|-------|-------|-------+
| Bb/A# | 0 | 48 | 96 | 144 | 192 | 240 | 288 | 336 |
| B | 4 | 52 | 100 | 148 | 196 | 244 | 292 | 340 |
| C | 8 | 56 | 104 | 152 | 200 | 248 | 296 | 344 |
| C#/Db | 12 | 60 | 108 | 156 | 204 | 252 | 300 | 348 |
| D | 16 | 64 | 112 | 160 | 208 | 256 | 304 | 352 |
| Eb/D# | 20 | 68 | 116 | 164 | 212 | 260 | 308 | 356 |
| E | 24 | 72 | 120 | 168 | 216 | 264 | 312 | 360 |
| F | 28 | 76 | 124 | 172 | 220 | 268 | 316 | 364 |
| F#/Gb | 32 | 80 | 128 | 176 | 224 | 272 | 320 | 368 |
| G | 36 | 84 | 132 | 180 | 228 | 276 | 324 | 372 |
| Ab/G# | 40 | 88 | 136 | 184 | 232 | 280 | 328 | 376 |
| A | 44 | 92 | 140 | 188 | 236 | 284 | 332 | 380 |
### Function 0x54 -- Sound Play SNDPLAY)
| _Entry Parameters_
| B: 0x54
@ -1529,9 +1538,6 @@ key aspects of the specific Audio Device.
Reports information about the audio device unit specified.
At this stage, only one driver type is supported (SN76489), but is
envisaged that more will be added in the future.
Register B reports the audio device type (see below).
Registers HL and DE contain relevant port addresses for the hardware
@ -1543,7 +1549,27 @@ AUDIO ID | Value | Device | Returned registers
-------------- | ----- | ---------- | --------------------------------------------
SND_SN76489 | 0x01 | SN76489 | E: Left channel port, L: Right channel port
SND_AY38910 | 0x02 | AY-3-8910 | D: Address port, E: Data port
SND_BITMODE | 0x03 | I/O PORT | D: Address port, E: Bit mask
### Function 0x56 -- Sound Duration (SNDDUR)
| _Entry Parameters_
| B: 0x56
| C: Audio Device Unit ID
| HL: Duration
| _Returned Values_
| A: Status (0=OK, else error)
This function sets the duration of the note to be played in milliseconds.
If the duration is set to zero, then the play function will operate in a non-blocking
mode. i.e. a tone will start playing and the play function will return. The tone will
continue to play until the next tone is played. I/O PORT are not compatible and will
not play a note if the duration is zero.
For other values, when a tone is played, it will play for the duration defined in HL
and then return.
`\clearpage`{=latex}

123
Source/HBIOS/ay38910.asm

@ -4,10 +4,9 @@
;
;======================================================================
;
;#include "cfg_state.inc"
; @3.579545 OCTAVE RANGE IS 2 - 7 (Bb2/A#2 .. A7)
; @4.000000 OCTAVE RANGE IS 2 - 7 (B2 .. A7)
;
AY_RCSND .EQU 0 ; 0 = EB MODULE, 1=MF MODULE
;
#IF (AYMODE == AYMODE_SCG)
@ -15,6 +14,7 @@ AY_RSEL .EQU $9A
AY_RDAT .EQU $9B
AY_RIN .EQU AY_RSEL
AY_ACR .EQU $9C
AY_CLK .SET 3579545 ; MSX NTSC COLOUR BURST FREQ = 315/88
#ENDIF
;
#IF (AYMODE == AYMODE_N8)
@ -56,7 +56,8 @@ AY_FNTBL:
.DW AY_NOTE
.DW AY_PLAY
.DW AY_QUERY
.DW AY_DURATION
;
#IF (($ - AY_FNTBL) != (SND_FNCNT * 2))
.ECHO "*** INVALID SND FUNCTION TABLE ***\n"
!!!!!
@ -68,15 +69,16 @@ AY_IDAT .EQU 0 ; NO INSTANCE DATA ASSOCIATED WITH THIS DEVICE
;
; DEVICE CAPABILITIES AND CONFIGURATION
;
SBCV2004 .EQU 0 ; USE SBC-V2-004 HALF CLOCK DIVIDER
;
AY_TONECNT .EQU 3 ; COUNT NUMBER OF TONE CHANNELS
AY_NOISECNT .EQU 1 ; COUNT NUMBER OF NOISE CHANNELS
;
AY_PHICLK .EQU 3579545 ; MSX NTSC COLOUR BURST FREQ = 315/88
;AY_PHICLK .EQU 3500000 ; ZX SPECTRUM 3.5MHZ
;AY_PHICLK .EQU 4000000 ; RETROBREW SCB-SCG
AY_RATIO .EQU AY_CLK * 100 / 16
#IF (AY_CLK > 3579545) ; DEPENDING ON THE
AY_SCALE .EQU 2 ; INPUT CLOCK FREQUENCY
#ELSE ; PRESCALE THE TONE PERIOD
AY_SCALE .EQU 3 ; DATA TO MAINTAIN MAXIMUM
#ENDIF ; RANGE AND ACCURACY
;
AY_RATIO .EQU (AY_CLK * 100) / (16 >> AY_SCALE)
;
#INCLUDE "audio.inc"
;
@ -96,7 +98,7 @@ AY38910_INIT:
CALL PRTHEXBYTE
;
#IF ((AYMODE == AYMODE_SCG) | (AYMODE == AYMODE_N8))
LD A,$FF ; ACTIVATE DEVICEBIT 4 IS AY RESET CONTROL, BIT 3 IS ACTIVE LED
LD A,$FF ; ACTIVATE DEVICE BIT 4 IS AY RESET CONTROL, BIT 3 IS ACTIVE LED
OUT (AY_ACR),A ; SET INIT AUX CONTROL REG
#ENDIF
;
@ -127,55 +129,50 @@ AY_FND: LD IY, AY_IDAT ; SETUP FUNCTION TABLE
LD DE,(AY_R3CHBP*256)+$00
CALL AY_WRTPSG ; R03 = $00 = XXXX0000
;
#IF (SYSTIM != TM_NONE)
LD A, TICKFREQ / 3 ; SCHEDULE IN 1/3 SECOND TO TURN OFF SOUND
LD (AY_TIMTIK), A
;
LD HL, (VEC_TICK + 1) ; GET CUR TICKS VECTOR
LD (AY_TIMHOOK), HL ; SAVE IT INTERNALLY
LD HL, AY_TIMER ; INSTALL TIMER HOOK HANDLER
LD (VEC_TICK + 1), HL
;
LD A, $02 ; NOT READY & IN INTERUPT HANDLER
LD (AY_READY), A
#ELSE
CALL LDELAY ; HALF SECOND DELAY
LD E,$00 ; SET VOLUME OFF
CALL AY_SETV ; ON ALL CHANNELS
LD A, $01 ; READY & NOT IN INTERUPT HANDLER
LD (AY_READY), A
#ENDIF
;
XOR A ; SUCCESSFULL INIT
RET
;
#IF (SYSTIM != TM_NONE)
AY_TIMER:
LD A, (AY_TIMTIK)
DEC A
LD (AY_TIMTIK), A
JR NZ, AY_TIMER1
;
LD E,$00 ; SET VOLUME OFF
CALL AY_SETV ; ON ALL CHANNELS
LD A, $01 ; READY & NOT IN INTERUPT HANDLER
LD (AY_READY), A
;
LD DE, AY_TIMER ; MAKE AY_TIMER A NO_OP HANDLER
LD HL, AY_TIMER1
LD BC, 3
LDIR
;
AY_TIMER1:
JP 0 ; OVERWRITTEN WITH NEXT HANDLER
AY_TIMHOOK: .EQU $ - 2
AY_TIMTIK .DB 0 ; COUNT DOWN TO FINISH BOOT BEEP
#ENDIF
;
;======================================================================
@ -185,7 +182,7 @@ AY_TIMTIK .DB 0 ; COUNT DOWN TO FINISH BOOT BEEP
AY_INIT:
LD DE,(AY_R7ENAB*256)+$F8 ; SET MIXER CONTROL / IO ENABLE. $F8 - 11 111 000
JP AY_WRTPSG ; I/O PORTS = OUTPUT, NOISE CHANNEL C, B, A DISABLE, TONE CHANNEL C, B, A ENABLE
;
AY_CHKREDY:
LD A, (AY_READY)
BIT 0, A
@ -219,7 +216,7 @@ AY_SV: CALL AY_WRTPSG ; CYCLING THROUGH ALL CHANNELS
AY_RESET:
AUDTRACE(AYT_INIT)
CALL AY_CHKREDY ; RETURNS TO OUR CALLER IF NOT READY
;
PUSH DE
PUSH HL
CALL AY_INIT ; SET DEFAULT CHIP CONFIGURATION
@ -261,10 +258,34 @@ AY_NOTE:
AUDTRACE(AYT_NOTE)
AUDTRACE_HL
AUDTRACE_CR
LD DE, AY3NOTETBL
CALL AUD_NOTE ; RETURNS PERIOD IN HL, FALL THRU
; TO SET THIS PERIOD
;
; CALL PRTHEXWORDHL
; CALL PC_COLON
;
LD DE, AY3NOTETBL ; ON ENTRY HL IS THE NOTE TO PLAY
PUSH DE ; AND DE IS THE START OF NOTE TABLE
LD DE, 48 ; LOAD DE WITH NOTE TABLE SIZE
CALL DIV16 ; AND CALCULATE OCTAVE COUNT IN BC
;
ADD HL, HL ; HL IS THE REMAINDER FROM ABOVE DIVISION (0-47) AND THE NOTE
POP DE ; TO PLAY IN THE OCTAVE. ADD IT TO THE START OF THE NOTE TABLE
ADD HL, DE ; TO POINT TO THE PERIOD FOR THE NOTE WE WANT TO PLAY.
;
LD A, (HL) ; HL POINT TO CURRENT PERIOD COUNT WE WANT TO PLAY
INC HL ; SO LOAD PERIOD COUNT FROM NOTE TABLE INTO HL
LD H, (HL) ; SO WE CAN UPDATE IT FOR THE REQUIRED OCTAVE
LD L, A
;
LD A,AY_SCALE-1 ; THE NOTE TABLE PERIOD DATA HAS BEEN
ADD A,C ; PRESCALED TO MAINTAIN RANGE SO ALLOW
LD B,A ; FOR THIS WHEN CHANGING OCTAVE
AY_NOTE1:
SRL H ; ADJUST THE PERIOD DATA
RR L ; FOR THE DESIRED OCTAVE
DJNZ AY_NOTE1 ; FALL THROUGH TO SET PERIOD AND RANGE CHECK
;
; CALL PRTHEXWORDHL
; CALL NEWLINE
;
;======================================================================
; SOUND DRIVER FUNCTION - PERIOD
@ -278,7 +299,7 @@ AY_PERIOD:
LD A, H ; IF ZERO - ERROR
OR L
JR Z, AY_PERIOD1
;
LD A, H ; MAXIMUM TONE PERIOD IS 12-BITS
AND 11110000B ; ALLOWED RANGE IS 0001-0FFF (4095)
JR NZ, AY_PERIOD1 ; RETURN NZ IF NUMBER TOO LARGE
@ -304,7 +325,6 @@ AY_PLAY:
AUDTRACE_D
AUDTRACE_CR
CALL AY_CHKREDY ; RETURNS TO OUR CALLER IF NOT READY
;
LD A, (AY_PENDING_PERIOD + 1) ; CHECK THE HIGH BYTE OF THE PERIOD
INC A
@ -412,21 +432,33 @@ AY_QUERY_DEV:
LD DE, (AY_RSEL*256)+AY_RDAT ; AND ADDRESS AND DATA PORT
XOR A
RET
;
;======================================================================
; SOUND DRIVER FUNCTION - DURATION
;======================================================================
;
AY_DURATION:
LD (AY_PENDING_DURATION),HL ; SET TONE DURATION
XOR A
RET
;
;======================================================================
; NON-BLOCKING INTERRUPT CODE
;======================================================================
;
AY_DI:
LD A, (AY_READY)
BIT 1, A
RET NZ
HB_DI
RET
;
AY_EI:
LD A, (AY_READY)
BIT 1, A
RET NZ
HB_EI
RET
;
;======================================================================
;
@ -437,9 +469,9 @@ AY_EI:
;
AY_WRTPSG:
CALL AY_DI
#IF (SBCV2004)
#IFDEF SBCV2004
LD A,8 ; SBC-V2-004 CHANGE
OUT (112),A ; TO HALF CLOCK SPEED
OUT (RTCIO),A ; TO HALF CLOCK SPEED
#ENDIF
#IF (CPUFAM == CPU_Z180)
IN0 A,(Z180_DCNTL) ; GET WAIT STATES
@ -455,12 +487,11 @@ AY_WRTPSG:
POP AF ; GET SAVED DCNTL VALUE
OUT0 (Z180_DCNTL),A ; AND RESTORE IT
#ENDIF
#IF (SBCV2004)
#IFDEF SBCV2004
LD A,0 ; SBC-V2-004 CHANGE TO
OUT (112),A ; NORMAL CLOCK SPEED
OUT (RTCIO),A ; NORMAL CLOCK SPEED
#ENDIF
JP AY_EI
;
;======================================================================
;
@ -468,9 +499,9 @@ AY_WRTPSG:
;
AY_RDPSG:
CALL AY_DI
#IF (SBCV2004)
#IFDEF SBCV2004
LD A,8 ; SBC-V2-004 CHANGE
OUT (112),A ; TO HALF CLOCK SPEED
OUT (RTCIO),A ; TO HALF CLOCK SPEED
#ENDIF
#IF (CPUFAM == CPU_Z180)
IN0 A,(Z180_DCNTL) ; GET WAIT STATES
@ -486,9 +517,9 @@ AY_RDPSG:
POP AF ; GET SAVED DCNTL VALUE
OUT0 (Z180_DCNTL),A ; AND RESTORE IT
#ENDIF
#IF (SBCV2004)
#IFDEF SBCV2004
LD A,0 ; SBC-V2-004 CHANGE TO
OUT (112),A ; NORMAL CLOCK SPEED
OUT (RTCIO),A ; NORMAL CLOCK SPEED
#ENDIF
JP AY_EI
;
@ -496,6 +527,7 @@ AY_RDPSG:
;
AY_PENDING_PERIOD .DW 0 ; PENDING PERIOD (12 BITS) ; ORDER
AY_PENDING_VOLUME .DB 0 ; PENDING VOL (8 BITS) ; SIGNIFICANT
AY_PENDING_DURATION .DW 0 ; PENDING DURATION (16 BITS)
AY_READY .DB 0 ; BIT 0 -> NZ DRIVER IS READY TO RECEIVE PLAY COMMAND
; BIT 1 -> NZ EXECUTING WITHIN TIMER HANDLER = DO NOT DIS/ENABLE INT
;
@ -510,13 +542,14 @@ AYT_REGWR .DB "\r\nOUT AY-3-8910 $"
#ENDIF
;
;======================================================================
; BBC MICRO QUARTER TONE FREQUENCY TABLE
; QUARTER TONE FREQUENCY TABLE
;======================================================================
;
; THE FREQUENCY BY QUARTER TONE STARTING AT A0# OCATVE 0
; THE FREQUENCY BY QUARTER TONE STARTING AT A0# OCTAVE 0
; USED TO MAP EACH OCTAVE (DIV BY 2 TO JUMP AN OCTAVE UP)
; FIRST PLAYABLE NOTE WILL BE 0
; ASSUMING A CLOCK OF 1843200 THIS MAPS TO A0#
;
AY3NOTETBL:
.DW AY_RATIO / 2913
.DW AY_RATIO / 2956

89
Source/HBIOS/hbios.asm

@ -1628,6 +1628,7 @@ HB_INIT_REC:
#IF (PLATFORM == PLT_SBC)
.DW UART_INIT
.DW MD_INIT
.DW PPIDE_INIT
#ENDIF
HB_INITRLEN .EQU (($ - HB_INIT_REC) / 2)
;
@ -1673,14 +1674,14 @@ HB_INITTBL:
#IF (CTCENABLE)
.DW CTC_INIT
#ENDIF
#IF (SPKENABLE)
.DW SP_INIT ; AUDIBLE INDICATOR OF BOOT START
#IF (AY38910ENABLE)
.DW AY38910_INIT ; AUDIBLE INDICATOR OF BOOT START
#ENDIF
#IF (SN76489ENABLE)
.DW SN76489_INIT
#ENDIF
#IF (AY38910ENABLE)
.DW AY38910_INIT ; AUDIBLE INDICATOR OF BOOT START
#IF (SPKENABLE)
.DW SP_INIT ; AUDIBLE INDICATOR OF BOOT START
#ENDIF
#IF (ASCIENABLE)
.DW ASCI_INIT
@ -2295,7 +2296,7 @@ SND_ADDENT:
; WORD DRIVER FUNCTION TABLE ADDRESS
; WORD UNIT SPECIFIC DATA (TYPICALLY A DEVICE INSTANCE DATA ADDRESS)
;
SND_FNCNT .EQU 6 ; NUMBER OF SND FUNCS (FOR RANGE CHECK)
SND_FNCNT .EQU 7 ; NUMBER OF SND FUNCS (FOR RANGE CHECK)
SND_MAX .EQU 3 ; UP TO 2 UNITS
SND_SIZ .EQU SND_MAX * 4 ; EACH ENTRY IS 4 BYTES
;
@ -3680,10 +3681,14 @@ PRTSUM:
LD C,BF_SYSGET_DIOCNT ; DISK DRIVES
LD HL,PS_DISK
CALL PRT_ALLD
;
LD C,BF_SYSGET_VDACNT ; VIDEO DEVICES
LD HL,PS_VIDEO
CALL PRT_ALLD
;
LD C,BF_SYSGET_SNDCNT ; SOUND DEVICES
LD HL,PS_SOUND
CALL PRT_ALLD
RET
;
PRT_ALLD:
@ -4026,6 +4031,68 @@ PS_PRTVC:
CALL PRTDECB
RET
;
; PRINT SOUND CONFIG
;
PS_SOUND:
PUSH BC
; UNIT COLUMN
PRTS("Sound $")
LD A,C ; MOVE UNIT NUM TO A
CALL PRTDECB ; PRINT IT
CP 10 ; CHECK FOR MULTIPLE DIGITS
CALL C,PC_SPACE ; EXTRA SPACE IF NEEDED
PRTS(" $") ; PAD TO NEXT COLUMN
; DEVICE COLUMN
PUSH BC ;
LD E,C
XOR A
LD DE,PS_SDSND ; POINT TO DEVICE TYPE NAME TABLE
CALL PRTIDXDEA ; PRINT DEVICE NMEMONIC PADDED TO FIELD WIDTH
LD A,C ; MOVE UNIT NUM TO A
CALL PRTDECB ; PRINT IT
CALL PC_COLON
CP 10 ; CHECK FOR MULTIPLE DIGITS
CALL C,PC_SPACE ; EXTRA SPACE IF NEEDED
LD A,(PRTIDXCNT)
SUB 9+1
CPL
CALL PS_PAD
POP BC
; DEVICE TYPE
;
LD B,BF_SNDQUERY ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C
LD E,BF_SNDQ_DEV
RST 08
LD A,B
DEC A
LD DE,PS_SDSN76489
CALL PRTIDXDEA
LD A,(PRTIDXCNT)
SUB 18+1
CPL
CALL PS_PAD ; PAD N SPACES (SPECIFIED IN A)
; DEVICE CHARACTERISTICS
;
LD B,BF_SNDQUERY ; FUNC=GET DEVICE INFO, UNIT NUM STILL IN C
LD E,BF_SNDQ_CHCNT
RST 08
LD A,B
CALL PRTDECB
LD A,'+'
CALL COUT
LD A,C
CALL PRTDECB
PRTS(" CHANNELS$")
CALL NEWLINE
;
POP BC
RET
;
; PRINT DEVICE NMEMONIC, DEVTYP/NUM SPECIFIED IN DE
;
PS_PRTDEV:
@ -4182,6 +4249,16 @@ PS_VDVGA .TEXT "VGA$"
;
PS_VTCRT .TEXT "CRT$"
;
; SOUND DEVICE STRINGS
;
PS_SDSND .TEXT "SND$"
;
; SOUND TYPE STRINGS
;
PS_SDSN76489 .TEXT "SN76489$"
PS_SDAY38910 .TEXT "AY-3-8910$"
PS_SDBITMODE .TEXT "I/O PORT$"
;
; 0 1 2 3 4 5 6 7
; 01234567890123456789012345678901234567890123456789012345678901234567890123456789
PS_STRHDR .TEXT "Unit Device Type Capacity/Mode\r\n"

1
Source/HBIOS/hbios.inc

@ -62,6 +62,7 @@ BF_SNDPRD .EQU BF_SND + 2 ; REQUEST SOUND PERIOD - HL CONTAINS DRIVER SPECIFIC V
BF_SNDNOTE .EQU BF_SND + 3 ; REQUEST NOTE - L CONTAINS NOTE - EACH VALUE IS QUARTER NOTE
BF_SNDPLAY .EQU BF_SND + 4 ; INITIATE THE REQUESTED SOUND COMMAND
BF_SNDQUERY .EQU BF_SND + 5 ; E IS SUBFUNCTION
BF_SNDDURATION .EQU BF_SND + 6 ; REQUEST DURATION HL MILLISECONDS
;
; BF_SNDQUERY SUBCOMMANDS
BF_SNDQ_STATUS .EQU 0

11
Source/HBIOS/sn76489.asm

@ -262,7 +262,7 @@ SN7_APPLY_PRD:
LD A, L ; GET LOWER 4 BITS FOR COMMAND 1
AND $F
OR B ; A NOW CONATINS FIRST PERIOD COMMAND
OR B ; A NOW CONTAINS FIRST PERIOD COMMAND
AUDTRACE(SNT_REGWR)
AUDTRACE_A
@ -299,6 +299,10 @@ SN7_APPLY_PRD:
POP DE
RET
SN7_DURATION:
LD (SN7_PENDING_DURATION),HL ; SET TONE DURATION
XOR A
RET
SN7_FNTBL:
.DW SN7_RESET
@ -307,7 +311,8 @@ SN7_FNTBL:
.DW SN7_NOTE
.DW SN7_PLAY
.DW SN7_QUERY
.DW SN7_DURATION
;
#IF (($ - SN7_FNTBL) != (SND_FNCNT * 2))
.ECHO "*** INVALID SND FUNCTION TABLE ***\n"
!!!!!
@ -317,6 +322,8 @@ SN7_PENDING_PERIOD
.DW 0 ; PENDING PERIOD (10 BITS)
SN7_PENDING_VOLUME
.DB 0 ; PENDING VOL (8 BITS -> DOWNCONVERTED TO 4 BITS AND INVERTED)
SN7_PENDING_DURATION
.DW 0 ; PENDING DURATION (16 BITS)
STR_MESSAGELT .DB "\r\nSN76489: LEFT IO=0x$"
STR_MESSAGERT .DB ", RIGHT IO=0x$"

340
Source/HBIOS/spk.asm

@ -4,15 +4,22 @@
;
;======================================================================
;
; LIMITATIONS - CPU FREQUENCY ADJUSTMENT LIMITED TO 1MHZ RESOLUTION
; QUARTER TONES NOT SUPPORTED
; DURATION FIXED TO 1 SECOND.
; NO VOLUME ADJUSTMENT DUE TO HARDWARE LIMITATION
;======================================================================
;
; DRIVER FUNCTION TABLE AND INSTANCE DATA
;
SP_FNTBL:
.DW SP_RESET
.DW SP_VOLUME
.DW SP_STUB ; SP_RESET
.DW SP_STUB ; SP_VOLUME
.DW SP_PERIOD
.DW SP_NOTE
.DW SP_PLAY
.DW SP_QUERY
.DW SP_DURATION
;
#IF (($ - SP_FNTBL) != (SND_FNCNT * 2))
.ECHO "*** INVALID SND FUNCTION TABLE ***\n"
@ -24,8 +31,14 @@ 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_RTCIOMSK .EQU 00000100B
;
; FOR OTHER DRIVERS, THE PERIOD VALUE FOR THE TONE IS STORED AT PENDING_PERIOD
; FOR THE SPK DRIVER THE ADDRESS IN THE TONE TABLE IS STORED IN PENDING_PERIOD
;
SP_PENDING_PERIOD .DW SP_NOTE_C8 ; PENDING PERIOD (16 BITS)
SP_PENDING_VOLUME .DB $FF ; PENDING VOL (8 BITS)
SP_PENDING_DURATION .DW 0 ; PENDING DURATION (16 BITS)
;
;======================================================================
; DRIVER INITIALIZATION
@ -50,7 +63,7 @@ SP_INIT:
; SOUND DRIVER FUNCTION - RESET
;======================================================================
;
SP_RESET:
;SP_RESET:
; XOR A ; SUCCESSFULL RESET
; RET
;
@ -58,9 +71,9 @@ SP_RESET:
; SOUND DRIVER FUNCTION - VOLUME
;======================================================================
;
SP_VOLUME:
XOR A ; SIGNAL SUCCESS
RET
;SP_VOLUME:
; XOR A ; SIGNAL SUCCESS
; RET
;
;======================================================================
; SOUND DRIVER FUNCTION - PERIOD
@ -68,6 +81,7 @@ SP_VOLUME:
;
SP_PERIOD:
LD (SP_PENDING_PERIOD), HL ; SAVE AND RETURN SUCCESSFUL
SP_STUB:
XOR A
RET
;
@ -76,13 +90,23 @@ SP_PERIOD:
;======================================================================
;
SP_NOTE:
; CALL PRTHEXWORDHL
; CALL PC_COLON
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.
PUSH DE ; ON ENTRY HL IS A NOTE INDEX
LD A,L ; CONVERT THIS NOTE INDEX
AND 00000011B ; TO THE ASSOCIATED ENTRY
JR Z,SP_NOTE1 ; IN THE TUNE TABLE.
;
LD HL,$FFFF ; QUARTER NOTES
JR SP_NOTE2 ; NOT SUPPORTED
;
SP_NOTE1:
LD DE,SP_TUNTBL ; SAVE THIS ADDRESS AS
ADD HL,DE ; THE PERIOD
SP_NOTE2:
; CALL PRTHEXWORDHL
; CALL NEWLINE
LD (SP_PENDING_PERIOD),HL
POP DE
POP HL
@ -125,20 +149,27 @@ SP_QUERY_VOLUME:
RET
;
SP_QUERY_DEV:
LD B, BF_SND_BITMODE ; RETURN DEVICE IDENTIFIER
LD DE, 0 ; AND ADDRESS AND DATA PORT
LD B, BF_SND_BITMODE ; RETURN DEVICE IDENTIFIER
LD DE, (RTCIO*256)+SP_RTCIOMSK ; AND ADDRESS AND DATA PORT
XOR A
RET
;
;======================================================================
; INITIALIZE THE TONE TABLE
; INITIALIZE THE TONE TABLE - ONLY ACCURATE FOR 1MHZ INCREMENTS
;======================================================================
;
SP_SETTBL:
LD A,(CB_CPUMHZ) ; GET CPU SPEED.
LD C,A
LD B,SP_NOTCNT ; SET NUMBER OF NOTES TO
LD HL,(CB_CPUKHZ) ; GET CPU SPEED.
LD DE,1000 ; CONVERT TO MHZ
CALL DIV16
;
LD DE,900 ; IF MHZ IS WITHIN 10% OF
SBC HL,DE ; NEXT INTEGER INCREMENT
JP M,SP_SETTBL3 ; THEN BUMP UP. I.E. 9.928MHZ
INC C ; BECOMES 10MHZ
;
SP_SETTBL3:
LD B,SP_NOTCNT ; SET NUMBER OF NOTES TO
LD HL,SP_TUNTBL+2 ; ADJUST AND START POINT
;
SP_SETTBL2:
@ -149,13 +180,17 @@ SP_SETTBL2:
;
PUSH BC
LD B,C
LD HL,0 ; MULTIPLY
SP_SETTBL1: ; 1MHZ NOTE
ADD HL,DE ; VALUE BY
DJNZ SP_SETTBL1 ; SYSTEM MHZ
LD HL,0 ; MULTIPLY 1MHZ
SP_SETTBL1: ; NOTE VALUE BY
ADD HL,DE ; SYSTEM MHZ
JR NC,SP_SETBL4
LD HL,$FFFF ; FOR CPU > 10MHz
LD B,1 ; HANDLE OVERFLOW
SP_SETBL4:
DJNZ SP_SETTBL1
POP BC
;
LD DE,30 ; ADD OVERHEAD
LD DE,15 ; ADD OVERHEAD
ADD HL,DE ; COMPENSATION
;
POP DE ; RECALL NOTE
@ -178,22 +213,36 @@ SP_SETTBL1: ; 1MHZ NOTE
SP_PLAY:
LD HL,(SP_PENDING_PERIOD) ; SELECT NOTE
;
LD A,$FF ; EXIT WITH ERROR
CP H ; STATUS IF INVALID
JR NZ,SP_PLAY1 ; PERIOD ($FFFF)
CP L
RET Z
SP_PLAY1:
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
;
; LD A,$FF ; EXIT WITH ERROR
CP B ; STATUS IF INVALID
JR NZ,SP_PLAY2 ; NOTE ($FFFF)
CP C
RET Z
;
SP_PLAY2:
PUSH BC ; SETUP ARG IN HL
POP HL
;
CALL SP_BEEPER ; PLAY
; CALL SP_BEEPER ; PLAY
;
RET
; RET
;
; The following SP_BEEPER routine is a modification of code from
; "The Complete SPECTRUM ROM DISSASSEMBLY" by Dr Ian Logan & Dr Frank O’Hara
@ -205,7 +254,7 @@ SP_PLAY:
;
SP_BEEPER:
PUSH IX
DI ; Disable the interrupt for the duration of a 'beep'.
HB_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
@ -234,7 +283,7 @@ BE_H_L_LP:
;
; The loudspeaker is now alternately activated and deactivated.
;
XOR %00000100 ; Flip bit 2.
XOR SP_RTCIOMSK ; 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.
@ -258,123 +307,138 @@ BE_AGAIN:
INC C ; Add 16 T states as this path is shorter.
JP (IX) ; Jump back.
BE_END:
EI
HB_EI
POP IX
RET ; ALWAYS EXITS WITH SUCCESS STATUS (A=0)
;
;======================================================================
; SOUND DRIVER FUNCTION - DURATION
;======================================================================
;
SP_DURATION:
LD (SP_PENDING_DURATION),HL; SET TONE PERIOD TO ZERO
XOR A
RET
;
; STANDARD ONE SECOND TONE TABLES AT 1MHZ (UNCOMPENSATED). FOR SP_BEEPER, FIRST WORD LOADED INTO DE, SECOND INTO HL
;======================================================================
;
; STANDARD ONE SECOND TONE TABLES AT 1MHZ.
; FOR SP_BEEPER ROUTINE, 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
#DEFINE SP_TONESET(SP_FREQ) .DW SP_FREQ/100, 12500000/SP_FREQ
;
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_TONESET(1635) ; C0
SP_TONESET(1732) ; C
SP_TONESET(1835) ; D0
SP_TONESET(1945) ; D
SP_TONESET(2060) ; E0
SP_TONESET(2183) ; F0
SP_TONESET(2312) ; F
SP_TONESET(2450) ; G0
SP_TONESET(2596) ; G
SP_TONESET(2750) ; A0
SP_TONESET(2914) ; A
SP_TONESET(3087) ; B0
SP_TONESET(3270) ; C1
SP_TONESET(3465) ; C
SP_TONESET(3671) ; D1
SP_TONESET(3889) ; D
SP_TONESET(4120) ; E1
SP_TONESET(4365) ; F1
SP_TONESET(4625) ; F
SP_TONESET(4900) ; G1
SP_TONESET(5191) ; G
SP_TONESET(5500) ; A1
SP_TONESET(5827) ; A
SP_TONESET(6174) ; B1
SP_TONESET(6541) ; C2
SP_TONESET(6930) ; C
SP_TONESET(7342) ; D2
SP_TONESET(7778) ; D
SP_TONESET(8241) ; E2
SP_TONESET(8731) ; F2
SP_TONESET(9250) ; F
SP_TONESET(9800) ; G2
SP_TONESET(10383) ; G
SP_TONESET(11000) ; A2
SP_TONESET(11654) ; A
SP_TONESET(12347) ; B2
SP_TONESET(13081) ; C3
SP_TONESET(13859) ; C
SP_TONESET(14683) ; D3
SP_TONESET(15556) ; D
SP_TONESET(16481) ; E3
SP_TONESET(17461) ; F3
SP_TONESET(18500) ; F
SP_TONESET(19600) ; G3
SP_TONESET(20765) ; G
SP_TONESET(22000) ; A3
SP_TONESET(23308) ; A
SP_TONESET(24694) ; B3
SP_TONESET(26163) ; C4
SP_TONESET(27718) ; C
SP_TONESET(29366) ; D4
SP_TONESET(31113) ; D
SP_TONESET(32963) ; E4
SP_TONESET(34923) ; F4
SP_TONESET(36999) ; F
SP_TONESET(39200) ; G4
SP_TONESET(41530) ; G
SP_TONESET(44000) ; A4
SP_TONESET(46616) ; A
SP_TONESET(49388) ; B4
SP_TONESET(52325) ; C5
SP_TONESET(55437) ; C
SP_TONESET(58733) ; D5
SP_TONESET(62225) ; D
SP_TONESET(65925) ; E5
SP_TONESET(69846) ; F5
SP_TONESET(73999) ; F
SP_TONESET(78399) ; G5
SP_TONESET(83061) ; G
SP_TONESET(88000) ; A5
SP_TONESET(93233) ; A
SP_TONESET(98777) ; B5
SP_TONESET(104650) ; C6
SP_TONESET(110873) ; C
SP_TONESET(117466) ; D6
SP_TONESET(124451) ; D
SP_TONESET(131851) ; E6
SP_TONESET(139691) ; F6
SP_TONESET(147998) ; F
SP_TONESET(156798) ; G6
SP_TONESET(166122) ; G
SP_TONESET(179000) ; A6
SP_TONESET(186466) ; A
SP_TONESET(197553) ; B6
SP_TONESET(209300) ; C7
SP_TONESET(221746) ; C
SP_TONESET(234932) ; D7
SP_TONESET(248902) ; D
SP_TONESET(263702) ; E7
SP_TONESET(279383) ; F7
SP_TONESET(295996) ; F
SP_TONESET(313596) ; G7
SP_TONESET(332244) ; G
SP_TONESET(352000) ; A7
SP_TONESET(372931) ; A
SP_TONESET(395107) ; 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
SP_TONESET(418601) ; C8
SP_TONESET(443492) ; C
SP_TONESET(469863) ; D8
SP_TONESET(497803) ; D
SP_TONESET(527404) ; E8
SP_TONESET(558765) ; F8
SP_TONESET(591991) ; F
SP_TONESET(627193) ; G8
SP_TONESET(664488) ; G
SP_TONESET(704000) ; A8
SP_TONESET(745862) ; A
SP_TONESET(790213) ; B8
;
SP_NOTCNT .EQU ($-SP_TUNTBL) / 4
;

2
Source/HBIOS/time.asm

@ -83,7 +83,7 @@ DOW_YR .DB 0
DOW_DT .DB 0
DOW_MO .DB 0
;
; DERIVE DOW FROM STARNDARD TIME BUFFER AT HL
; DERIVE DOW FROM STANDARD TIME BUFFER AT HL
; RETURN DOW IN A (0-6: SUN-SAT)
;
TIMDOW:

8
Source/HBIOS/util.asm

@ -343,6 +343,8 @@ PRTIDXDEA:
PUSH BC
LD C,A ; INDEX COUNT
OR A
LD A,0
LD (PRTIDXCNT),A ; RESET CHARACTER COUNT
PRTIDXDEA1:
JR Z,PRTIDXDEA3
PRTIDXDEA2:
@ -357,6 +359,9 @@ PRTIDXDEA3:
; CALL WRITESTR ; FALL THROUGH TO WRITESTR
; RET
;
PRTIDXCNT:
.DB 0 ; CHARACTER COUNT
;
; OUTPUT A '$' TERMINATED STRING AT DE
;
WRITESTR:
@ -366,6 +371,9 @@ WRITESTR1:
CP '$' ; TEST FOR STRING TERMINATOR
JP Z,WRITESTR2
CALL COUT
LD A,(PRTIDXCNT)
INC A
LD (PRTIDXCNT),A
INC DE
JP WRITESTR1
WRITESTR2:

Loading…
Cancel
Save