This is 16bit ports. I must find manual. But you can see all ports on SID PLAYER source code:
http://simonowen.com/sam/sidplay/
See in schematic:
8bit port #D4
and A8-A12 + A15 select adress for SID chip.
This port is unusable on real ZX Spectrums (collision wih port FE and 7FFD,etc...) but complette schematic and port decoder can be modified (integrated to one CPLD)
SOURCE CODE OF SIDPLAYER:
Код:; 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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

