Код:
; SID interface functions
sid_reset: ld hl,last_regs
ld bc,&00d4 ; SID base port is &D4
ld d,b ; write 0 to all registers
ld a,25 ; 25 registers to write
reset_loop: out (c),d ; write to register
ld (hl),d ; remember new value
inc hl
set 7,b
out (c),d ; effectively strobe write
res 7,b
inc b
cp b
jr nz,reset_loop ; loop until all reset
xor a
ld (last_regs+&04),a ; control for voice 1
ld (last_regs+&0b),a ; control for voice 2
ld (last_regs+&12),a ; control for voice 3
ret
sid_update: ex de,hl ; switch new values to DE
ld c,&d4 ; SID interface base port
ld hl,25 ; control 1 changes offset
add hl,de
ld a,(hl) ; fetch changes
and a
jr z,control2 ; skip if nothing changed
ld (hl),0 ; reset changes for next time
ld hl,&04 ; new register 4 offset
ld b,l ; SID register 4
add hl,de
xor (hl) ; toggle changed bits
out (c),a ; write intermediate value
ld (last_regs+&04),a ; update last reg value
set 7,b
out (c),a ; strobe
control2: ld hl,26 ; control 2 changes offset
add hl,de
ld a,(hl)
and a
jr z,control3 ; skip if no changes
ld (hl),0
ld hl,&0b
ld b,l ; SID register 11
add hl,de
xor (hl)
out (c),a
ld (last_regs+&0b),a
set 7,b
out (c),a
control3: ld hl,27 ; control 3 changes offset
add hl,de
ld a,(hl)
and a
jr z,control_done ; skip if no changes
ld (hl),0
ld hl,&12
ld b,l ; SID register 18
add hl,de
xor (hl)
out (c),a
ld (last_regs+&12),a
set 7,b
out (c),a
control_done: ld hl,last_regs ; previous register values
ld b,0 ; start with register 0
out_loop: ld a,(de) ; new register value
cp (hl) ; compare with previous value
jr z,sid_skip ; skip if no change
out (c),a ; write value
ld (hl),a ; store new value
set 7,b
out (c),a ; effectively strobe write
res 7,b
sid_skip: inc hl
inc de
inc b ; next register
ld a,b
cp 25 ; 25 registers to write
jr nz,out_loop ; loop until all updated
ld hl,7
add hl,de ; make up to a block of 32
ret
start_50Hz: equ 0
step_50Hz: equ 0
end_50Hz: equ 0
start_60Hz: equ 191 ; start on line 191
step_60Hz: equ 312/6 ; step back 52 lines
step5_60Hz: equ start_60Hz-(4*step_60Hz) ; in top border
end_60Hz: equ start_60Hz-(5*step_60Hz) ; frame int finish
start_100Hz: equ 88
step_100Hz: equ 0
end_100Hz: equ start_100Hz
; Set playback speed, using timer first then ntsc flag
set_speed: ld hl,(c64_cia_timer) ; C64 CIA#1 timer frequency
ld a,h
or l
jr nz,use_timer ; use if non-zero
ld a,(ntsc_tune) ; SID header said NTSC tune?
and a
jr nz,set_60hz ; use 60Hz for NTSC
set_50hz: ld h,start_50Hz
; ld l,end_50Hz
; ld a,step_50Hz
set_exit: ld (line_step1+1),a
ld (line_step2+1),a
ld a,h
ld (line_start+1),a
ld (line_num),a
ld a,l
ld (line_end+1),a
ld a,&ff
out (line),a ; disable line interrupts
ret
set_60hz: ld h,start_60Hz
ld l,end_60Hz
ld a,step_60hz
jr set_exit
set_100hz: ld h,start_100Hz
ld l,end_100Hz
ld a,step_100Hz
jr set_exit
; 985248.4Hz / HL = playback frequency in Hz
use_timer: ld a,h
cp &22 ; 110Hz (PAL)
jr c,bad_timer ; reject >100Hz
cp &2b ; 90Hz
jr c,set_100Hz ; use 100Hz for 90-110Hz
cp &3b ; 65Hz
jr c,bad_timer ; reject 65<freq<90hz
cp &45 ; 55Hz
jr c,set_60Hz ; use 60Hz for 55-65Hz
cp &56 ; 45Hz
jr c,set_50Hz ; use 50Hz for 45-55Hz
; reject <45Hz
bad_timer: pop hl ; junk return address
ld a,ret_timer ; unsupported frequency
ret
gap4: equ &dd00-$ ; error if previous code is
defs gap4 ; too big for available gap!
defs 16 ; CIA #2 (serial, NMI)
defs 32 ; small private stack
new_stack: equ $
blocks: defw 0 ; buffered block count
head: defw 0 ; head for recorded data
tail: defw 0 ; tail for playing data
init_addr: defw 0
play_addr: defw 0
play_song: defb 0
ntsc_tune: defb 0 ; non-zero for 60Hz tunes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;