mocklib/mocklib/mockingboard_speech.s

266 lines
4.9 KiB
ArmAsm

;
; speech.s
; mocktest
;
; Created by Jeremy Rand on 2016-09-29.
; Copyright © 2016 Jeremy Rand. All rights reserved.
;
.export _mockingBoardSpeechInit, _mockingBoardSpeechShutdown, _mockingBoardSpeakPriv
.export _mockingBoardSpeechData, _mockingBoardSpeechLen
.export _mockingBoardSpeechBusy, _mockingBoardSpeechPlaying
.interruptor mock_irq
TMPPTR := $FB ; Temporary pointer used in interrupt handler
IRQL := $03FE ; Interrupt vector, low byte
IRQH := $03FF ; Interrupt vector, high byte
BASE := $40 ; First speech chip
DURPHON := BASE ; Register 0 of speech chip
INFLECT := BASE+$01 ; Register 1 of speech chip
RATEINF := BASE+$02 ; Register 2 of speech chip
CTTRAMP := BASE+$03 ; Register 3 of speech chip
FILFREQ := BASE+$04 ; Register 4 of speech chip
DDRB := $02
DDRA := $03
PCR := $8C ; Peripheral control register, 6522
IFR := $8D ; Interrupt flag register, 6522
IER := $8E
.DATA
_mockingBoardSpeechData: .byte $00, $00
_mockingBoardSpeechLen: .byte $00, $00
_outptr: .byte $00, $00
_endptr: .byte $00, $00
_mockingBoardSpeechBusy: .byte $00
_mockingBoardSpeechPlaying: .byte $00
mock_irq: .byte $60
.lobytes _mockInterrupt
.hibytes _mockInterrupt
.CODE
writeChip:
sta $C000,X
rts
readChip:
lda $C000,X
rts
.proc _mockingBoardSpeechInit
sei
; The accumulator has the slot number of the mockingboard.
; Turn that into the address of the slot and set the address
; in the read and write functions.
and #$7
ora #$c0
sta writeChip+2
sta readChip+2
; Write a jump instruction at mock_irq to turn on our handler
lda #$4c
sta mock_irq
cli
rts
.endproc
.proc _mockingBoardSpeechShutdown
sei
; Write a RTS instruction at mock_irq to disable our handler
lda #$60
sta mock_irq
cli
rts
.endproc
.proc _mockingBoardSpeakPriv
sei
lda #$00
ldx #DDRA
jsr writeChip
ldx #DDRB
jsr writeChip
; Get the starting address of the data and store in the work pointer
lda _mockingBoardSpeechData+1
sta _outptr+1
lda _mockingBoardSpeechData
sta _outptr
; Calculate the end address from the start address and the length
lda _mockingBoardSpeechLen+1
clc
adc _mockingBoardSpeechData+1
sta _endptr+1
lda _mockingBoardSpeechLen
clc
adc _mockingBoardSpeechData
bcc @L2
inc _endptr+1
@L2:
sta _endptr
; Set the busy flag
lda #$FF
sta _mockingBoardSpeechBusy
; Set peripheral control register to recognize the signal from the
; speech chip.
lda #$0C
ldx #PCR
jsr writeChip
; Raise control bit in register 3
lda #$80
ldx #CTTRAMP
jsr writeChip
; Set transitioned inflection mode in register 0
lda #$C0
ldx #DURPHON
jsr writeChip
; Lower control bit
lda #$70
ldx #CTTRAMP
jsr writeChip
; Enable 6522 interrupts
lda #$82
ldx #IER
jsr writeChip
cli
rts
.endproc
.proc _mockInterrupt
; If we have a 6522 interrupt, jump to L4.
ldx #IFR
jsr readChip
bmi @L4
; Otherwise clear the carry to indicate we didn't handle the interrupt
; and return to the caller.
clc
rts
@L4:
; Clear the interrupt flag
lda #$02
ldx #IFR
jsr writeChip
; Check for end of data file. If not the end, jump to L1
lda _outptr+1
cmp _endptr+1
bcc @L1
bne @L5
lda _outptr
cmp _endptr
bcc @L1
@L5:
; If at the end, turn everything off. Store a pause phoneme.
lda #$00
ldx #DURPHON
jsr writeChip
; Zero amplitude
lda #$70
ldx #CTTRAMP
jsr writeChip
; Clear busy and playing flags
lda #$00
sta _mockingBoardSpeechBusy
sta _mockingBoardSpeechPlaying
; Clear interrupt enable in 6522
lda #$02
ldx #IER
jsr writeChip
lda #$FF
ldx #DDRA
jsr writeChip
lda #$07
ldx #DDRB
jsr writeChip
@L2:
; Set the carry flag to indicate we handled the interrupt and return to the caller.
sec
rts
@L1:
; Set the speach playing flag
lda #$ff
sta _mockingBoardSpeechPlaying
; Save the value of the tmp pointer on the stack
lda TMPPTR
pha
lda TMPPTR+1
pha
; Move the _outptr into the tmp pointer
lda _outptr
sta TMPPTR
lda _outptr+1
sta TMPPTR+1
; Init registers
ldy #$00
ldx #FILFREQ
@L6:
; Get the next data
lda (TMPPTR),Y
; Store in the speech chip
jsr writeChip
; Next data
inc TMPPTR
bne @L3
inc TMPPTR+1
@L3:
; Go to next register
dex
; If we are not done the last register, then loop back to L6
cpx #BASE-1
bne @L6
; We are done writing so move the tmp pointer back into _outptr
lda TMPPTR
sta _outptr
lda TMPPTR+1
sta _outptr+1
; Restore the tmp pointer from the stack
pla
sta TMPPTR+1
pla
sta TMPPTR
; Finish the interrupt handler
jmp @L2
.endproc