;license:MIT ;(c) 2019-2022 by Andrew Roughan, qkumba, 4am, Tom Charlesworth, Rob Justice ; ; Mockingboard support functions ; ;------------------------------------------------------------------------------ ; GetMockingboardStuff ; detect Mockingboard card by searching for 6522 timers across all slots 7->1 ; access 6522 timers with deterministic cycle counts ; ; based on prior art in Mockingboard Developers Toolkit ; with optimisation from deater/french touch ; also takes into account FastChip //e clock difference ; ; in: A/Y contains address of callback to call if card was found ; (this will be called before the speech detection routine, and ; (zp$81 will contain the slot in form $Cx) ; /!\ ALL ACCELERATORS MUST BE OFF OR SET TO 1 MHZ ; out: if card was found, X = #$?n where n is the slot number of the card, otherwise #$00 ; and bit 5 = 0 if Mockingboard Sound I found ; or bit 5 = 1 if Mockingboard Sound II or "A"-"D" found ; and bit 6 = 1 if SSI-263 speech chip found ; or bit 7 = 1 if SC-01 speech chip found ; flags clobbered ; zp $80-$82 clobbered ; A/Y clobbered ;------------------------------------------------------------------------------ MAGIC_Z80_LOCATION=$FFD GetMockingboardStuff +ST16 @callback+1 lda ROM_MACHINEID cmp #$06 bne @not_iic ldx ROM_MACHINE2C bne @not_iic ; from mgcaret ; https://github.com/a2-4am/4cade/issues/483 ; the Mockingboard init can accidentally enable the Softcard Z80 ; and can crash the machine ; solved by loading a small Z80 routine at $0FFD (FFFDh in the Z80 space): ; $32 $00 $E4 $C3 FD FF which is ; NOP ; LD (E400h),A ; card is at $E400 due to memory translation ; JP FFFDh ; returns the system to 6502 mode and leaves it in the same state as the Z80 after RESET: ; ready to execute the instruction at 0000h (from the Z80 perspective) ldx #5 - lda magic_z80_bytes, x sta MAGIC_Z80_LOCATION, x dex bpl - stx $C403 ; enable Mockingboard 4C support stx $C404 @not_iic lda #$00 sta $80 sta $82 ; type ldx #$C1 @slotLoop stx $81 ldy #$04 ; 6522 #1 $Cx04 jsr @timercheck bcc @foundI @nextSlot inx cpx #$C8 bne @slotLoop ldx #$00 ; not found rts @foundI ; sound I or better jsr @callback ldy #$84 ; 6522 #2 $Cx84 jsr @timercheck bcc @foundII ldy #$0c sty @mb_smc1 + 1 iny sty @mb_smc10 + 1 iny sty @mb_smc5 + 1 sty @mb_smc14 + 1 clc +HIDE_NEXT_BYTE @foundII ;stereo sec ror $82 lda $81 sta @mb_smc1 + 2 sta @mb_smc2 + 2 sta @mb_smc3 + 2 sta @mb_smc4 + 2 sta @mb_smc5 + 2 sta @mb_smc6 + 2 sta @mb_smc7 + 2 sta @mb_smc8 + 2 sta @mb_smc9 + 2 sta @mb_smc10 + 2 sta @mb_smc11 + 2 sta @mb_smc12 + 2 sta @mb_smc13 + 2 sta @mb_smc14 + 2 sta @mb_smc15 + 2 sta @mb_smc17 + 2 sta @mb_smc18 + 2 sta @mb_smc19 + 2 sta @mb_smc20 + 2 sta @mb_smc21 + 2 sta @mb_smc22 + 2 ; detect speech - SSI263 sei +READ_RAM2_WRITE_RAM2 lda #$40 ; setup NMI vector (rti) sta $3fb lda #$fb sta $fffa lda #3 sta $fffb lda #<@mb_irq ; setup IRQ vector sta $3fe sta $fffe lda #>@mb_irq sta $3ff sta $ffff lda #$0c ; CB2 - input neg edge, CB1 neg edge, CA2 low output, CA1 neg edge @mb_smc1 sta $c48c ; peripheral control register 6522#2 lda #$80 ; ctl=1 @mb_smc2 sta $c443 ; C = SSI reg 3, S/S I or A = 6522#1 ddr a lda #$c0 ; duration=11 phoneme=000000 (pause) @mb_smc3 sta $c440 ; C = SSI reg 0, S/S I or A = 6522#1 port b data lda #$70 ; ctl=0 (A/R active - phoneme timing response) @mb_smc4 sta $c443 ; C = SSI reg 3, S/S I or A = 6522#1 ddr a lda #$82 ; enable CA1 interrupt @mb_smc5 sta $c48e ; interrupt enable register 6522#2 ldx #$80 ; 0= ~650ms, 80 = ~325ms ldy #0 sec cli @wait_irq lda $80 bne + iny bne @wait_irq inx bne @wait_irq clc + ror $82 ; detect speech - SC-01 ;based on S/S I demo dsk ;init sc-01 interface lda #$ff @mb_smc15 sta $c402 ; ddr portb - all outputs lda #$b0 ; cb2 pulse output,cb1 pos edge @mb_smc17 sta $c40c ; pcr lda #$10 ; clear all interrupt flags @mb_smc18 sta $c40d ; ifr ;output stop phoneme lda #$3f ; stop @mb_smc19 sta $c400 ; orb, write phoneme & pitch ldx #$D0 ; wait ~120ms, stop takes 47ms - lda #$10 @mb_smc20 bit $c40d ; ifr, check for cb1 interrupt flag bne + ; flag set, we found one iny bne - inx bne - beq @got_irq @mb_smc21 + sta $c40d ; ifr, clear flag lda #$00 ; turn off cb2 pulse mode to disable false writes to sc01 @mb_smc22 sta $c40c ; pcr sec ; found, we have an SC-01 ror $82 bne @ssI @got_irq sei clc ; not found ror $82 ldy #$ff @mb_smc6 sty $c403 ; 6522#1 ddra lda #7 @mb_smc7 sta $c402 ; 6522#1 ddrb iny sty $80 tya sta ($80),y ; 6522#1 orb lda #4 sta ($80),y ; 6522#1 orb @ssI ldy #$ff @mb_smc8 sty $c483 ; 6522#2 ddra lda #7 @mb_smc9 sta $c482 ; 6522#2 ddrb lda #0 ldy #$80 sta ($80),y ; 6522#2 orb lda #4 sta ($80),y ; 6522#2 orb lda #7 and $81 ora $82 tax lda #Ignore sta $ffff +READ_ROM_NO_WRITE rts ; found @timercheck sec lda ($80),y ; read 6522 timer low byte sbc ($80),y ; second time sec sbc #5 ; looking for 5 cycles between reads cmp #2 ; or 6 cycles with the FastChip //e rts @mb_irq lda #2 ; clear CA1 interrupt flag @mb_smc10 sta $c48d ; interrupt flag register 6522#2 lda #$80 ; ctl=1 @mb_smc11 sta $c443 ; C = SSI reg 3, S/S I or A = 6522#1 ddr a lda #0 ; duration=00 phoneme=000000 (pause) @mb_smc12 sta $c440 ; C = SSI reg 0, S/S I or A = 6522#1 port b data lda #$70 ; ctl=0 (A/R active - phoneme timing response) @mb_smc13 sta $c443 ; C = SSI reg 3, S/S I or A = 6522#1 ddr a sta $80 ; found lda #2 ; disable CA1 interrupt @mb_smc14 sta $c48e ; interrupt enable register 6522#2 lda $45 rti @callback jmp $FDFD ; SMC magic_z80_bytes !byte $32, $00, $E4, $C3, $FD, $FF