; Mockingboad programming: ; + Has two 6522 I/O chips connected to two AY-3-8910 chips ; + Optionally has some speech chips controlled via the outport on the AY ; + Often in slot 4 ; TODO: how to auto-detect? ; References used: ; http://macgui.com/usenet/?group=2&id=8366 ; 6522 Data Sheet ; AY-3-8910 Data Sheet ;======================== ; Mockingboard card ; Essentially two 6522s hooked to the Apple II bus ; Connected to AY-3-8910 chips ; PA0-PA7 on 6522 connected to DA0-DA7 on AY ; PB0 on 6522 connected to BC1 ; PB1 on 6522 connected to BDIR ; PB2 on 6522 connected to RESET ; left speaker MOCK_6522_ORB1 EQU $C400 ; 6522 #1 port b data MOCK_6522_ORA1 EQU $C401 ; 6522 #1 port a data MOCK_6522_DDRB1 EQU $C402 ; 6522 #1 data direction port B MOCK_6522_DDRA1 EQU $C403 ; 6522 #1 data direction port A ; right speaker MOCK_6522_ORB2 EQU $C480 ; 6522 #2 port b data MOCK_6522_ORA2 EQU $C481 ; 6522 #2 port a data MOCK_6522_DDRB2 EQU $C482 ; 6522 #2 data direction port B MOCK_6522_DDRA2 EQU $C483 ; 6522 #2 data direction port A ; AY-3-8910 commands on port B ; RESET BDIR BC1 MOCK_AY_RESET EQU $0 ; 0 0 0 MOCK_AY_INACTIVE EQU $4 ; 1 0 0 MOCK_AY_READ EQU $5 ; 1 0 1 MOCK_AY_WRITE EQU $6 ; 1 1 0 MOCK_AY_LATCH_ADDR EQU $7 ; 1 1 1 ;======================== ; Mockingboard Init ;======================== ; Initialize the 6522s ; set the data direction for all pins of PortA/PortB to be output mockingboard_init: lda #$ff ; all output (1) sta MOCK_6522_DDRB1 sta MOCK_6522_DDRA1 sta MOCK_6522_DDRB2 sta MOCK_6522_DDRA2 rts ;====================== ; Reset Left AY-3-8910 ;====================== reset_ay_left: lda #MOCK_AY_RESET sta MOCK_6522_ORB1 lda #MOCK_AY_INACTIVE sta MOCK_6522_ORB1 rts ;====================== ; Reset Right AY-3-8910 ;====================== reset_ay_right: lda #MOCK_AY_RESET sta MOCK_6522_ORB2 lda #MOCK_AY_INACTIVE sta MOCK_6522_ORB2 rts ; Write sequence ; Inactive -> Latch Address -> Inactive -> Write Data -> Inactive ;======================= ; Write Right AY-3-8910 ;======================= ; register in Y ; value in X write_ay_right: ; address sty MOCK_6522_ORA1 ; put address on PA lda #MOCK_AY_LATCH_ADDR ; latch_address on PB sta MOCK_6522_ORB1 lda #MOCK_AY_INACTIVE ; go inactive sta MOCK_6522_ORB1 ; value stx MOCK_6522_ORA1 ; put value on PA lda #MOCK_AY_WRITE ; write on PB sta MOCK_6522_ORB1 lda #MOCK_AY_INACTIVE ; go inactive sta MOCK_6522_ORB1 rts ;======================= ; Write Left AY-3-8910 ;======================= ; register in X ; value in Y write_ay_left: ; address sty MOCK_6522_ORA2 ; put address on PA lda #MOCK_AY_LATCH_ADDR ; latch_address on PB sta MOCK_6522_ORB2 lda #MOCK_AY_INACTIVE ; go inactive sta MOCK_6522_ORB2 ; value stx MOCK_6522_ORA2 ; put value on PA lda #MOCK_AY_WRITE ; write on PB sta MOCK_6522_ORB2 lda #MOCK_AY_INACTIVE ; go inactive sta MOCK_6522_ORB2 rts ;======================================= ; clear ay -- clear all 14 AY registers ; should silence the card ;======================================= clear_ay_left: ldy #14 ldx #0 clear_ay_left_loop: jsr write_ay_left dey bpl clear_ay_left_loop rts ;======================================= ; clear ay -- clear all 14 AY registers ; should silence the card ;======================================= clear_ay_right: ldy #14 ldx #0 clear_ay_right_loop: jsr write_ay_right dey bpl clear_ay_right_loop rts ;======================================= ; Detect a Mockingboard card ;======================================= ; Based on code from the French Touch "Pure Noise" Demo ; Attempts to time an instruction sequence with a 6522 ; ; If found, puts in bMB ; MB_ADDRL:MB_ADDRH has address of Mockingboard ; returns X=0 if not found, X=1 if found mockingboard_detect: lda #0 sta MB_ADDRL mb_detect_loop: ; self-modifying lda #$07 ; we start in slot 7 ($C7) and go down to 0 ($C0) ora #$C0 ; make it start with C sta MB_ADDRH ldy #04 ; $CX04 ldx #02 ; 2 tries? mb_check_cycle_loop: lda (MB_ADDRL),Y ; timer 6522 (Low Order Counter) ; count down sta TEMP ; 3 cycles lda (MB_ADDRL),Y ; + 5 cycles = 8 cycles ; between the two accesses to the timer sec sbc TEMP ; subtract to see if we had 8 cycles cmp #$f8 ; -8 bne mb_not_in_this_slot dex ; decrement, try one more time bne mb_check_cycle_loop ; loop detection inx ; Mockingboard found (X=1) done_mb_detect: ;stx bMB ; store result to bMB rts ; return mb_not_in_this_slot: dec mb_detect_loop+1 ; decrement the "slot" (self_modify) bne mb_detect_loop ; loop down to one ldx #00 beq done_mb_detect ;======================================= ; Detect a Mockingboard card in Slot4 ;======================================= ; Based on code from the French Touch "Pure Noise" Demo ; Attempts to time an instruction sequence with a 6522 ; ; MB_ADDRL:MB_ADDRH has address of Mockingboard ; returns X=0 if not found, X=1 if found mockingboard_detect_slot4: lda #0 sta MB_ADDRL mb4_detect_loop: ; self-modifying lda #$04 ; we're only looking in Slot 4 ora #$C0 ; make it start with C sta MB_ADDRH ldy #04 ; $CX04 ldx #02 ; 2 tries? mb4_check_cycle_loop: lda (MB_ADDRL),Y ; timer 6522 (Low Order Counter) ; count down sta TEMP ; 3 cycles lda (MB_ADDRL),Y ; + 5 cycles = 8 cycles ; between the two accesses to the timer sec sbc TEMP ; subtract to see if we had 8 cycles cmp #$f8 ; -8 bne mb4_not_in_this_slot dex ; decrement, try one more time bne mb4_check_cycle_loop ; loop detection inx ; Mockingboard found (X=1) done_mb4_detect: rts ; return mb4_not_in_this_slot: ldx #00 beq done_mb4_detect