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 ret
26. 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ů.