tracker6: make it interrupt-run

This commit is contained in:
Vince Weaver 2022-11-09 22:21:25 -05:00
parent 28fb6d13ba
commit 27516de7f9
6 changed files with 170 additions and 45 deletions

View File

@ -37,7 +37,8 @@ d4.o: d4.s \
zp.inc hardware.inc \
mA2E_4.s \
mockingboard_init.s play_frame.s \
tracker_init.s ay3_write_regs.s
tracker_init.s ay3_write_regs.s interrupt_handler.s \
mockingboard_constants.s
ca65 -o d4.o d4.s -l d4.lst
@ -53,4 +54,4 @@ text_to_tiny.o: text_to_tiny.c
####
clean:
rm -f *~ *.o *.lst D2 HELLO text_to_tiny mA2E_2.s mA2E_3.s mA2E_4.s
rm -f *~ *.o *.lst D4 HELLO text_to_tiny mA2E_2.s mA2E_3.s mA2E_4.s

View File

@ -6,21 +6,8 @@
.include "zp.inc"
.include "hardware.inc"
; for a 256 entry we need to fit in 252 bytes
; 310 bytes -- initial
; 268 bytes -- strip out interrupts
; 262 bytes -- simplify init
; 261 bytes -- optimize init more
; 253 bytes -- optimize var init
; 252 bytes -- bne vs jmp
; 250 bytes -- song only has 16 notes so can never be negative
; 249 bytes -- make terminating value $80 instead of $FF
; 247 bytes -- combine note loop. makes song a bit faster
; 245 bytes -- try to optimize writing out volume
; 255 bytes -- add in some visualization
; 252 bytes -- re-arrange decode code
d2:
d4:
;===================
; music Player Setup
@ -37,26 +24,14 @@ tracker_song = peasant_song
jsr SETGR ; enable lo-res graphics
cli ; enable music
game_loop:
; typically A=0, X=FF, Y=0 here
; play a frame of music
.include "play_frame.s"
.include "ay3_write_regs.s"
jmp game_loop
; delay 20Hz, or 1/20s = 50ms
lda #140
jsr WAIT
lda #140
jsr WAIT
lda #140
jsr WAIT
beq game_loop
.include "interrupt_handler.s"
.include "mockingboard_constants.s"
; music
.include "mA2E_4.s"

View File

@ -0,0 +1,68 @@
;================================
;================================
; mockingboard interrupt handler
;================================
;================================
; On Apple II/6502 the interrupt handler jumps to address in 0xfffe
; This is in the ROM, which saves the registers
; on older IIe it saved A to $45 (which could mess with DISK II)
; newer IIe doesn't do that.
; It then calculates if it is a BRK or not (which trashes A)
; Then it sets up the stack like an interrupt and calls 0x3fe
; Note: the IIc is much more complicated
; its firmware tries to decode the proper source
; based on various things, including screen hole values
; we bypass that by switching out ROM and replacing the
; $fffe vector with this, but that does mean we have
; to be sure status flag and accumulator set properly
interrupt_handler:
php ; save status flags
cld ; clear decimal mode
pha ; save A ; 3
; A is saved in $45 by firmware
txa
pha ; save X
tya
pha ; save Y
inc $0404 ; debug (flashes char onscreen)
ay3_irq_handler:
bit MOCK_6522_T1CL ; clear 6522 interrupt by reading T1C-L ; 4
.include "play_frame.s"
.include "ay3_write_regs.s"
;=================================
; Finally done with this interrupt
;=================================
done_ay3_irq_handler:
pla
tay ; restore Y
pla
tax ; restore X
pla ; restore a ; 4
; on II+/IIe (but not IIc) we need to do this?
interrupt_smc:
lda $45 ; restore A
plp ; restore flags
rti ; return from interrupt ; 6
;============
; typical
; ???? cycles

View File

