Děkuju za další lekci. Zkouším si to psát po svém, neřeším tolik jestli ušetřím pár byte, ale preferuju abych to měl přehledný. Mám rád když je oddělený testování klavesnice od akcí, kterou má stisk klávesy vyvolat, takže jsem použil podobně jako minule (děkuji ".DW" za připomínky a rady, už jsem si opravil chyby co jsem tam měl) podprogramy "vpravo", "vlevo", "nahoru", "dolu".
Chtěl jsem tam taky mít dorazy na kraje obrazovky. První co mne napadlo mít v DE souřadnice Y,X a před každou změnou atributu vypočítat adresu atributu do HL.
att_adr: ;vypocet adresy atributu 32*D+E
push bc
ld h,0
ld l,d ;Y
add hl,hl ;Y*2
add hl,hl ;Y*4
add hl,hl ;Y*8
add hl,hl ;Y*16
add hl,hl ;Y*32
ld bc, ATTRIBUTE_ADR
add hl,bc ;ADR+32*Y
ld b,0
ld c,e ;X
add hl,bc ;ADR+32*Y+X
pop bc
ret
Funguje to, nevím jestli by to šlo napsat elegantněji (na nic lepšího jsem zatím nepřišel), ale přijde mi to dost brutální dělat po každé takovýhle výpočet.
Druhý nápad byl tedy, že budu při pohybu současně přičítat/odčítat 1 v D/E a zároveň modifikovat HL (trik s přičítáním -32 mne napadl taky hned - na atmelu zas chybí instrukce pro přičtení konstanty, tak se musí odečítat záporná hodnota). Je to sice kratší, ale zas se mi moc nelíbí, že musím současně aktualizovat dvoje souřadnice.
Verze pro Sinclair / Interface 2:
ENTRY_POINT equ $8000
ROM_OPEN_CHANNEL equ $1601
ATTRIBUTE_ADR equ $5800
ROM_CLS equ $0DAF
X0 equ 15
Y0 equ 10
XMIN equ 0
XMAX equ 31
YMIN equ 0
YMAX equ 23
KB_R0 equ $fe
KB_R1 equ $fd
KB_R2 equ $fb
KB_R3 equ $f7
KB_R4 equ $ef
KB_R5 equ $df
KB_R6 equ $bf
KB_R7 equ $7f
Color0 equ $38
Color1 equ $48
Color2 equ $50
INIPOS equ ATTRIBUTE_ADR+32*Y0+X0
;-------------------------------------------------------------------------------
CH_ATTR macro attr
ld (hl), attr
endm
KEYB macro port
ld c, $fe ;adresa portu
ld b, port ;adresa radku
in a, (c) ;vlastní čtení z portu (5 bitů)
endm
;-------------------------------------------------------------------------------
org ENTRY_POINT
start: call ROM_CLS
ld d,Y0
ld e,X0
ld hl,INIPOS
CH_ATTR Color1
;-------------------------------------------------------------------------------
main: call delay
KEYB KB_R3
rra ;1
call nc,vlevo
rra ;2
call nc,dolu
rra ;3
call nc,nahoru
rra ;4
call nc,vpravo
rra ;5
call nc,palba
call c,klid
jp main
;-------------------------------------------------------------------------------
vpravo: push AF
CH_ATTR Color0
ld a,e
cp XMAX
jr Z,vp0
inc e
inc hl
vp0: CH_ATTR Color1
pop AF
ret
;-------------------------------------------------------------------------------
vlevo: push AF
CH_ATTR Color0
ld a,e
cp XMIN
jr Z,vl0
dec e
dec hl
vl0: CH_ATTR Color1
pop AF
ret
;-------------------------------------------------------------------------------
dolu: push AF
CH_ATTR Color0
ld a,d
cp YMAX
jr Z,do0
inc d
ld bc,32
add hl,bc
do0: CH_ATTR Color1
pop AF
ret
;-------------------------------------------------------------------------------
nahoru: push AF
CH_ATTR Color0
ld a,d
cp YMIN
jr Z,na0
dec d
ld bc,-32
add hl,bc
na0: CH_ATTR Color1
pop AF
ret
;-------------------------------------------------------------------------------
palba: push AF
CH_ATTR Color2
pop AF
ret
;-------------------------------------------------------------------------------
klid: push AF
CH_ATTR Color1
pop AF
ret
;-------------------------------------------------------------------------------
delay: push bc ;zpozdeni
push de
ld d,60
ld e,0
d01: dec e
jr nz, d01
dec d
jr nz, d01
pop de
pop bc
ret
end ENTRY_POINT
Hned jak jsem to tu večer dopsal, vypnul jsem počítač a v koupelně mne napadlo jak to udělt líp: pro test pravého/levého okraje by mělo stačit testovat dolních 5 bitů L jestli jsou 00000/11111. Pro horní okraj musí být HL menší než ATTRIBUTE_ADR+32 a pro dolní okraj větší než ATTRIBUTE_ADR+23*32 (trochu se budu muset "poprat" s 16b porovnáváním). Dál mám v hlavě verzi pro dva hráče. Odpoledne až budu doma z práce otestuju.
Mám další otázku: jak je to s kompatibilitou 8080 - Z80 - 8086?
Vím že programy pro 8080 bez problému fungují i na Z80 (před časem jsem četl články od NOSTALCOMPa a ten dělal PMI 80 na univerzálních deskách, procesorovou pak udělal jak s 8080 tak s 8085 a i s Z80 a v sw změnil jedinou věc a to nápis po startu z PMI80 na PMI85 či PMIZ8). Co se týká assembleru tak předpokládám, že existuje translátor který dokáže ze zkratek 8080 udělat zkratky pro Z80.
8086 by měla být kopatibilní na úrovni zdrojového kodu, úplně jsem to nezkoumal, ale myslím že pro každou instrukci 8080 se najde ekvivalent pro 8086 (jen nevyužiju potenciál 16b procesoru).
Jak to je mezi Z80 a 8086?
Tak jsem si "pohrál" a tady je výsledek pro dva hráče. Dorazy testuju přímo v HL. No a protože jsou hráči dva, jsou jejich souřadnice primárně uloženy v proměnných HracA_XY a HracB_XY.
ENTRY_POINT equ $8000
ROM_OPEN_CHANNEL equ $1601
ATTRIBUTE_ADR equ $5800
ROM_CLS equ $0DAF
;-------------------------------------------------------------------------------
X0A equ 10 ;pocatecni souradnice
Y0A equ 10
X0B equ 20
Y0B equ 10
XMIN equ 0 ;meze
XMAX equ 31
YMIN equ ATTRIBUTE_ADR
YMAX equ ATTRIBUTE_ADR+23*32
KB_R0 equ $fe ;radky klavesnice
KB_R1 equ $fd
KB_R2 equ $fb
KB_R3 equ $f7
KB_R4 equ $ef
KB_R5 equ $df
KB_R6 equ $bf
KB_R7 equ $7f
Color0 equ $38 ;bila
Color1A equ $48 ;modra
Color2A equ $58 ;magenta
Color1B equ $60 ;zelena
Color2B equ $70 ;zluta
Color3 equ $50 ;cervena
INIPOS_A equ ATTRIBUTE_ADR+32*Y0A+X0A
INIPOS_B equ ATTRIBUTE_ADR+32*Y0B+X0B
;-------------------------------------------------------------------------------
CH_ATTR macro attr
ld (hl), attr
endm
KEYB macro port
ld c, $fe ;adresa portu
ld b, port ;adresa radku
in a, (c) ;vlastní čtení z portu (5 bitů)
endm
LOAD_HracXY macro ;nacteni pozice hrace z pameti do HL
ld l,(IX)
ld h,(IX+1)
endm
STORE_HracXY macro ;ulozeni pozice hrace z HL do pameti
ld (IX),l
ld (IX+1),h
endm
;-------------------------------------------------------------------------------
org ENTRY_POINT
start: call ROM_CLS ;vymazani obrazovky
ld ix,HracA_XY ;pocatecni zobrazeni hrace A
LOAD_HracXY
CH_ATTR Color1A
ld ix,HracB_XY ;pocatecni zobrazeni hrace B
LOAD_HracXY
CH_ATTR Color1B
;-------------------------------------------------------------------------------
main: call delay ;zpozdeni
ld ix,HracA_XY ;adresa pozice hrace A
KEYB KB_R3 ;test joysticku A
ld e,Color1A ;barva hrace A
rra ;1
call nc,vlevo
rra ;2
call nc,dolu
rra ;3
call nc,nahoru
rra ;4
call nc,vpravo
rra ;5
ld e,Color2A ;barva pri strelbe
call nc,palba
ld e,Color1A ;barva hrace A
call c,klid
ld ix,HracB_XY ;adresa pozice hrace B
KEYB KB_R4 ;test joysticku B
ld e,Color1B ;barva hrace B
rla
rla
rla
rla ;6
call nc,vlevo
rla ;7
call nc,dolu
rla ;8
call nc,nahoru
rla ;9
call nc,vpravo
rla ;0
ld e,Color2B ;barva pri strelbe
call nc,palba
ld e,Color1B ;barva hrace B
call c,klid
call kolize ;test kolize hracu
jp main ;hlavni cyklus
;-------------------------------------------------------------------------------
vpravo: push AF
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR Color0 ;barva pozadi
ld a,l ;test okraje
cpl
and 0x1F ;poslednich 5 bitu 11111
jr Z,vp0 ;nebude zmena pozice
inc hl ;nova pozice
vp0: CH_ATTR e ;barva hrace
STORE_HracXY ;ulozeni pozice hrace
pop AF
ret
;-------------------------------------------------------------------------------
vlevo: push AF
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR Color0 ;barva pozadi
ld a,l ;test okraje
and 0x1F ;poslednich 5 bitu 00000
jr Z,vl0 ;nebude zmena pozice
dec hl ;nova pozice
vl0: CH_ATTR e ;barva hrace
STORE_HracXY ;ulozeni pozice hrace
pop AF
ret
;-------------------------------------------------------------------------------
dolu: push AF
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR Color0 ;barva pozadi
push HL ;zalohovani pozice
ld a,l
and 0xE0 ;nulovani poslednich 5 bitu
ld l,a
ld bc,YMAX ;nastaveni maxima
sbc hl,bc ;otestovani hodnoty
pop HL
jr Z,do0 ;nebude zmena pozice
ld bc,32 ;nova pozice
add hl,bc
do0: CH_ATTR e ;barva hrace
STORE_HracXY ;ulozeni pozice hrace
pop AF
ret
;-------------------------------------------------------------------------------
nahoru: push AF
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR Color0 ;barva pozadi
push HL ;zalohovani pozice
ld a,l
and 0xE0 ;nulovani poslednich 5 bitu
ld l,a
ld bc,YMIN ;nastaveni maxima
sbc hl,bc ;otestovani hodnoty
pop HL
jr Z,na0 ;nebude zmena pozice
ld bc,-32 ;nova pozice
add hl,bc
na0: CH_ATTR e ;barva hrace
STORE_HracXY ;ulozeni pozice hrace
pop AF
ret
;-------------------------------------------------------------------------------
palba: push AF ;zmena barvy pri strelbe
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR e
pop AF
ret
;-------------------------------------------------------------------------------
klid: push AF ;zmena barvy kdyz se nestrili
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR e
pop AF
ret
;-------------------------------------------------------------------------------
kolize: push AF
ld ix,HracA_XY
LOAD_HracXY ;nacteni pozice hrace A
ld b,h ;kopie do BC
ld c,l
ld ix,HracB_XY
LOAD_HracXY ;nacteni pozice hrace B
or a ;nulovani cary
sbc hl,bc ;porovnani
jr nz,ko0 ;neni kolize
LOAD_HracXY
CH_ATTR Color3 ;nastaveni barvy kolize
ko0: pop AF
ret
;-------------------------------------------------------------------------------
delay: push bc ;zpozdeni
push de
ld d,60
ld e,0
d01: dec e
jr nz, d01
dec d
jr nz, d01
pop de
pop bc
ret
;-------------------------------------------------------------------------------
HracA_XY: dw INIPOS_A ;pozice hrace A v pameti
HracB_XY: dw INIPOS_B ;pozice hrace B v pameti
end ENTRY_POINT
ENTRY_POINT equ $8000
ROM_OPEN_CHANNEL equ $1601
ATTRIBUTE_ADR equ $5800
ROM_CLS equ $0DAF
;-------------------------------------------------------------------------------
X0A equ 10 ;pocatecni souradnice
Y0A equ 10
X0B equ 20
Y0B equ 10
XMIN equ 0 ;meze
XMAX equ 31
YMIN equ ATTRIBUTE_ADR
YMAX equ ATTRIBUTE_ADR+23*32
KB_R0 equ $fe ;radky klavesnice
KB_R1 equ $fd
KB_R2 equ $fb
KB_R3 equ $f7
KB_R4 equ $ef
KB_R5 equ $df
KB_R6 equ $bf
KB_R7 equ $7f
Color0 equ $38 ;bila
Color1A equ $48 ;modra
Color2A equ $58 ;magenta
Color1B equ $60 ;zelena
Color2B equ $70 ;zluta
Color3 equ $50 ;cervena
INIPOS_A equ ATTRIBUTE_ADR+32*Y0A+X0A
INIPOS_B equ ATTRIBUTE_ADR+32*Y0B+X0B
;-------------------------------------------------------------------------------
CH_ATTR macro attr
ld (hl), attr
endm
KEYB macro port
ld c, $fe ;adresa portu
ld b, port ;adresa radku
in a, (c) ;vlastní čtení z portu (5 bitů)
endm
LOAD_HracXY macro ;nacteni pozice hrace z pameti do HL
ld l,(IX)
ld h,(IX+1)
endm
STORE_HracXY macro ;ulozeni pozice hrace z HL do pameti
ld (IX),l
ld (IX+1),h
endm
;-------------------------------------------------------------------------------
org ENTRY_POINT
start: call ROM_CLS ;vymazani obrazovky
ld ix,HracA_XY ;pocatecni zobrazeni hrace A
LOAD_HracXY
CH_ATTR Color1A
ld ix,HracB_XY ;pocatecni zobrazeni hrace B
LOAD_HracXY
CH_ATTR Color1B
;-------------------------------------------------------------------------------
main: call delay ;zpozdeni
ld ix,HracA_XY ;adresa pozice hrace A
KEYB KB_R3 ;test joysticku A
ld e,Color1A ;barva hrace A
rra ;1
call nc,vlevo
rra ;2
call nc,dolu
rra ;3
call nc,nahoru
rra ;4
call nc,vpravo
rra ;5
ld e,Color2A ;barva pri strelbe
call nc,palba
ld e,Color1A ;barva hrace A
call c,klid
ld ix,HracB_XY ;adresa pozice hrace B
KEYB KB_R4 ;test joysticku B
ld e,Color1B ;barva hrace B
rla
rla
rla
rla ;6
call nc,vlevo
rla ;7
call nc,dolu
rla ;8
call nc,nahoru
rla ;9
call nc,vpravo
rla ;0
ld e,Color2B ;barva pri strelbe
call nc,palba
ld e,Color1B ;barva hrace B
call c,klid
call kolize ;test kolize hracu
jp main ;hlavni cyklus
;-------------------------------------------------------------------------------
vpravo: push AF
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR Color0 ;barva pozadi
ld a,l ;test okraje
cpl
and 0x1F ;poslednich 5 bitu 11111
jr Z,vp0 ;nebude zmena pozice
inc hl ;nova pozice
vp0: CH_ATTR e ;barva hrace
STORE_HracXY ;ulozeni pozice hrace
pop AF
ret
;-------------------------------------------------------------------------------
vlevo: push AF
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR Color0 ;barva pozadi
ld a,l ;test okraje
and 0x1F ;poslednich 5 bitu 00000
jr Z,vl0 ;nebude zmena pozice
dec hl ;nova pozice
vl0: CH_ATTR e ;barva hrace
STORE_HracXY ;ulozeni pozice hrace
pop AF
ret
;-------------------------------------------------------------------------------
dolu: push AF
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR Color0 ;barva pozadi
push HL ;zalohovani pozice
ld a,l
and 0xE0 ;nulovani poslednich 5 bitu
ld l,a
ld bc,YMAX ;nastaveni maxima
sbc hl,bc ;otestovani hodnoty
pop HL
jr Z,do0 ;nebude zmena pozice
ld bc,32 ;nova pozice
add hl,bc
do0: CH_ATTR e ;barva hrace
STORE_HracXY ;ulozeni pozice hrace
pop AF
ret
;-------------------------------------------------------------------------------
nahoru: push AF
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR Color0 ;barva pozadi
push HL ;zalohovani pozice
ld a,l
and 0xE0 ;nulovani poslednich 5 bitu
ld l,a
ld bc,YMIN ;nastaveni maxima
sbc hl,bc ;otestovani hodnoty
pop HL
jr Z,na0 ;nebude zmena pozice
ld bc,-32 ;nova pozice
add hl,bc
na0: CH_ATTR e ;barva hrace
STORE_HracXY ;ulozeni pozice hrace
pop AF
ret
;-------------------------------------------------------------------------------
palba: push AF ;zmena barvy pri strelbe
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR e
pop AF
ret
;-------------------------------------------------------------------------------
klid: push AF ;zmena barvy kdyz se nestrili
LOAD_HracXY ;nacteni pozice hrace
CH_ATTR e
pop AF
ret
;-------------------------------------------------------------------------------
kolize: push AF
ld ix,HracA_XY
LOAD_HracXY ;nacteni pozice hrace A
ld b,h ;kopie do BC
ld c,l
ld ix,HracB_XY
LOAD_HracXY ;nacteni pozice hrace B
or a ;nulovani cary
sbc hl,bc ;porovnani
jr nz,ko0 ;neni kolize
LOAD_HracXY
CH_ATTR Color3 ;nastaveni barvy kolize
ko0: pop AF
ret
;-------------------------------------------------------------------------------
delay: push bc ;zpozdeni
push de
ld d,60
ld e,0
d01: dec e
jr nz, d01
dec d
jr nz, d01
pop de
pop bc
ret
;-------------------------------------------------------------------------------
HracA_XY: dw INIPOS_A ;pozice hrace A v pameti
HracB_XY: dw INIPOS_B ;pozice hrace B v pameti
end ENTRY_POINT
A pro dva hrace to jde napsat i takto:
ENTRY_POINT equ $8000
ATTRIBUTE_ADR equ $5800
ROM_CLS equ $0DAF
X0A equ 10 ;pocatecni souradnice
Y0A equ 10
X0B equ 20
Y0B equ 10
KB_R0 equ $fefe ;BC=0xFEFE ->A=...VCXZc
KB_R1 equ $fdfe ;BC=0xFDFE ->A=...GFDSA
KB_R2 equ $fbfe ;BC=0xFBFE ->A=...TREWQ
KB_R3 equ $f7fe ;BC=0xF7FE ->A=...54321
KB_R4 equ $effe ;BC=0xEFFE ->A=...67890
KB_R5 equ $dffe ;BC=0xDFFE ->A=...YUIOP
KB_R6 equ $bffe ;BC=0xBFFE ->A=...HJKLe
KB_R7 equ $7ffe ;BC=0x7FFE ->A=...BNMs_
Color0 equ $38 ;bila
Color1A equ $48 ;modra
Color2A equ $58 ;magenta
Color1B equ $60 ;zelena
Color2B equ $70 ;zluta
Color3 equ $50 ;cervena
INIPOS_A equ ATTRIBUTE_ADR+32*Y0A+X0A
INIPOS_B equ ATTRIBUTE_ADR+32*Y0B+X0B
;-------------------------------------------------------------------------------
KEYB macro port
ld bc, 256*port+$fe ;adresa radku & adresa portu
endm
;-------------------------------------------------------------------------------
org ENTRY_POINT
start: call ROM_CLS
ld hl,INIPOS_B
ld (hl),Color1B
ex de,hl
ld hl,INIPOS_A
ld (hl),Color1A
;-------------------------------------------------------------------------------
main: halt
halt
ld bc, KB_R3
in a, (c) ;vlastní čtení z portu (5 bitů)
call move
ld a,Color1A ;klid
jr c,$+4
ld a,Color2A ;palba
ld (hl),a ;1:7
ex de,hl
ld bc, KB_R4
in a, (c) ;vlastní čtení z portu (5 bitů)
ld c,a
ld b,5
invert_loop:
rr c
adc a,a
djnz invert_loop
call move
ld a,Color1B ;klid
jr c,$+4
ld a,Color2B ;palba
ld (hl),a ;1:7
ex de,hl
or a
sbc hl,de
add hl,de
jr nz,$+4
ld (hl),Color3 ; kolize
jp main
;-------------------------------------------------------------------------------
; in:
; A=read port
; HL= ATTRIBUTE_ADR
move:
push hl
ld bc, 0x0020 ;3:10 = 32
vlevo:
rra ;1
jr c,vpravo
if 1
; 31x 43 taktu, 1x 44 taktu
push af ;1:11
ld a,%00011111 ;2:7
and l ;1:4
jr z,$+3 ;2:7/12
dec l ;1:4
pop af ;1:10
else
; 50% 24 taktu, 3% 43 taktu, 47% 42 taktu
dec l ;1:4 ...0 0000-1?
bit 4,l ;2:8
jr z,vpravo ;2:7/12
inc l ;1:4 ...1 ....+1?
bit 4,l ;2:8
jr z,vpravo ;2:7/12
dec l ;1:4
endif
vpravo:
rra ;4
jr c,dolu
if 1
push af ;1:11
if 1
; o trochu rychlejsi, protoze 31x 47 taktu, 1x48 taktu
ld a,%00011111 ;2:7
inc l ;1:4
and l ;1:4
jr nz,$+3 ;2:7/12
dec l ;1:4
else
; o trochu pomalejsi, protoze 31x 48 taktu, 1x47 taktu
ld a,%11100000 ;2:7
or l ;1:4
inc a ;1:4
jr z,$+3 ;2:7/12
inc l ;1:4
endif
pop af ;1:10
else
; 50% 24 taktu, 3% 43 taktu, 47% 42 taktu
inc l ;1:4 ...1 1111+1?
bit 4,l ;2:8
jr nz,dolu ;2:7/12
dec l ;1:4 ...0 ....-1?
bit 4,l ;2:8
jr nz,dolu ;2:7/12
inc l ;1:4
endif
dolu:
rra ;2
jr c,nahoru
; last row 0x5AE0..0x5AFF => 0101 1010 111. ....
add hl,bc ;1:11 fail:0x5B ...1011; ok:0x58 ...1000,0x59 ...1001,0x5A ...1010
inc h ;1:4
bit 2,h ;2:8
jr z,nahoru-1 ;2:7/12
sbc hl,bc ;2:15
dec h ;1:4
nahoru:
rra ;3
jr c,palba
; first row 0x5800..0x581F => 0101 1000 000. ....
sbc hl,bc ;2:15 no carry! fail:0x57 ...0(1)11; ok:0x58 ...1(0)00,0x59 ...1(0)01,0x5A ...1(0)10
bit 2,h ;2:8
jr z,palba ;2:7/12
add hl,bc ;1:11
palba:
rra ;5
ex (sp),hl ;1:19
ld (hl),Color0 ;2:10
pop hl ;1:11
ret
;-------------------------------------------------------------------------------
end ENTRY_POINT
Je to 122 bajtu z puvodnich 313. Opet tam mas tu chybu ze mas jinak poprehazene klavesy a pohyby.
A tady jsem se sam spalil! Protoze jsem jen prohodil u druheho hrace puvodne jen radek ktery se cte a zbytek nechal shodny jenze...
V clanku to neni zdurazneno ale na te strance:
https://worldofspectrum.org/faq/reference/peripherals.htm
je uvedeno ze:
Sinclair
The 'left' Sinclair joystick maps the joystick directions and the fire button to the 1 (left), 2 (right), 3 (down), 4 (up) and 5 (fire) keys on the ZX Spectrum keyboard, and can thus be read via port 0xf7fe; see the Port 0xfe section for full details. For any of the joystick interfaces which map to keys, any game offering the appropriate form of joystick control can instead be played with the listed keys.
The 'right' Sinclair joystick maps to keys 6 (left), 7 (right), 8 (down), 9 (up) and 0 (fire) and can therefore be read via port 0xeffe.
Vypada to logicky az do chvile kdy zjistis, ze se ti ty bity mapuji takto
KB_R3 equ $f7fe ;BC=0xF7FE ->A=...54321 KB_R4 equ $effe ;BC=0xEFFE ->A=...67890
Je to inverzne! Tak jsem to jen narychlo ohackoval ze prohazuji 5 bitu nez volam rutinu co resi druheho hrace.
Tady mas hned 2 varianty kdy se pouziva pro drzeni souradnic jen adresa
Prvni je delsi 91 bajtu a pouziva 8 bitovou aritmetiku. Plus prohazuje puvodni a nove souradnice pres "ex DE,HL"
ENTRY_POINT equ $8000
ATTRIBUTE_ADR equ $5800
ROM_CLS equ $0DAF
X0 equ 15
Y0 equ 10
KB_R0 equ $fe ;BC=0xFEFE ->A=...VCXZc
KB_R1 equ $fd ;BC=0xFDFE ->A=...GFDSA
KB_R2 equ $fb ;BC=0xFBFE ->A=...TREWQ
KB_R3 equ $f7 ;BC=0xF7FE ->A=...54321
KB_R4 equ $ef ;BC=0xEFFE ->A=...67890
KB_R5 equ $df ;BC=0xDFFE ->A=...YUIOP
KB_R6 equ $bf ;BC=0xBFFE ->A=...HJKLe
KB_R7 equ $7f ;BC=0x7FFE ->A=...BNMs_
Color0 equ $38
Color1 equ $48
Color2 equ $50
INIPOS equ ATTRIBUTE_ADR+32*Y0+X0
;-------------------------------------------------------------------------------
KEYB macro port
ld bc, 256*port+$fe ;adresa radku & adresa portu
in a, (c) ;vlastní čtení z portu (5 bitů)
endm
;-------------------------------------------------------------------------------
org ENTRY_POINT
start: call ROM_CLS
ld hl,INIPOS
ld (hl),Color1
;-------------------------------------------------------------------------------
main: halt
halt
KEYB KB_R3
ld d, h
ld e, l
vlevo:
rra ;1
ld c,a
jr c,vpravo
ld a,%00011111
and e
jr z,vpravo
dec e
vpravo:
rr c ;4
jr c,dolu
ld a,%11100000
or e
inc a
jr z,dolu
inc e
dolu:
rr c ;2
jr c,nahoru
; last row 0x5AE0..0x5AFF => 0101 1010 111. ....
ld a,%00011111 ;2:7
or e ;1:4
xor d ;1:4
xor ~0x5A ;2:7
jr z, nahoru ;2:7/12
ld a,%00100000 ;2:7
add a,e ;1:4
ld e,a ;1:4
adc a,d ;1:4
sub e ;1:4
ld d,a ;1:4
nahoru:
rr c ;3
jr c,palba
; first row 0x5800..0x581F => 0101 1000 000. ....
ld a,%11100000 ;2:7
and e ;1:4
xor d ;1:4
xor 0x58 ;2:7
jr z, palba ;2:7/12
ld a,e ;1:4
sub %00100000 ;2:7
ld e,a ;1:4
jr nc,palba ;2:7/12
dec d ;1:4
palba:
rr c ;5
ld a,Color1 ;klid
jr c,klid
ld a,Color2 ;palba
klid:
ld (hl),Color0
ld (de),a
ex DE,HL
jp main
;-------------------------------------------------------------------------------
end ENTRY_POINT
Druha kratsi (79 bajtu) varianta to dela pres 16 bitovou aritmetiku a kdyz to je kratsi tak 8 bitovou aritmetiku (viz "if 1"). Plus souradnice drzi jen v HL a prohazuje si to se zasobnikem.
ENTRY_POINT equ $8000
ATTRIBUTE_ADR equ $5800
ROM_CLS equ $0DAF
X0 equ 15
Y0 equ 10
KB_R0 equ $fe ;BC=0xFEFE ->A=...VCXZc
KB_R1 equ $fd ;BC=0xFDFE ->A=...GFDSA
KB_R2 equ $fb ;BC=0xFBFE ->A=...TREWQ
KB_R3 equ $f7 ;BC=0xF7FE ->A=...54321
KB_R4 equ $ef ;BC=0xEFFE ->A=...67890
KB_R5 equ $df ;BC=0xDFFE ->A=...YUIOP
KB_R6 equ $bf ;BC=0xBFFE ->A=...HJKLe
KB_R7 equ $7f ;BC=0x7FFE ->A=...BNMs_
Color0 equ $38
Color1 equ $48
Color2 equ $50
INIPOS equ ATTRIBUTE_ADR+32*Y0+X0
;-------------------------------------------------------------------------------
KEYB macro port
ld bc, 256*port+$fe ;adresa radku & adresa portu
in a, (c) ;vlastní čtení z portu (5 bitů)
endm
;-------------------------------------------------------------------------------
org ENTRY_POINT
start: call ROM_CLS
ld hl,INIPOS
ld (hl),Color1
;-------------------------------------------------------------------------------
main: halt
halt
KEYB KB_R3
push hl
ld bc, 0x0020 ;3:10 = 32
vlevo:
rra ;1
jr c,vpravo
if 1
; 31x 43 taktu, 1x 44 taktu
push af ;1:11
ld a,%00011111 ;2:7
and l ;1:4
jr z,$+3 ;2:7/12
dec l ;1:4
pop af ;1:10
else
; 50% 24 taktu, 3% 43 taktu, 47% 42 taktu
dec l ;1:4 ...0 0000-1?
bit 4,l ;2:8
jr z,vpravo ;2:7/12
inc l ;1:4 ...1 ....+1?
bit 4,l ;2:8
jr z,vpravo ;2:7/12
dec l ;1:4
endif
vpravo:
rra ;4
jr c,dolu
if 1
push af ;1:11
if 1
; o trochu rychlejsi, protoze 31x 47 taktu, 1x48 taktu
ld a,%00011111 ;2:7
inc l ;1:4
and l ;1:4
jr nz,$+3 ;2:7/12
dec l ;1:4
else
; o trochu pomalejsi, protoze 31x 48 taktu, 1x47 taktu
ld a,%11100000 ;2:7
or l ;1:4
inc a ;1:4
jr z,$+3 ;2:7/12
inc l ;1:4
endif
pop af ;1:10
else
; 50% 24 taktu, 3% 43 taktu, 47% 42 taktu
inc l ;1:4 ...1 1111+1?
bit 4,l ;2:8
jr nz,dolu ;2:7/12
dec l ;1:4 ...0 ....-1?
bit 4,l ;2:8
jr nz,dolu ;2:7/12
inc l ;1:4
endif
dolu:
rra ;2
jr c,nahoru
; last row 0x5AE0..0x5AFF => 0101 1010 111. ....
add hl,bc ;1:11 fail:0x5B ...1011; ok:0x58 ...1000,0x59 ...1001,0x5A ...1010
inc h ;1:4
bit 2,h ;2:8
jr z,nahoru-1 ;2:7/12
sbc hl,bc ;2:15
dec h ;1:4
nahoru:
rra ;3
jr c,palba
; first row 0x5800..0x581F => 0101 1000 000. ....
sbc hl,bc ;2:15 no carry! fail:0x57 ...0(1)11; ok:0x58 ...1(0)00,0x59 ...1(0)01,0x5A ...1(0)10
bit 2,h ;2:8
jr z,palba ;2:7/12
add hl,bc ;1:11
palba:
rra ;5
ld a,Color1 ;klid
jr c,klid
ld a,Color2 ;palba
klid:
ex (sp),hl ;1:19
ld (hl),Color0 ;2:10
pop hl ;1:11
ld (hl),a ;1:7
jp main
;-------------------------------------------------------------------------------
end ENTRY_POINT
Mrkni se na stranky: https://worldofspectrum.org/faq/reference/peripherals.htm pod Sinclair mas napsane:
Sinclair
The 'left' Sinclair joystick maps the joystick directions and the fire button to the 1 (left), 2 (right), 3 (down), 4 (up) and 5 (fire) keys on the ZX Spectrum keyboard, and can thus be read via port 0xf7fe;
Ty pouzivas spatne rozlozeni.
Dale:
KEYB macro port
ld c, $fe ;adresa portu
ld b, port ;adresa radku
in a, (c) ;vlastní čtení z portu (5 bitů)
endm
Muzes zkratit:
KEYB macro port
ld bc, 256*port+$fe ;adresa radku a portu
in a, (c) ;vlastní čtení z portu (5 bitů)
endm
Dale:
att_adr: ;vypocet adresy atributu 32*D+E
push bc
ld h,0
ld l,d ;Y
add hl,hl ;Y*2
add hl,hl ;Y*4
add hl,hl ;Y*8
add hl,hl ;Y*16
add hl,hl ;Y*32
ld bc, ATTRIBUTE_ADR
add hl,bc ;ADR+32*Y
ld b,0
ld c,e ;X
add hl,bc ;ADR+32*Y+X
pop bc
ret
Bych asi resil jinak, prvne me trklo ze tam 2x pouzivas konstantu nuly, kdyz to preskladas tak podruhe muzes pouzit registr obsahujici nulu.
ALe po dalsim preskladani zjistis ze ADR=0x5800
takze ADR+X udelas kdyz misto spodnich 8 bitu tam das E
att_adr: ;vypocet adresy atributu 32*D+E
push bc
ld h,0
ld l,d ;Y
add hl,hl ;Y*2
add hl,hl ;Y*4
add hl,hl ;Y*8
add hl,hl ;Y*16
add hl,hl ;Y*32
ld b, high ATTRIBUTE_ADR
ld c,e ;X
add hl,bc ;ADR+32*Y+X
pop bc
ret
slo by to zrychlit kdyz 3x zamenis "add hl,hl ;1:11" za "add a,a;1:4" ale bude to stat 1 bajt navic:
att_adr: ;vypocet adresy atributu 32*D+E
push bc
ld a,d ;Y
add a,a ;Y*2 0..+2..46
add a,a ;Y*4 0..+4..92
add a,a ;Y*8 0..+8..184
ld h,0
ld l,a ;hl=8*Y
add hl,hl ;Y*16
add hl,hl ;Y*32
ld b, high ATTRIBUTE_ADR
ld c,e ;X
add hl,bc ;ADR+32*Y+X
pop bc
ret
A pro tu druhou variantu vlastne ani BC uz nepotrebujes a vyjde ti to rychleji pres 8 bitove scitani:
att_adr: ;vypocet adresy atributu 32*D+E
ld a,d ;Y
add a,a ;Y*2 0..+2..46
add a,a ;Y*4 0..+4..92
add a,a ;Y*8 0..+8..184
ld h,0
ld l,a ;hl=8*Y
add hl,hl ;Y*16
add hl,hl ;Y*32
ld a,l ;hl=8*Y
add a,e ;lo(Y*32+E)
ld l,a ;
ld a, high ATTRIBUTE_ADR
adc a,h
ld h,a ;
ret
A dalsi iterace je o bajt kratsi a jeste rychleji...:
att_adr: ;vypocet adresy atributu 32*D+E
ld a,d ;Y
add a,a ;Y*2 0..+2..46
add a,a ;Y*4 0..+4..92
add a,a ;Y*8 0..+8..184
ld h,0x58>>2 ;
ld l,a ;
add hl,hl ;ATTRIBUTE_ADR/2+Y*16
add hl,hl ;ATTRIBUTE_ADR+Y*32
ld a,l ;hl=8*Y
add a,e ;lo(Y*32+E)
ld l,a ;
adc a,h ;1:4
sub l ;1:4
ld h,a ;1:4
ret
...a jeste rychleji...:
att_adr: ;vypocet adresy atributu 32*D+E
ld a,d ;Y
add a,a ;Y*2 0..+2..46
add a,a ;Y*4 0..+4..92
add a,a ;Y*8 0..+8..184
ld h,0x58>>2 ;
ld l,a ;
add hl,hl ;ATTRIBUTE_ADR/2+Y*16
add hl,hl ;ATTRIBUTE_ADR+Y*32
ld a,l ;hl=8*Y
add a,e ;lo(Y*32+E)
ld l,a ;
jr nc,$+3 ;2:7/12
inc h ;1:4
ret
a nakonec jeste rychleji protoze je to ve funkci a s mene bajty:
...a jeste rychleji...:
att_adr: ;vypocet adresy atributu 32*D+E
ld a,d ;Y
add a,a ;Y*2 0..+2..46
add a,a ;Y*4 0..+4..92
add a,a ;Y*8 0..+8..184
ld h,0x58>>2 ;
ld l,a ;
add hl,hl ;ATTRIBUTE_ADR/2+Y*16
add hl,hl ;ATTRIBUTE_ADR+Y*32
ld a,l ;hl=8*Y
add a,e ;lo(Y*32+E)
ld l,a ;
ret nc ;1:5/11
inc h ;1:4
ret26. 5. 2023, 22:58 editováno autorem komentáře
Tahle procedura vypadá elegantně. Nemám tolik zkušeností s Z80 (a ani celkově s takhle brutální minimalizací kodu na jakémkoliv procesoru). Pořád tu objevuju další a další instrukce a třeba jsem nevěděl, že můžu použít direktivu high / low (přitom na AVR se požívají prakticky neustále). U těch ostatních programů po tvojí úpravě jsou místa kde se už ztrácím jak to vlastně funguje.
To rozložení kláves jsem si opravil (myslel jsem, že je to stejný jako u "kurzorovýho Joysticku"). Taky mne překvapilo, že ta druhá část je inverzně. V tom jak to mám napsaný bylo přeházení kláves jednoduchý, stačilo přeházet návěští u CALLů.