diff --git a/asm_routines/mockingboard_a.s b/asm_routines/mockingboard_a.s new file mode 100644 index 00000000..29423d46 --- /dev/null +++ b/asm_routines/mockingboard_a.s @@ -0,0 +1,219 @@ +; 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_both: + lda #MOCK_AY_RESET + sta MOCK_6522_ORB1 + lda #MOCK_AY_INACTIVE + sta MOCK_6522_ORB1 + + ;====================== + ; 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 X + ; value in MB_VALUE + +write_ay_both: + ; address + stx 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 + lda MB_VALUE + sta 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 + + ;======================= + ; Write Left AY-3-8910 + ;======================= + +;write_ay_left: + ; address + stx 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 + lda MB_VALUE + sta 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_both: + ldx #14 + lda #0 + sta MB_VALUE +clear_ay_left_loop: + jsr write_ay_both + dex + bpl clear_ay_left_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 + diff --git a/chiptune_player/Makefile b/chiptune_player/Makefile index 8d48cf79..1706572b 100644 --- a/chiptune_player/Makefile +++ b/chiptune_player/Makefile @@ -5,8 +5,10 @@ PNG2GR = ../gr-utils/png2gr all: mock_player.dsk -mock_player.dsk: CHIPTUNE_PLAYER +mock_player.dsk: CHIPTUNE_PLAYER OUT.0 $(DOS33) -y mock_player.dsk BSAVE -a 0x1000 CHIPTUNE_PLAYER + $(DOS33) -y mock_player.dsk BSAVE -a 0x4000 OUT.0 + CHIPTUNE_PLAYER: chiptune_player.o ld65 -o CHIPTUNE_PLAYER chiptune_player.o -C ../linker_scripts/apple2_1000.inc diff --git a/chiptune_player/OUT.0 b/chiptune_player/OUT.0 new file mode 100644 index 00000000..3a887fd5 Binary files /dev/null and b/chiptune_player/OUT.0 differ diff --git a/chiptune_player/chiptune_player.s b/chiptune_player/chiptune_player.s index f7b502bd..c6043637 100644 --- a/chiptune_player/chiptune_player.s +++ b/chiptune_player/chiptune_player.s @@ -15,7 +15,7 @@ sta DONE_PLAYING sta XPOS - lda #1 + lda #0 sta MB_FRAME_DIFF lda #ksp_theme -; sta INH - -; lda (INL),Y ; read in frame delay -; sta MB_FRAME_DIFF -; inc INL ; FIXME: should check if we oflowed + lda #$40 + sta INH + lda #$00 + sta INL + lda #$0 + sta MB_CHUNK ;========================= ; Setup Interrupt Handler @@ -105,7 +101,7 @@ mockingboard_found: ; Enable 6502 interrupts ;============================ ; -; cli ; clear interrupt mask + cli ; clear interrupt mask ;============================ @@ -147,8 +143,7 @@ done_play: sei ; disable interrupts - jsr clear_ay_left - jsr clear_ay_right + jsr clear_ay_both lda #0 sta CH @@ -179,100 +174,53 @@ interrupt_handler: pha ; save A ; Should we save X and Y too? + inc $0404 ; debug + bit $C404 ; can clear 6522 interrupt by reading T1C-L - inc $0401 ; DEBUG: increment text char + ldy MB_FRAME_DIFF - dec MB_FRAME_DIFF - bne done_interrupt + ldx #0 +mb_write_loop: + lda (INL),y + cpx #13 + bne mb_not_13 + cmp #$ff + beq skip_r13 - - - ldy #0 -bottom_regs: - lda (INL),Y ; load low reg bitmask - sta MASK - ldx #$ff ; init to -1 -bottom_regs_loop: - inx ; increment X - cpx #$8 ; if we reach 8, done - beq top_regs ; move on to top - - ror MASK - bcc bottom_regs_loop ; if bit not set in mask, skip reg - - stx XX ; save X - - iny ; get next output value - lda (INL),Y ; read in value - - sty YY ; save Y - - tax ; value in X - ldy XX ; register# in Y - - ; reg in Y, value in X - jsr write_ay_left ; assume 3 channel (not six) - jsr write_ay_right ; so write same to both left/write - - ldx XX ; restore X - ldy YY ; restore Y - - jmp bottom_regs_loop ; loop - -top_regs: - iny ; point to next value - lda (INL),Y ; load top reg bitmask - sta MASK - ldx #$7 ; load X as 7 (we increment first) -top_regs_loop: - inx ; increment - cpx #16 - beq done_with_masks ; exit if done - - ror MASK - bcc top_regs_loop ; loop if not set - - stx XX ; save X value - - iny ; point to value - lda (INL),Y ; read in output value - - sty YY ; save Y value - - tax ; value in X - ldy XX ; register in Y - - ; reg in Y, value in X - jsr write_ay_left ; assume 3 channel (not six) - jsr write_ay_right ; so write same to both left/write - - ldx XX - ldy YY - - jmp top_regs_loop - -done_with_masks: -new_frame_diff: - iny - lda (INL),Y ; read in frame delay - cmp #$ff ; see if end - bne not_done ; if so, done - inc DONE_PLAYING ; set done playing flag - jmp done_interrupt -not_done: - sta MB_FRAME_DIFF - - iny +mb_not_13: + sta MB_VALUE + ; INLINE? + jsr write_ay_both ; assume 3 channel (not six) + ; so write same to both left/write clc - tya - adc INL - sta INL - lda #0 - adc INH + lda INH + adc #$4 sta INH + inx + cpx #14 + bmi mb_write_loop + +skip_r13: + lda MB_CHUNK + clc + adc #$40 + sta INH + + inc MB_FRAME_DIFF + bne done_interrupt +wraparound: + + inc MB_CHUNK + lda MB_CHUNK + cmp #$4 + bne chunk_good + lda #0 + sta MB_CHUNK +chunk_good: + done_interrupt: pla rti @@ -286,7 +234,7 @@ done_interrupt: ;========= .include "../asm_routines/gr_offsets.s" .include "../asm_routines/text_print.s" -.include "../asm_routines/mockingboard.s" +.include "../asm_routines/mockingboard_a.s" .include "../asm_routines/lzss_decompress.s" .include "../asm_routines/gr_fast_clear.s" .include "../asm_routines/pageflip.s" diff --git a/chiptune_player/mock_player.dsk b/chiptune_player/mock_player.dsk index e8336181..c5cbe9da 100644 Binary files a/chiptune_player/mock_player.dsk and b/chiptune_player/mock_player.dsk differ diff --git a/chiptune_player/zp.inc b/chiptune_player/zp.inc index a83a7dd0..a4ae6bf1 100644 --- a/chiptune_player/zp.inc +++ b/chiptune_player/zp.inc @@ -100,6 +100,8 @@ KEY_OFFSET EQU $8D DRAW_BLUE_SKY EQU $8E RANDOM_POINTER EQU $8F FRAME_COUNT EQU $90 +MB_VALUE EQU $91 +MB_CHUNK EQU $92 MB_ADDRL EQU $91 MB_ADDRH EQU $92 DONE_PLAYING EQU $93