;.include "ssi263.inc"

; Simple speech routine for ssi-263

; to save space we only change the Phoneme/Delay each time, we don't
; mess with the other registers

	;========================
	; ssi263_write_chip
	;========================
ssi263_write_chip:
wc_smc1:
	sta	$C000,X
	rts

	;========================
	; read_chip
	;========================
ssi263_read_chip:
rc_smc1:
	lda	$C000,X
	rts


	;========================
	; ssi263_speech_init
	;========================
	; A = slot number of mockingboard
ssi263_speech_init:
	sei			; disable interrupts

	and	#$7
	ora	#$c0		; turn slot number into address
	sta	wc_smc1+2	; update the read/write routines
	sta	rc_smc1+2

	; Set 6522#2 peripheral control register to recognize the signal
	; from the speech chip.
	lda	#(VIA6522_PCR2_CA2_LOW|VIA6522_PCR2_CA1_NEG)
	ldx	#VIA6522_PCR2
	jsr	ssi263_write_chip


	lda	#<ssi263_speech_irq	; point IRQ handler to our code
	sta	$3fe
	lda	#>ssi263_speech_irq
	sta	$3ff


	; set defaults

	; filter frequency
	lda	#$E9
	ldx	#SSI263_F
	jsr	ssi263_write_chip

	; control / articulation/ amplitude
	lda	#$5C
	ldx	#SSI263_CAA
	jsr	ssi263_write_chip

	; rate/inflection
	lda	#$A8
	ldx	#SSI263_RI
	jsr	ssi263_write_chip

	; inflection
	lda	#$50
	ldx	#SSI263_I
	jsr	ssi263_write_chip

	cli				; enable interrupts

	rts


	;============================
	; ssi263_speech_shutdown
	;============================

ssi263_speech_shutdown:
	sei

	jsr	ssi263_disable

	rts



	;=========================
	; ssi263_speak
	;=========================
	; pointer to data in SPEECH_PTRL/H

ssi263_speak:

	sei		; disable interrupts

	; Set the busy flag
	lda	#$FF
	sta	speech_busy

	; Set peripheral control register to recognize the signal from the
	; speech chip.
	lda	#(VIA6522_PCR2_CA2_LOW|VIA6522_PCR2_CA1_NEG)
	ldx	#VIA6522_PCR2
	jsr	ssi263_write_chip

	; Set transitioned inflection by setting value while toggling CTL

	lda	#SSI263_CAA_CTL
	ldx	#SSI263_CAA
	jsr	ssi263_write_chip

	; Set transitioned inflection mode in register 0
	lda	#SSI263_DRP_TRANSITIONED_INFLECTION
	ldx	#SSI263_DRP
	jsr	ssi263_write_chip

	; Lower control bit
	lda	#$70		; also T=7
	ldx	#SSI263_CAA
	jsr	ssi263_write_chip

	; Enable 6522 interrupts
	lda	#(VIA6522_IER2_SET|VIA6522_IER2_CA1)
	ldx	#VIA6522_IER2
	jsr	ssi263_write_chip

	cli			; re-enable interrupts

	rts


	;====================
	; speech interrupt
	;====================
ssi263_speech_irq:

	php			; save flags
	cld

	pha			; save A
	txa
	pha			; save X
	tya
	pha			; save Y

;	inc	$0404		; irq indicator on screen

	; be sure it was a 6522#2 interrupt
	ldx	#VIA6522_IFR2
	jsr	ssi263_read_chip
	bmi	have_interrupt

	; wasn't us, return to caller
	; this assumes we can handle multiple interrupt sources

	jmp	end_interrupt

have_interrupt:
	; Clear the 6522#2 CA interrupt flag
	lda	#VIA6522_IFR2_CA1
	ldx	#VIA6522_IFR2
	jsr	ssi263_write_chip

	; Check if done with speech
	ldy	#0
	lda	(SPEECH_PTRL),Y
	cmp	#$ff
	beq	speech_end

not_end:

	; Set the speech playing flag
	lda	#$ff
	sta	speech_playing


	ldy	#$00
	; Get the next data
	lda	(SPEECH_PTRL),Y
	ldx	#SSI263_DRP		; duration/phoneme
	jsr	ssi263_write_chip

	; Next data (inc 16 bit)
	inc	SPEECH_PTRL
	bne	no_oflo
	inc	SPEECH_PTRH
no_oflo:

	; Finish the interrupt handler
	jmp	end_interrupt

speech_end:

	jsr	ssi263_disable

end_interrupt:

	pla
	tay				; restore Y
	pla
	tax				; restore X

	pla				; restore A

ssi_interrupt_smc:
	lda	$45			; restore A (II+/IIe)

	plp				; restore flags

	rti				; return from interrupt



ssi263_disable:
	; If at the end, turn everything off

	; Toggle CTL while DR set to disable A/!R

	lda	#SSI263_CAA_CTL
	ldx	#SSI263_CAA
	jsr	ssi263_write_chip

	lda	#SSI263_DRP_DISABLE_AR
	ldx	#SSI263_DRP
	jsr	ssi263_write_chip

	; Zero amplitude
	lda	#$70
	ldx	#SSI263_CAA
	jsr	ssi263_write_chip

	; Clear busy and playing flags
	lda	#$00
	sta	speech_busy
	sta	speech_playing

	; Disable interrupt in 6522
	lda	#VIA6522_IER2_CA1
	ldx	#VIA6522_IER2
	jsr	ssi263_write_chip

	rts


speech_busy:	.byte   $00
speech_playing:	.byte   $00