Názory k článku Práce s klávesnicí na ZX Spectru

  • Článek je starý, nové názory již nelze přidávat.
  • 18. 5. 2023 3:26

    _dw

    Diky za clanek! Jeste jsem to nedocetl, ale nedalo mi ukazat u tretiho prikladu maly trik.

    To ze jsi to dal do maker, je asi prehlednejsi co to ma delat, ale ne jak to dela a pak ti snadno uniknou optimalizace.

    Takhle to vypada kdyz provedu makra:

    next_key:
            srl a                          ; přesunout kód stisku klávesy do příznaku carry
            jr  nc, key_pressed            ; test stisku klávesy
            ld  (hl), WHITE_COLOR << 3
            inc hl
            jr  next                       ; test další klávesy
    key_pressed:
            ld  (hl), INTENSITY_BIT | (RED_COLOR << 3)
            inc hl
    next:
            djnz next_key                  ; opakovat celou smyčku 5x

    1 bajt usetrim kdyz zamenim dvoubajtove "srl a" za treba "rra", pokud me zajima jen carry.
    1 bajt usetrim kdyz si uvedomim, ze obe vetve provadi spolecny kod "inc hl"

    next_key:
            rra                            ; přesunout kód stisku klávesy do příznaku carry
            jr  nc, key_pressed            ; test stisku klávesy
            ld  (hl), WHITE_COLOR << 3
            jr  next                       ; test další klávesy
    key_pressed:
            ld  (hl), INTENSITY_BIT | (RED_COLOR << 3)
    next:
            inc hl
            djnz next_key                  ; opakovat celou smyčku 5x

    Tim jsem se dostal do situace, kdy obe vetve maji jen 2 bajty a tak lze proves jeste dalsi optimalizaci a usetrit jeden bajt tim, ze zamenim "jr next" za 3 bajtovy jp. Trik je v tom, ze nastavim priznaky tak, ze se nikdy neprovede a adresa skoku bude kod druhe vetve. Podobneho efektu lze docilit ze si zaspinim nejaky dvouregistr napr "ld DE,xxxx", ale tady mam jasne definovany stav priznaku takze to jde udelat ciste.

    next_key:
            rra                            ; přesunout kód stisku klávesy do příznaku carry
            jr  nc, key_pressed            ; test stisku klávesy
            ld  (hl), WHITE_COLOR << 3
            db  0xD2                       ; jp nc,nn
    key_pressed:
            ld  (hl), INTENSITY_BIT | (RED_COLOR << 3)
    next:
            inc hl
            djnz next_key                  ; opakovat celou smyčku 5x

    Tohle by se dalo jeste prepsat, ze zrusim uplne to "jr nc" a "jp" a umistim za prvni vetev, ktera se vykona vzdy opacny priznak, aby se druha vetev vykonala jen kdyz ma. Tim by se usetril dalsi bajt.

    next_key:
            rra                            ; přesunout kód stisku klávesy do příznaku carry
            ld  (hl), WHITE_COLOR << 3
            jr   c, next                   ; test stisku klávesy
            ld  (hl), INTENSITY_BIT | (RED_COLOR << 3)
    next:
            inc hl
            djnz next_key                  ; opakovat celou smyčku 5x

    Tohle ma ale hacek! Bude to videt, protoze sahame do atributove pameti v nahodnem case a nekdy trefime paprsek a tak se nam muze u zobrazeni objevit bila cara. Bude se to chvet. Udelame 3 barvy v jednom znaku, kdybychom to spravne sesynchronizovali s paprskem.

  • 18. 5. 2023 18:40

    Mikes21

    Pekne, a co treba:

    next_key:
            rra                            ; přesunout kód stisku klávesy do příznaku carry
            ld   a, WHITE_COLOR << 3
            jr   c, next                   ; test stisku klávesy
            ld   a, INTENSITY_BIT | (RED_COLOR << 3)
    next:
            ld   (hl), a
            inc hl
            djnz next_key                  ; opakovat celou smyčku 5x
  • 18. 5. 2023 20:00

    _dw

    Pekne, tohle je jako evoluce toho posledniho reseni, aby to neblikalo? .)
    Kdyz se zameni registr A za napr. E tak to bude funkcni, protoze A si drzi stav toho radku/sloupce matice klaves..

    Porovnal jsem to s predposlednim, protoze oba maji 11 bajtu a JP reseni je rychlejsi.

    JP:
    White: 7+10+10=27
    Red: 12+10=22

    White: 7+12+7=26
    Red: 7+7+7+7=28

  • 18. 5. 2023 20:21

    Pavel Tišnovský
    Zlatý podporovatel

    hmm ještě si říkám, jestli tu podmínku neotočit, protože je pravděpodobnější, že klávesa NEbude stisknuta.

  • 18. 5. 2023 21:16

    _dw

    Jo mas pravdu, dobry postreh. Dopredu vedet, ktere vetve jsou pravdepodobnejsi je dalsi informace diky ktere muze mit clovek navrh nad prekladaci (aspon na Z80, pokud to neni neco jako java).

    Ale realne v tomto pripade to nic nezmeni, protoze se ten atribut stejne prepise...ted to jeste spocitat

    ;[: 8*(52+225)=2216+200?]  1448x pomala vetev
    ;[: 8*(52+250)=2416+200?]  1337x rychla vetev

    nez se to jednou prekresli na obrazovce.

    Tohle teda plati pro tu moji verzi ve smycce. To +200 si cucam z prstu, protoze nemam tuseni o kolik se to zpomali tim ze se saha pod 0x8000.
    Dal jsem, ze misto ld (HL),nn 2:10 to je 2:15. A 5*(5*8)=200

  • 18. 5. 2023 21:26

    _dw

    Zapomnel jsem to jeste podelit 50.

    Takze

    26.97x pomala vetev
    28.76x rychla vetev

    18. 5. 2023, 21:26 editováno autorem komentáře

  • 18. 5. 2023 21:50

    _dw

    Pridal jsem do kodu mensi zpomaleni o 176 taktu pro nastaveni barvy pozadi

    ld    A, 7          ; 2:7       zx_border
    and   B             ; 1:4       zx_border
    out (254),A         ; 2:11      zx_border   0=blk,1=blu,2=red,3=mag,4=grn,5=cyn,6=yel,7=wht
                              ;[: 8*(52+225)=2216+200?+176]  70000/2592=27.007x
                              ;[: 8*(52+250)=2416+200?+176]  70000/2792=25.072x
    
    jp   keypress             ; 3:10    další test stisku kláves

    A vysledek je asi 22x a 20x? oproti vypoctu 27x a 25x.

    Fast:
    https://ibb.co/bmRqnYk
    Slow:
    https://ibb.co/18GVBkS

    PS: U te slow (puvodni verze) je zajimavy efekt jak se stiskne klavesa. Bez ni se ty pruhy pomalu pohybuji nahoru a po stisku to zacne ruzne klesat a nebo zase stoupat.

    18. 5. 2023, 21:55 editováno autorem komentáře

  • 18. 5. 2023 4:44

    _dw

    Prepsal jsem jeste posledni program z kapitoly 15 do smycky. Takze jsem to stahnul ze 168 bajtu na 90 bajtu.

    ENTRY_POINT   equ $8000
    ROM_CLS       equ $0DAF
    
            org ENTRY_POINT
    
    BLINK_BIT     equ %10000000
    INTENSITY_BIT equ %01000000
    BLACK_COLOR   equ %000
    BLUE_COLOR    equ %001
    RED_COLOR     equ %010
    MAGENTA_COLOR equ %011
    GREEN_COLOR   equ %100
    CYAN_COLOR    equ %101
    YELLOW_COLOR  equ %110
    WHITE_COLOR   equ %111
    
    
    start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
    
        ld   BC, str_keys_size    ; 3:10      print     Length of string
        ld   DE, str_keys         ; 3:10      print     Address of string
        call 0x203C               ; 3:17      print     Print our string with ZX 48K ROM
    
        ld  bc, 0xfef0            ; adresa portu, ze kterého budeme číst údaje
        ld  hl, 0x5800            ; adresa, od které budeme měnit barvové atributy
    keypress:
        in  a, (c)                ; vlastní čtení z portu (5 bitů)
        ld  e, 5                  ; počet atributů + počet testovaných kláves
    next_key:
        rra                       ; přesunout kód stisku klávesy do příznaku carry
        jr  nc, key_pressed       ; test stisku klávesy
        ld  (hl), WHITE_COLOR << 3
        db  0xD2                  ; jp nc,nn
    key_pressed:
        ld  (hl), INTENSITY_BIT | (RED_COLOR << 3)
    next:
        inc  l
        dec  e
        jr   nz, next_key         ; opakovat celou smyčku 5x
    
        ld   a, l
        add  a, 32-5
        ld   l, a
        rlc b
        jp   keypress             ; další test stisku kláves
    
    str_keys:                                  ; layout klávesnice z pohledu čipů ZX Spectra
        NEW_LINE      equ 13
        DB "^ZXCV", NEW_LINE
        DB "ASDFG", NEW_LINE
        DB "QWERT", NEW_LINE
        DB "12345", NEW_LINE
        DB "09876", NEW_LINE
        DB "POIUY", NEW_LINE
        DB $7f, "LKJH", NEW_LINE
        DB "_", $60, "MNB"
    str_keys_size equ $-str_keys
    
    end ENTRY_POINT

    PS: U Fuse mam problem, ze me to nebere u ceske klavesnice cisla a naopak u anglicke to v basicu vyvolava spatne prikazy.
    PPS: Jinak muj notebook zvladne ASDW (asi optimalizovano) + napriklad C+K+T a + space

  • 18. 5. 2023 8:01

    atarist

    Jo ASDW umi hodne hernich klavesnic, ktere se tvari, ze nemaji ghosting. Ale samozrejme maji (neni tam nikde cip se 100+ vstupy :-), akorat u tech "proflaklych" kombinaci si dali tu praci s matici, aby k nemu nedochazelo.

  • 18. 5. 2023 8:20

    pučmeloun

    Nikde jsem si nevsiml ze by se v kodu resilo zakmitavani klaves(debouncing) a pripadne autorepeat. Nemam uplne znalosti ZXSpectra a jeho klaves, ale zrovna nedavno sem toto resil u Sord M5 bez pouziti BIOS rutin.

  • 18. 5. 2023 15:25

    _dw

    One ten kod je napsany velmi chytre a vysledek vypada efektivne. V podstate nezjistuje co si zmackl, ve smyslu ze zjistujes co ti uzivatel stiskl a mas znak.

    50x za vterinu ti probehne prekresleni obrazovky.
    Pres to jedno prekresleni ti hodnekrat probehne ta smycka co ti nastavi atribut pri stisku.

    Takze nic dalsiho nemusis a obraz bude vypadat stabilne.
    Jestli pred zacatkem stisku tam probehne nejaky zakmit co by pri spatnem zpusobu cteni vyvolal opakovane zmacknuti, zda je tlacitko stale drzeno nebo opakovane rychle mackano atd. Vubec nic te nemusi zajimat, v nejhorsim moznem scenari ti to jednou blikne na 1/50s pri stisku a jednou pri uvolneni.

    PS: Ke vsemu to ani netestujeme na realnem ZX, ale emulatoru.

  • 18. 5. 2023 8:27

    atarist

    Tak me napadlo - nektere spectracke hry se pri ovladani klavesnici daji ovladat hodne kombinacemi klaves. Myslel jsem si, ze je to tak naprogramovano, ale ted me napada, jestli tu klavesnici nectou nejakym trikem - ze napriklad povoli vic adresovych linek zaraz a proste se nesnazi o rozeznani vsech klaves, ale jen toho, ve kterem radku (0-4) jsou. Je to tak?

  • 18. 5. 2023 15:35

    _dw

    K te hadance v 14. kapitole se jeste nikdo nevyjadril:

    .)08Z an( utkat 23=)01-41(*8=01*8-)7*8+7*8( o kedelsyv olilamops ela ,utjab 6=)2+8*2(-8*3 olirtesu yb oT .enitur v taled edub es H a rtsiger L nej ivatsan ecazilaicini ez ,kat ot tiledzor a "0085x0 lh" s i taledu sezum elhot elA

    . ":noitceted_sser­pyek" az denh sitsimu ot dukop cebuv tadirp olemen ot yb ytkat a x8 salov ot zydk ,utjab 8*2 tirtesu olem ot yb ezkaT
    ."ef$+trop*652,cb,dl" ohisjenvitkefe itizuop otsim itumjyv an enevarpirp ecnokod sam zu ot ezotorP
    .yniturbus od inezolv a ecazilaicini z "ef$ ,c dl" ytondoh intnatsnok itumjyv ilsym an sam ez ,milsym is aJ

  • 18. 5. 2023 20:26

    _dw

    Jen zpusob jak nekomu nechtene nevyzradit mozne reseni hadanky. a mel sanci si na to prijit sam. Kdybych to chtel "sifrovat" tak bych zvolil

    -<<<--<++<---<--<---<+++<+++++++++[>----->+>->>>---->+>-><[>++++++++++++<<]>-]>[.>]

    =

    +++++++++[>++>+++++>+++++++>++++>++++++>+>+>++++>++>++++[-<]>]>+[>--->>+>>+++++>+>+++>+++>++<[>++++++<<]>-]>[.>]

    =

    ++[<-<<<<++<<<<<+++[>+]>-------]<++++[<-<---<++<-<<-<---<+<--[>]<-]<+<+<-<<<-<-<<[.>]

    =

    ++[<+<+<+<+++<+<+<+<+<+++[>]<-------]++++[<-<---<++<-<<-<---<+<--[>]<-]<+<+<-<<<-<-<<[.>]

    To by pak bylo o neco slozitejsi, zvlast kdybych nechal jen nejkratsi reseni, to by uz nebylo tak zadarmo a spustu lidi by to vyselektovalo (az na ty co by nasli francouzske stranky).

  • 18. 5. 2023 21:17

    Pavel Tišnovský
    Zlatý podporovatel

    to uz je orisek, jestli je to to, co si myslim, ze je, tak je zajimavej ten posun < hned na zacatku mimo pasku (takze to neni to co si myslim :-). Zkusim lustit :)

  • 20. 5. 2023 20:15

    xbastaj

    Zkouším si příklady, a všiml jsem si že v prvních dvou příkladech se před in a, (c) vkládá do regisru C hodnota F0 a v posledním FE. Funguje obojí, zkoušel jsem i jiné hodnoty: F2 funguje, F1 nefunguje. (adresa musí být sudá?) Jaká je tedy správná hodnota portu?
    Jestli jsem to ze schématu správně pochopil, tak jde o osmibitovou adresu vstupního portu který je součástí ULA a využívá se triku že vyšší část adresní sběrnice se použije pro výběr sloupce, což je pěkný trik.

  • 21. 5. 2023 2:04

    xbastaj

    Zkusil jsem si napsat podprogram pro získání kodu klavesy. V akumulátoru je vrácen poziční kod - není to nijak zvlášt optimalizované. Formát je 5 bitů sloupec a 3 bity číslo řádku.

    keyb:   push bc             ;A - kod klavesy
            push de
            ld d,8              ;pocitadlo radku
            ld c,0xF0           ;adresa portu
            ld b,0xFE           ;adresa prvniho radku
    
    keyb01: in a,(c)            ;nacteni portu
            cpl                 ;negace
            and 0x1F            ;nastaveni hornich bitu
            jp nz,keyb02        ;je stisknuta
    
            ld a,b              ;adresa dalsiho radku
            rla
            ld b,a
            dec d               ;pocitadlo radku
            jp nz,keyb01        ;dalsi radek
            pop de
            pop bc
            ret                 ;neni stisknuta zadna (A=00)
    
    keyb02: rla                 ;nalezena prvni stisknuta klavesa
            rla                 ;posun o 3 bity
            rla
            dec d
            add a,d             ;pricteni cisla radku
            pop de
            pop bc
            ret                 ;stisknuta klavesa (A=sssssrrr)

    Pro otestovvání kodů klaves jsem využil "print_hex_number"

    ENTRY_POINT      equ $8000
    ROM_OPEN_CHANNEL equ $1601
    
    AT               equ $16
    ;-------------------------------------------------------------------------------
    GOTO_XY macro X,Y
            ld   A, AT            ; řídicí kód pro specifikaci pozice psaní
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, Y             ; y-ová souřadnice
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, X             ; x-ová souřadnice
            rst  0x10             ; zavolání rutiny v ROM
     endm
    ;-------------------------------------------------------------------------------
    ZNAK_XY macro X,Y,kod
            ld   A, AT            ; řídicí kód pro specifikaci pozice psaní
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, Y             ; y-ová souřadnice
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, X             ; x-ová souřadnice
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, kod           ; kód znaku '*' pro tisk
            rst  0x10             ; zavolání rutiny v ROM
     endm
    ;-------------------------------------------------------------------------------
    
            org ENTRY_POINT
    
    start:
            ld   A,2              ; číslo kanálu
            call ROM_OPEN_CHANNEL ; otevření kanálu číslo 2 (screen)
    
    main:   GOTO_XY 5,5
    
            call keyb
            call print_hex_number
    
            jp main
    
    ;-------------------------------------------------------------------------------
    
    keyb:   push bc             ;A - kod klavesy
            push de
            ld d,8              ;pocitadlo radku
            ld c,0xF0           ;adresa portu
            ld b,0xFE           ;adresa prvniho radku
    
    keyb01: in a,(c)            ;nacteni portu
            cpl                 ;negace
            and 0x1F            ;nastaveni hornich bitu
            jp nz,keyb02        ;je stisknuta
    
            ld a,b              ;adresa dalsiho radku
            rla
            ld b,a
            dec d               ;pocitadlo radku
            jp nz,keyb01        ;dalsi radek
            pop de
            pop bc
            ret                 ;neni stisknuta zadna (A=00)
    
    keyb02: rla                 ;nalezena prvni stisknuta klavesa
            rla                 ;posun o 3 bity
            rla
            dec d
            add a,d             ;pricteni cisla radku
            pop de
            pop bc
            ret                 ;stisknuta klavesa (A=sssssrrr)
    ;-------------------------------------------------------------------------------
    
    print_hex_number:
            push AF             ; uschovat A pro pozdější využití
            rrca                ; rotace o čtyři bity doprava
            rrca
            rrca
            rrca
            and  $0f            ; zamaskovat horní čtyři bity
            call print_hex_digit; vytisknout hexa číslici
    
            pop  AF             ; obnovit A
            and  $0f            ; zamaskovat horní čtyři bity
            call print_hex_digit; vytisknout hexa číslici
            ret                 ; a návrat z podprogramu
    ;-------------------------------------------------------------------------------
    print_hex_digit:
            cp   0x0a           ; test, jestli je číslice menší než 10
            jr c, print_0_to_9  ; ok, hodnota je menší než 10, budeme tedy tisknout desítkovou číslici
            add  A, 65-10-48    ; ASCII kód znaku 'A', ovšem začínáme od desítky, ne od nuly (+ update pro další ADD)
    print_0_to_9:
            add  A, 48          ; ASCII kód znaku '0'
            rst  0x10           ; zavolání rutiny v ROM pro tisk jednoho znaku
            ret                 ; návrat ze subrutiny
    ;-------------------------------------------------------------------------------
    
    end ENTRY_POINT

    No a ještě jeden program: klávesy E, S, D, X pohybují znakem po obrazovce

    ENTRY_POINT      equ $8000
    ROM_OPEN_CHANNEL equ $1601
    ROM_CLS          equ $0DAF
    
    AT               equ $16
    X0               equ 15
    Y0               equ 10
    XMIN             equ 0
    XMAX             equ 31
    YMIN             equ 0
    YMAX             equ 21
    ZNAK             equ "#"
    MEZERA           equ " "
    ;-------------------------------------------------------------------------------
    GOTO_XY macro X,Y
            ld   A, AT            ; řídicí kód pro specifikaci pozice psaní
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, Y             ; y-ová souřadnice
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, X             ; x-ová souřadnice
            rst  0x10             ; zavolání rutiny v ROM
     endm
    ;-------------------------------------------------------------------------------
    ZNAK_XY macro X,Y,kod
            ld   A, AT            ; řídicí kód pro specifikaci pozice psaní
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, Y             ; y-ová souřadnice
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, X             ; x-ová souřadnice
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, kod           ; kód znaku '*' pro tisk
            rst  0x10             ; zavolání rutiny v ROM
     endm
    ;-------------------------------------------------------------------------------
    
            org ENTRY_POINT
    
    start:  call ROM_CLS
    
            ld h,X0               ;pocatecni nastaveni X,Y
            ld l,Y0
            ZNAK_XY h,l,ZNAK
    
    main:   call delay
    m01:    call keyb
    
            cp 0x26
            call z,vpravo
            cp 0x16
            call z,vlevo
            cp 0x25
            call z,nahoru
            cp 0x27
            call z,dolu
    
            jp main
    
    ;-------------------------------------------------------------------------------
    
    keyb:   push bc             ;A - kod klavesy
            push de
            ld d,8              ;pocitadlo radku
            ld c,0xF0           ;adresa portu
            ld b,0xFE           ;adresa prvniho radku
    
    keyb01: in a,(c)            ;nacteni portu
            cpl                 ;negace
            and 0x1F            ;nastaveni hornich bitu
            jp nz,keyb02        ;je stisknuta
    
            ld a,b              ;adresa dalsiho radku
            rla
            ld b,a
            dec d               ;pocitadlo radku
            jp nz,keyb01        ;dalsi radek
            pop de
            pop bc
            ret                 ;neni stisknuta zadna (A=00)
    
    keyb02: rla                 ;nalezena prvni stisknuta klavesa
            rla                 ;posun o 3 bity
            rla
            dec d
            add a,d             ;pricteni cisla radku
            pop de
            pop bc
            ret                 ;stisknuta klavesa (A=sssssrrr)
    ;-------------------------------------------------------------------------------
    vpravo:
            ZNAK_XY h,l,MEZERA
            ld a,h
            cp XMAX
            jr Z,vp0
            inc h
    vp0:    ZNAK_XY h,l,ZNAK
            ret
    
    ;-------------------------------------------------------------------------------
    vlevo:
            ZNAK_XY h,l,MEZERA
            ld a,h
            cp XMIN
            jr Z,vl0
            dec h
    vl0:    ZNAK_XY h,l,ZNAK
            ret
    
    ;-------------------------------------------------------------------------------
    dolu:
            ZNAK_XY h,l,MEZERA
            ld a,l
            cp YMAX
            jr Z,do0
            inc l
    do0:    ZNAK_XY h,l,ZNAK
            ret
    
    ;-------------------------------------------------------------------------------
    nahoru:
            ZNAK_XY h,l,MEZERA
            ld a,l
            cp YMIN
            jr Z,na0
            dec l
    na0:    ZNAK_XY h,l,ZNAK
            ret
    
    ;-------------------------------------------------------------------------------
    delay:  push bc
            push de
            ld d,40
            ld e,0
    d01:    dec e
            jr nz, d01
            dec d
            jr nz, d01
            pop de
            pop bc
            ret
    
    end ENTRY_POINT
  • 23. 5. 2023 3:00

    _dw

    Ta keyb rutina jde napsat mnohem kratsi

    ;-------------------------------------------------------------------------------
    
    keyb:   push bc             ;A - kod klavesy
            push de
            ld d,7              ;pocitadlo radku
            ld bc,0xFEF0        ;adresa prvniho radku & adresa portu
    
    keyb01: in a,(c)            ;nacteni portu
            cpl                 ;negace
            add a,a             ;posun o 3 bity
            add a,a
            add a,a
            jp nz,keyb02        ;je stisknuta
    
            dec d               ;pocitadlo radku
            rl b                ; 0xFE->FD->FB->F7->EF->DF->BF->7F
            jp  c,keyb01        ;dalsi radek
            ld  d,a             ;neni stisknuta zadna (D=A=00)
    
    keyb02: add a,d             ;pricteni cisla radku
            pop de
            pop bc
            ret                 ;stisknuta klavesa (A=sssssrrr)

    A u toho CASE vetveni ktera klavesa je stiskla muzes usetrit taky nejake bajty kdyz mas rozdily mezi vetvemi nekdy jedna.

    Misto:

    cp 0x26
    call z,vpravo
    cp 0x16
    call z,vlevo
    cp 0x25
    call z,nahoru
    cp 0x27
    call z,dolu

    To napis:

    sub 0x16
    call z,vlevo         ; 0x16
    cp 0x25-0x16
    call z,nahoru        ; 0x25
    dec a
    call z,vpravo        ; 0x26
    dec a
    call z,dolu          ; 0x27

    Ale mas tam chybu, ze v tech podrutinach prepisujes registr A. Takze ti to funguje jen nahodou.

    Kdyz se nad tim zamyslis, tak ten zpusob cteni klavesnice neni idealni. Protoze najdes prvni stisklou klavesu a ukoncis cteni klavesnice, ale ty pro tu hru spis potrebujes zjistit i vic klaves, napriklad nahoru+doprava+fi­re. Takze bud nejake 40 bitove pole a nebo jeste lepe pro kazdou konkretni klavesu mit znovu cteni. Mas tam 4 az 5 klaves.

    Nejak takto treba na 110 bajtu (z puvodnich 203):

    ENTRY_POINT      equ $8000
    ROM_CLS          equ $0DAF
    
    AT               equ $16
    X0               equ 15
    Y0               equ 10
    XMIN             equ 0
    XMAX             equ 31
    YMIN             equ 0
    YMAX             equ 21
    ZNAK             equ "#"
    MEZERA           equ " "
    
    
            org ENTRY_POINT
    
    start:  call ROM_CLS
    
            ld hl,256*X0+Y0       ;pocatecni nastaveni X,Y
            ld de,ZNAK*257        ;D=E=znak
            call print_yx_hl_e
    main:   halt
            halt
    
            ld bc,0xFB02     ; Q
            call checkpress
            call nz,nahoru
    
            ld b,0xFD        ; A, C=0x02
            call checkpress
            call nz,dolu
    
            ld bc,0xDF04     ; O
            call checkpress
            call nz,vlevo
    
            ld c,0x02        ; P, B=0xEF
            call checkpress
            call nz,vpravo
    
            jr main
    
    ;-------------------------------------------------------------------------------
    
    ;in:
    ;B=0x7F C= ..BNMs_.
    ;B=0xBF C= ..HJKLe.
    ;B=0xDF C= ..YUIOP.
    ;B=0xEF C= ..67890.
    ;B=0xF7 C= ..54321.
    ;B=0xFB C= ..TREWQ.
    ;B=0xFD C= ..GFDSA.
    ;B=0xFE C= ..VCXZc.
    
    ;out: nz=press
    checkpress:
            in a,(c)            ;nacteni portu
            cpl                 ;negace
            add a,a             ;posun o 3 bity
            and c
            ret
    ;-------------------------------------------------------------------------------
    
    vpravo:
            ld a,h
            cp XMAX
            ret Z
            call print_yx_hl_space
            inc h
            ld e,d
            jr print_yx_hl_e
    
    ;-------------------------------------------------------------------------------
    vlevo:
      if (XMIN=0)
            inc h
            dec h
      else
            ld a,h
            cp XMIN
      endif
            ret Z
            call print_yx_hl_space
            dec h
            ld e,d
            jr print_yx_hl_e
    
    ;-------------------------------------------------------------------------------
    dolu:
            ld a,l
            cp YMAX
            ret Z
            call print_yx_hl_space
            inc l
            ld e,d
            jr print_yx_hl_e
    
    ;-------------------------------------------------------------------------------
    nahoru:
      if (XMIN=0)
            inc l
            dec l
      else
            ld a,l
            cp YMIN
      endif
            ret Z
            call print_yx_hl_space
            dec l
            ld e,d
            jr print_yx_hl_e
    
    ;-------------------------------------------------------------------------------
    print_yx_hl_space:
            ld   E,' '            ; 1e20
    print_yx_hl_e:
            ld   A, AT            ; řídicí kód pro specifikaci pozice psaní
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, L             ; y-ová souřadnice
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, H             ; x-ová souřadnice
            rst  0x10             ; zavolání rutiny v ROM
            ld   A, E             ; kód znaku '*' pro tisk
            rst  0x10             ; zavolání rutiny v ROM
            ret
    
    ;-------------------------------------------------------------------------------
    
    end ENTRY_POINT

    PS: Ja zase pouzivam v C masku klavesy co chci tisknout vynasobenou dvema. V emulatorou to funguje, ale na realnem ZX netusim... Z toho obrazku obvodu a ze jsou pri nejakych kombinacich vyvolany duchove je uz mimo muj level. Proste HW...

  • 23. 5. 2023 7:57

    xbastaj

    Nemám s Z80 tolik zkušeností a ani neznám všechny instrukce, tak jsem si nebyl jistý jak to vlastně je. Jestli můžu instrukce rotací použít i na jiný instrukce než akumulátor. Je nějaká rozumná tabulka s instrukcemi? Když jsem to na internetu hledal, tak na mne vylezla buď moc podrobná (odstavec na každou instrukci) nebo zas jen tabulka kde zjistím maximálně hex kod. Používám to od p. Tišnovského co je v lekcích, ale je to po kouskách a myslím že ne kompletní.

    To že přečtu jen jednu klávesu je mi jasný, neměl jsem v tuhle chvíli ambice to udělat líp. S tím že v podprogramech přepisuju A máš pravdu, nevšimnul jsem si toho. Funguje to jen proto, že kódy zvolených kláves jsou větší než souřadnice X.Y.

  • 23. 5. 2023 14:16

    _dw

    Ja osobne pouzivam 5. odkaz uvedeny v clanku v odkazech.

    https://clrhome.org/table/

    Asi pred pul rokem prosel web nejakym designovym updatem a uz to neni ono. Plus ma (nebo mel) tam asi nejake drobne chyby, ze ma spatne zacervenene instrukce.

    Popisky jsou v nahledu. Nekdy je stejne potreba vetsi popisek, protoze nektere instrukce jsou matouci.
    Nejdulezitejsi je prvni tabulka, protoze je bez prefixu, takze nejkratsi instrukce a nejrychlejsi.
    Pak muze byt uzitecna CB a ED.
    Zbytek v nejakych specialnich pripadech, bud slozity algoritmus, nebo mas vsechno obsazene, ale je otazka zda to nejde napsat jinak.

    Nekdy instrukce, ktere vypadaji jako kopie z prvni tabulky se ale lisi priznaky (ruzne posuny a rotace A).

    Ale treba LD (adr),HL ma dve varianty "22 lo hi" a "ED 63 lo hi". Uplne zbytecne, ale... nekdy by se to treba mohlo hodit kdyz provadis nektere triky, kdy se snazis eliminovat nejaky skok, nebo se snazis mit 2 kody v sobe, jen posunuty o bajt (Z80 ti to skoro okamzite ale slouci diky tomu jak ma udelane opcody).

    PS: U keyb si pouzil 3x "rla" a fungovalo ti to protoze si pred prvni "rla" mel vynulovany carry po "and" a pri druhem a tretim, protoze jsi mel vynulovany carry, protoze si zaroven tim "and" odmazal 3 nejvyssi bity z A.
    Pokud by si ale rovnou pouzil "add A,A", nemusel bys carry resit, kdyz tam chces jen nuly.
    PPS: Dobra prace.

  • 24. 5. 2023 15:11

    _dw

    Protoze prvni je spatne a je to mysleno jako oprava. Narazil jsem na to v nejakem dalsim kodu.
    Prvni dela:

    rl b                ; 0xFE->FC->F8->F0->E0->C0->80->00

    "rl b" = "adc b,b", ale v kodu je vzdy vynulovany carry takze je to "add b,b" (Pak ze Z80 umi pocitat jen s A(HL)).

    Premyslel jsem proc to fungovalo a dospel jsem k nazoru, ze...

    Tomu prvne predhodite spravnou hodnotu a on otestuje stisk klaves na radku 0xFE a zjisti ze je nejaka stiskla a ukonci se a nebo neni zadna stiskla a pokracuje.

    Dalsi hodnota je 0xFC a program provede znovu kontrolu jako v FE kde nic neni pokud to nahodou neni stiskle prave v ten moment (opakovane zmacknuti Z (3.bit 0xFE) by asi melo obcas vyvolat stisk S (3.bit 0xFD)) a provede kontrolu i pro 0xFD (dela asi proste zaroven kontrolu 0xFE a 0xFD kdyz ma dva bity nulove)

    Atd pro zbytek.