Me to ukazuje u kapitoly 4 a 6 velikost programu o bajt vice.
Poznámka: velikost přeloženého strojového kódu klesla na 78 bajtů oproti původním 86 bajtům.
Viz ty vypisy:
8056:C9 RET 8057: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 8056
804E:C9 RET 804F: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 804E
Zacina to na nule.
Dalsi 4 bajty jde srazit prepsanim tech make add a sub:
add_to_hl MACRO value ld b, 0 ; 2:7 ld c, value ; 2:7 add hl, bc ; 1:11 ENDM sub_from_hl MACRO value ld b, 0 ; 2:7 ld c, value ; 2:7 or a ; 1:4 vynulovat carry sbc hl, bc ; 2:15 ENDM
add_to_hl MACRO value ld bc, value ; 3:10 add hl, bc ; 1:11 ENDM sub_from_hl MACRO value ld bc,-(value) ; 3:10 add hl, bc ; 1:11 ENDM
To divne -(value) je kvuli tomu kdyby se to volalo treba jako "sub_from_hl 16+16". Vyhrano ale nemame, protoze to jde jeste zkazit uvodnim minuskem, napriklad "sub_from_hl -2+34" se prelozi jako -36 -> pricte 36.
Jak se koukam na ten cely kod tak je tam vlastne chyba. Misto BC pro pricteni se melo radeji pouzivat DE. Protoze pri testu stisku klavesy "Q" uz cteme z portu 0x20 pripadne 0xE0.
A podle chytejsich lidi nez ja... (zdravim Busyho .) ) pouziti neceho jineho nez 0xFE muze delat kolize s pripojenymi dalsimi zarizenimi.
K te hadance pro kapitolu 9.
Poznámka: relativně jednoduchým přeskládáním kódu a modifikací instrukcí pro rotaci lze program nepatrně zkrátit i nepatrně urychlit. Přijdete na to, v jakém místě kódu?
V registru A mame po cteni z portu: A=???67890, kde misto cislic je 0 kdy je klavesa stisknuta a nebo 1 kdyz neni.
Nic me nenapada, spis mam pocit, ze jsi tam mel puvodne misto:
left_not_pressed: keypress KB_ROW_4_PORT ; test stisku klávesy 6,7,8 (joystick dolů, nahoru a doprava) rra ; třetí bit do příznaku carry rra rra jr c, right_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici right_not_pressed: rra ; čtvrtý bit do příznaku carry jr c, down_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici down_not_pressed: rra ; pátý bit do příznaku carry jr c, up_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici
Neco jako:
left_not_pressed: keypress KB_ROW_4_PORT ; test stisku klávesy 6,7,8 (joystick dolů, nahoru a doprava) bit 2,a ; 2:8 třetí (imho je to druhy bit a pocita se od nuly) bit do příznaku zero jr nz, right_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici inc hl ; posun doprava o jeden bajt changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici right_not_pressed: bit 3,a ; čtvrtý (imho je to treti bit a pocita se od nuly) bit do příznaku zero jr nz, down_not_pressed ; 2:8 přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici sub_from_hl 32 ; posun nahoru (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici down_not_pressed: and 0x10 ; 2:7 pátý (imho ctvrty) bit do příznaku zero jr nz, up_not_pressed ; přeskok dalších instrukcí, pokud klávesa není stisknuta changeAttribute ORIG_BLOCK ; smazat hráče na původní pozici add_to_hl 32 ; posun dolů (o 32 bajtů) changeAttribute RED_BLOCK ; vykreslit hráče na nové pozici
Takze ukazujes reseni hadanky.
...ale zkratit by to asi slo, kdyz se nebude resit prekresleni postavicky po kazdem pohybu (mysleno jako 2x pri sikmem posunu), ale az ve vysledku. Neco jako zmena do DE a na konci "ex HL,DE". Odpadne 6x changeAttribute kazda za 2 bajty. A potrebujeme 3 bajty na kopii do DE a prohozeni. Plus neco bude stat zmenit add_to_ a sub_to_ na 8 bitovou aritmetiku.
Kdyz nebudu pocitat Kempston, znamena to, ze ty dalsi interfajsy vlastne "oruji" nebo "anduji" stejne vodice, jako klavesnice? Myslim to tak, ze treba kdyz na klavesnici zmacknu 3 a nebo pouziju interface joystick ve stejnem smeru, tak to hra nepozna?
Ale mozna to spis vypada na "andovani" protoze inverzni logika - tj. stisk klavesy bude "rusit" ovladani joystickem a naopak, takze to (ASI) nejde pouzit soucasne, ze? (minimalne kvuli ghostingu)
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ů.
Upravil jsem ten kod na minimalisticky "Dyna Blaster". Kod trosku nabobtnal na 210 bajtu, ale uplne jsem to nehrotil s optimalizaci.
ENTRY_POINT equ $8000 ATTRIBUTE_ADR equ $5800 ROM_CLS equ $0DAF X0A equ 32/2-6 ;pocatecni souradnice Y0A equ 23/2 X0B equ 32/2+5 Y0B equ 23/2 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_ player_a equ 3 bomb equ 4 player_b equ 5 timer equ 6 INIPOS_A equ ATTRIBUTE_ADR+32*Y0A+X0A INIPOS_B equ ATTRIBUTE_ADR+32*Y0B+X0B ;------------------------------------------------------------------------------- org ENTRY_POINT ld A, %00101000 ; 2:7 start: rra ; 1:4 rra ; 1:4 rra ; 1:4 out (254),A ; 2:11 zx_border 0=blk,1=blu,2=red,3=mag,4=grn,5=cyn,6=yel,7=wht xor a ld (0x5C8D),a call ROM_CLS ld hl,INIPOS_B ex de,hl ld hl,INIPOS_A ;------------------------------------------------------------------------------- main: ld bc, KB_R4 ;3:10 in a,(c) ;2:12 vlastní čtení z portu (5 bitů) push af ;1:10 ld b,high KB_R3 ;2:7 in a,(c) ;2:12 vlastní čtení z portu (5 bitů) ld bc, 0x0020 ;3:10 = 32 push hl ;1:11 call vlevo_rra ;3:17 call vpravo_rra ;3:17 call dolu_rra ;3:17 call nahoru_rra ;3:17 call palba_rra ;3:17 ex (sp),hl ;1:19 res player_a,(hl) ;2:15 pop hl ;1:10 set player_a,(hl) ;2:15 ex de,hl pop af ;1:10 push hl ;1:11 call palba_rra ;3:17 call nahoru_rra ;3:17 call dolu_rra ;3:17 call vpravo_rra ;3:17 call vlevo_rra ;3:17 ex (sp),hl ;1:19 res player_b,(hl) ;2:15 pop hl ;1:10 set player_b,(hl) ;2:15 push hl ;1:11 ld hl,ATTRIBUTE_ADR+3*256-1;3:10 check_timer: ld a,(hl) ;1:7 bit timer,a ;2:8 jr z,no_timer ;2:7/12 bit bomb,a ;2:8 jr nz,explosion ;2:7/12 flash: and %00000111 ;2:7 mask_time jr z,save ;2:7/12 or %11000000 ;2:7 jr dec_a ;2:7/12 explosion: and %00000111 ;2:7 mask_time jr nz,dec_timer ;2:7/12 ld a,%11000111 ;2:7 init flash push hl call vlevo ld (hl),a pop hl push hl call vpravo ld (hl),a pop hl push hl call dolu ld (hl),a pop hl push hl call nahoru ld (hl),a pop hl jr save ;2:12 dec_timer: ld a,(hl) ;1:7 dec_a: dec a ;1:4 save: ld (hl),a ;1:7 no_timer: dec hl ;1:6 bit 2,h ;2:8 0x57 1001 0111 jr z,check_timer;2:7/12 pop hl ;1:10 ; check live ld a,(hl) ;1:7 ex de,hl ;1:4 or (hl) ;1:7 and %00101000 ;2:7 cp %00101000 ;2:7 jp nz,start ;3:10 halt halt jp main ;------------------------------------------------------------------------------- if 0 read_row: ld c, 0xFE ;2:7 in a, (c) ;2:12 vlastní čtení z portu (5 bitů) ld bc, 0x0020 ;3:10 = 32 ret ;1:10 endif ;------------------------------------------------------------------------------- vlevo_rra: rra ;1:4 ret c ;1:5/11 vlevo: 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 ret ;1:10 ;------------------------------------------------------------------------------- vpravo_rra: rra ;1:4 ret c ;1:5/11 vpravo: push af ;1:11 ld a,%00011111 ;2:7 inc l ;1:4 and l ;1:4 jr nz,$+3 ;2:7/12 dec l ;1:4 pop af ;1:10 ret ;1:10 ;------------------------------------------------------------------------------- dolu_rra: rra ;1:4 ret c ;1:5/11 dolu: ; 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,$+4 ;2:7/12 sbc hl,bc ;2:15 dec h ;1:4 ret ;1:10 ;------------------------------------------------------------------------------- nahoru_rra: rra ;1:4 ret c ;1:5/11 nahoru: ; 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 ret z ;1:5/11 add hl,bc ;1:11 ret ;1:10 ;------------------------------------------------------------------------------- palba_rra: rra ;1:4 ret c ;1:5/11 palba: push af ;1:11 ld a,%01010111 ;2:7 or (hl) ;1:7 ld (hl),a ;1:7 pop af ;1:10 ret ;1:10 end ENTRY_POINT
Tezko rici jak je to "hratelne" bez 2 hracu a joysticku. Na emulatoru me moje klavesnice nepodporuje pro prvniho hrace fire+sikmy pohyb, krome vlevo dolu.