antoine-source/speechlab/speechlab.s
Antoine Vignau 4053a4120b v1
2023-11-02 19:27:23 +01:00

613 lines
14 KiB
ArmAsm

*
* SpeechLab 20A RAM code
* (c) 1978, Heuristics
* (c) 2019, Brutal Deluxe Software
* Visit http://www.brutaldeluxe.fr/
*
* Thank you, Jeremy Apple
*
org $6000
mx %11
lst off
*---------------------------------------------------------
* Version
*
* v1.0 - 20190120 - Antoine Vignau
* After a couple of tries, it is now working
* Thank you for your help, Jeremy Apple
* It would be cool to have a new version of the card!
*
*--- Equates
numWORDS = 32 ; number of words one can record (variable)
wordSIZE = 64 ; length of a spoken word (fixed)
*--- Zero page equates
CSWL = $36 ; for output
CSWH = CSWL+1
KSWL = CSWH+1 ; for input
KSWH = KSWL+1
A5H = $45 ; ACC
XREG = A5H+1 ; $46
YREG = XREG+1 ; $47
STATUS = YREG+1 ; $48
zpF0 = $fc ; Zero page addresses I use
zpF1 = zpF0+1 ; $FC..$FF
zpPTR = zpF1+1
*--- Firmware/ROM equates
BELL1 = $FBDD ; Beep
COUT1 = $FDF0 ; Output a char
RESTORE = $FF3F ; Restore A/X/Y/P
SAVE = $FF4A ; Save A/X/Y/P/S
IORTS = $FF58 ; The official RTS
*---------------------------------------------------------
* How to use
*
* Installation of the driver
* 10 PRINT CHR$(4);"BLOAD SPEECHLAB20A RAM DRIVER"
* 20 DP = 24576 : REM $6000 FOR PR#
* 30 DI = DP + 3 : REM $6003 FOR IN#
* 40 POKE DP + 8, 5 : REM SLOT OF THE CARD
* REM NO NEED FOR LOMEM ANYMORE
*
* Init the card
* 10 CALL DP : PRINT : CALL DP
* ==> simulates PR#slot : PRINT : PR#0
*
* Get the buffer address
* 10 BU = PEEK(DP + 7) * 256 + PEEK(DP + 6)
*
* Record a word
* 10 CALL DP : PRINT "WORD" : CALL DP
* ==> simulates PR#slot : PRINT "WORD" : PR#0
*
* Get a word
* 10 CALL DI : INPUT V$ : CALL DI
* ==> simulates IN#slot : INPUT V$ : IN#0
* ==> If V$ is an empty string, no word was recognized
*
*---------------------------------------------------------
* Room for improvement
*
* Make buffers movable
* The buffers follow the code. One could add pointers
* to put them in other areas of memory
*
* Change the number of words
* That one is easy, change numWORDS to the value you want
*
* PR# and IN#
* One could keep the doPR and doIN to simulate the PR#
* and IN# BASIC calls. PR#0 and IN#0 could be kept
* That would save one page of code
*
*---------------------------------------------------------
* Entry point
jmp doPR ; CALL $6000
jmp doIN ; CALL $6003
da ptrBUFFER ; PEEK($6007)*256 + PEEK($6006)
L12F2 ds 1 ; POKE($6008),slot
; later transformed to slot*16
*---------------------------------------------------------
* The card runs with the INT ROM on
* If the "modern" ROMs are called,
* then calls to SAVE/RESTORE will be useless
LC809 ; our new entry point
lda L12F2 ; is slot already
cmp #7+1 ; set to slot*16?
bcs LC817 ; yes
asl
asl
asl
asl
sta L12F2 ; no, do slot*16
LC817 JSR SAVE ; save all parms
LDA CSWH ; output is already set to our card?
CMP #>LC900 ; L12F1
BEQ LC878 ; yes
LDA #LC84B
STA KSWH
LDA #IORTS
STA CSWH
LDY #$00 ; string index is 0
STY L12F4
JSR LC956 ; DO MAGIC
CMP #numWORDS
BPL LC875
TAX ; index
LDA L12F6,X ; pointer
STA zpPTR
LDA L1317,X
STA zpPTR+1
JSR RESTORE ; restore
LC84B JSR SAVE ; save
LDY L12F4 ; get index
LDA (zpPTR),Y ; get char
INC L12F4 ; y++
CMP #$8D ; end of string?
BNE LC864 ; no
LC85A LDA #LC817
STA KSWH
LDA #$8D ; exit with a RET
LC864 PHA ; save
JSR RESTORE ; restore
PLA ; pull A
RTS ; return
LC86A LDA #COUT1
STA CSWH
rts ; exit to RANGE ERR (modified)
LC875 JMP LC85A
*--- Card is already init'ed
LC878 LDA A5H ; get a char
CMP #$8D ; 8D means reset list of words
BEQ LC8D8
LDA #LC89F
STA CSWH
LDY #$00 ; Y as a counter
STY L12F4
LDX L12F3 ; word index
CPX #numWORDS
BPL LC86A ; we're full!
LDA L12F6,X ; get its pointer
STA zpPTR
LDA L1317,X
STA zpPTR+1
JSR RESTORE ; restore registers
LC89F JSR SAVE ; save registers
LDA A5H ; get A
LDY L12F4 ; get Y
STA (zpPTR),Y ; save char
INC L12F4 ; y++
CMP #$8D
BNE LC8D4
LDA L12F3 ; we're done, get word index
JSR LC909 ; DO MAGIC
INC L12F3 ; next index
LDX L12F3 ; get it again
LDA zpPTR ; ptr to char
CLC
ADC L12F4 ; +index in string
STA L12F6,X ; save pointer low
LDA zpPTR+1
ADC #$00
STA L1317,X ; save pointer high
LDA #LC817
STA CSWH
LC8D4 jmp RESTORE ; restore and exit (JMP)
LC8D8 LDA #$00 ; word index
STA L12F3
LDA #L1339
STA L1317
LDA #$00 ; init table of words
LDX #numWORDS-1
LC8EB STA L0820,X
DEX
BPL LC8EB
jmp RESTORE ; restore all and return (JMP)
*---------------------------------------------------------
*--- Buffers and friends
L081F ds 1 ; a value
L12F3 ds 1 ; index in list of words, see L12F6
L12F4 ds 1 ; Y as an index
L12F5 ds 1 ; A as an index
ds \
*---------------------------------------------------------
* The $Cs00 page
LC900 JSR LC809
LC909 STA L081F
TAX
LDA #$01
STA L0820,X
LC912 JSR LC973
BEQ LC96D
JSR LCB2D
LDA #L0AF1
STA L0808+2
LDA #$00
LSR L081F
BCC LC92D
LDA #wordSIZE
LC92D LSR L081F
BCC LC934
ORA #$80
LC934 CLC
ADC L0808+1
STA L0808+1
LDA L0808+2
ADC L081F
STA L0808+2
LDA #L0AB1
STA L0805+2
LDA #wordSIZE-1
JSR L0804
LDA #$00
RTS
LC956 JSR LC973
CMP #$00
BEQ LC967
JSR LCB2D
JSR LCA94
LDA L0840
RTS
LC967 JSR BELL1
JMP LC956
LC96D JSR BELL1
JMP LC912
*--- CALLED BY $Cs00
LC973 LDA #$00
STA L0840+$1
STA L0840+$2
LC97B LDA #L0859
STA L080F+2
JSR LC9E9
BEQ LC97B
LDA #$08
STA L0840+$7
LC98F JSR LC9E9
BEQ LC973
DEC L0840+$7
BNE LC98F
LDA #$0A
STA L0840+$8
LC99E JSR LC9E9
BEQ LC9B9
LDA #$0A
STA L0840+$8
LC9A8 LDA L080F+2 ; end of buffer?
CMP #>L0AB1
BNE LC99E
LDA L080F+1
CMP #L0859
ROR
ROR L0840+$15
ROR
ROR L0840+$15
LDA L0840+$15
RTS
*---------------------------------------------------------
LC9E9 LDY #$00
LDX L12F2
STY L0840+$9
LDA $C080,X
EOR #$FF
AND #$01
BEQ LCA0B
STA L0840+$9
JMP LCA09
ds \
*---------------------------------------------------------
LCA09 LDA #$08
LCA0B JSR L080F
LDA $C080,X
EOR #$FF
AND #$10
BEQ LCA1A
STA L0840+$9
LCA1A LDA #$08
JSR L080F
JSR LCA26
LDA L0840+$9
RTS
LCA26 LDA #$C8 ; counter
STA L0840+$A
LDA #$00
STA L0840+$4
STA L0840+$5
LDA L0840+$1
STA L0840+$B
LDA L0840+$2
STA L0840+$C
LCA3F LDA $C080,X
AND #$08
CMP L0840+$B
BEQ LCA52
STA L0840+$B
INC L0840+$4
LCA4F JMP LCA5B
LCA52 LDA L0840+$4
JMP LCA58
LCA58 JMP LCA4F
LCA5B LDA $C080,X
AND #$80
CMP L0840+$C
BEQ LCA6E
STA L0840+$C
INC L0840+$5
LCA6B JMP LCA77
LCA6E LDA L0840+$5
JMP LCA74
LCA74 JMP LCA6B
LCA77 DEC L0840+$A
BNE LCA3F
LDA L0840+$4
CMP #$20
BCC LCA86
STA L0840+$9
LCA86 JSR L080F
LDA L0840+$5
CMP #$50
BCC LCA90
LCA90 JSR L080F
RTS
LCA94 LDA #L0AF1
SBC #$00
STA L0800+2
LDA #$F4
STA L0840+$D
LDA #$01
STA L0840+$E
LDA #$20
STA L0840
LDY #$FF
LCAB4 INY
CPY #numWORDS
BMI LCABA
RTS
LCABA LDA #wordSIZE ; next
CLC
ADC L0800+1
STA L0800+1
LDA #$00
ADC L0800+2
STA L0800+2
LDA L0820,Y
BEQ LCAB4
LDA #$00
STA L0840+$F
STA L0840+$10
LDX #wordSIZE-1
LCADA JSR L0800
SEC
SBC L0AB1,X
BCS LCAE7
EOR #$FF
ADC #$01
LCAE7 CLC
ADC L0840+$10
STA L0840+$10
LDA #$00
ADC L0840+$F
STA L0840+$F
CMP L0840+$D
JMP LCB09
ds \
*---------------------------------------------------------
LCB09 BCC LCB15
BNE LCAB4
LDA L0840+$10
CMP L0840+$E
BCS LCAB4
LCB15 DEX
BMI LCB1B
JMP LCADA
LCB1B LDA L0840+$F
STA L0840+$D
LDA L0840+$10
STA L0840+$E
STY L0840
JMP LCAB4
*--- CALLED BY $Cs00
LCB2D LDA #L0AB1
STA L080F+2
LDA L0840+$15
STA L0840+$13
LDA #$00
STA L0840+$11
LDA #$10
STA L0840+$12
JSR LCBA3
STA zpF0
STA zpF1
LDA L0840+$13
ASL
ASL
STA L0840+$16
BEQ LCB5B
SEC
SBC #$04
LCB5B CLC
ADC #L0859
ADC #$00
STA L081B+2
LDA #$10
STA L12F5
LCB6D LDY #$00
LCB6F JSR L081B
JSR L080F
INY
CPY #$04
BNE LCB6F
LDA zpF0
CLC
ADC zpF1
STA zpF0
SEC
SBC #$10
BMI LCB8C
STA zpF0
LDA #$04
BPL LCB8E
LCB8C LDA #$00
LCB8E CLC
ADC L0840+$16
ADC L081B+1
STA L081B+1
BCC LCB9D
INC L081B+2
LCB9D DEC L12F5
BNE LCB6D
RTS
LCBA3 CLC
LDX #$F7
LDA L0840+$11
LCBA9 ROL L0840+$13
INX
BMI LCBB2
JMP LCBC7
LCBB2 ROL
BCC LCBBB
SBC L0840+$12
SEC
BCS LCBA9
LCBBB SEC
SBC L0840+$12
BCS LCBA9
ADC L0840+$12
CLC
BCC LCBA9
LCBC7 STA L0840+$11
RTS
*---------------------------------------------------------
L0800 LDA |$0000,X ; CODE AT $0800
RTS
L0804 TAX
L0805 LDA |$0000,X
L0808 STA |$0000,X
DEX
BPL L0805
RTS
L080F STA |$0000
INC L080F+1
BNE L081A
INC L080F+2
L081A RTS
L081B LDA |$0000,Y
RTS
ds \
*---------------------------------------------------------
* doPR
* We simulate PR#slot and here
doPR lda #0
bne doPRR ; restore
ldx CSWL ; put our hook routine
stx oldCSWL
ldy CSWH
sty oldCSWH
ldx #LC900
tya ; A is not 0
doPRE stx CSWL ; save values
sty CSWH
sta doPR+1 ; flip/flop
rts
doPRR ldx oldCSWL ; restore old values
ldy oldCSWH
lda #0
beq doPRE
oldCSWL ds 1
oldCSWH ds 1
*---------------------------------------------------------
* doIN
* We simulate IN#slot and here
doIN lda #0
bne doINR ; restore
ldx KSWL ; put our hook routine
stx oldKSWL
ldy KSWH
sty oldKSWH
ldx #LC900
tya ; A is not 0
doINE stx KSWL ; save values
sty KSWH
sta doIN+1 ; flip/flop
rts
doINR ldx oldKSWL ; restore old values
ldy oldKSWH
lda #0
beq doINE
oldKSWL ds 1
oldKSWH ds 1
*---------------------------------------------------------
*--- Buffers and friends
ptrBUFFER ; address of the buffer
L0840 ds $19 ; variables
L0859 ds 600 ; read buffer
; the buffer is $258 (600d) bytes long
L0AB1 ds wordSIZE ; a buffer ($40 bytes)
L0AF1 ds numWORDS*wordSIZE ; a buffer ($800 bytes)
L0820 ds numWORDS ; a table of numWORDS bytes (0: no word, 1: a word)
L12F6 ds numWORDS+1 ; table of pointers low ($21 bytes)
L1317 ds numWORDS+1 ; table of pointers high ($21 bytes)
L1339 ds numWORDS*numWORDS ; a buffer for words (the words)