@ -0,0 +1,21 @@
init_addresses:
.byte <MOCK_6522_DDRB1,<MOCK_6522_DDRA1 ; set the data direction for all pins of PortA/PortB to be output
.byte <MOCK_6522_ACR,<MOCK_6522_IER ; Continuous interrupts, clear all interrupts
.byte <MOCK_6522_IFR,<MOCK_6522_IER ; enable interrupt on timer overflow
.byte <MOCK_6522_T1CL,<MOCK_6522_T1CH ; set oflow value, start counting
.byte <MOCK_6522_ORB1,<MOCK_6522_ORB1 ; reset ay-3-8910
; note, terminated by the $ff below
init_values:
.byte $ff,$ff ; set the data direction for all pins of PortA/PortB to be output
.byte $40,$7f
.byte $C0,$C0
.byte $e7,$4f ; c7ce / 1.023e6 = .050s, 20Hz
.byte MOCK_AY_RESET,MOCK_AY_INACTIVE
; c7ce / 1.023e6 = .050s, 20Hz
; 9c40 / 1.023e6 = .040s, 25Hz
; 4fe7 / 1.023e6 = .020s, 50Hz
; 411a / 1.023e6 = .016s, 60Hz

View File

@ -66,12 +66,54 @@ mockingboard_init:
; Reset Left AY-3-8910
;===========================
ldx #$FF
stx MOCK_6522_DDRB1
stx MOCK_6522_DDRA1
; ldx #$FF
; stx MOCK_6522_DDRB1
; stx MOCK_6522_DDRA1
inx ; #MOCK_AY_RESET $0
stx MOCK_6522_ORB1
ldx #MOCK_AY_INACTIVE ; $4
stx MOCK_6522_ORB1
; inx ; #MOCK_AY_RESET $0
; stx MOCK_6522_ORB1
; ldx #MOCK_AY_INACTIVE ; $4
; stx MOCK_6522_ORB1
; sei ; disable interrupts, is this necessary?
;=========================
; Setup Interrupt Handler
;=========================
; NOTE: we don't support IIc as it's a hack
; traditionally Mockingboard on IIc was rare
;========================
; set up interrupt
; Vector address goes to 0x3fe/0x3ff
; can save 10 bytes if we load in memory so this
; is in the right place automatically
lda #<interrupt_handler ; 2
sta $03fe ; 3
lda #>interrupt_handler ; 2
sta $03ff ; 3
;=========
; 10
;=========================
; Initialize the 6522s
; Reset Left AY-3-8910
;===========================
; entries=10
; 14 + 2*entries = 34 bytes
; assume Y=0 on entry?
ldy #0 ; 2
init_it_loop:
lda init_values,Y ; 3
ldx init_addresses,Y ; 3
bmi doneit ; 2
iny ; 1
sta $c400,X ; 3
bne init_it_loop ; 2
doneit:

View File

@ -3,6 +3,15 @@ play_frame:
;============================
; see if still counting down
lda SONG_COUNTDOWN
; rotate through channel A volume
tya
and #$7
tay
lda channel_a_volume,Y
sta AY_REGS+8
lda SONG_COUNTDOWN
bpl done_update_song
@ -17,9 +26,8 @@ set_notes_loop:
;==================
; see if hit end
; this song only 16 notes so valid notes always positive
; cmp #$80
bpl not_end
cmp #$ff
bne not_end
;====================================
; if at end, loop back to beginning
@ -30,14 +38,15 @@ set_notes_loop:
not_end:
; NNNNNNEC -- c=channel, e=end, n=note
pha ; save note
and #1
tax
ldy #$0E
sty AY_REGS+8,X ; $08 set volume A,B
; tax
; ldy #$0E
; sty AY_REGS+8,X ; $08 set volume A,B
asl
tax ; put channel offset in X
@ -46,6 +55,9 @@ not_end:
pla ; restore note
tay
and #$2
asl
asl
asl
sta SONG_COUNTDOWN ; always 2 long?
tya
@ -76,3 +88,9 @@ blah_urgh:
done_update_song:
dec SONG_COUNTDOWN
bmi set_notes_loop
bpl skip_data
channel_a_volume:
.byte 14,14,14,14,11,11,10,10
skip_data: