Úno 032005
 

Před dalším dílem o klávesnici si musíme vysvětlit princip přerušení, k čemu slouží a jak jej využít.

Přerušení je okamžik, kdy Z80 dostane signál o tomto jevu, a zobrazovací obvody Spektra začnout vykreslovat na TV nový snímek obrazu podle obsahu videoram (16384-22527). Podle toho, jak je Z80 nastavena, se ještě něco vykoná. Můžeme Z80 nastavit na 2 chování:

1/ di – disable interrupt, zákaz přerušení.
2/ ei – enable interrupt, povolení přerušení.

Pokud je nastaveno di, vždy se začne vykreslovat nový obraz, ale jinak si Z80 ničeho nevšímá.

Je-li ovšem nastaveno ei, zachová se podle módu, který má nastaven. Jsou to tyto tři:

1/ im 0 – interrupt mode 0
2/ im 1 – interrupt mode 1
3/ im 2 – interrupt mode 2

im 0 se na ZXS nevyužívá, takže jen teoreticky: Z80 si přečte na datové sběrnici hodnotu a tu považuje za instrukci a tu provede. O žádné takové periférii nevím, která by toho využívala.

Je-li nastaven mód im 1, při signálu přerušení se provede rst 56 (rst $38). To je docela důležitý okamžik, právě tam se v ROM nachází rutina, která se stará o obsluhu klávesnice a hodin. Hodiny nás nezajímají, ale pro PeCaře: nejde o RTC. Pokud bude náš program využívat přerušení v módu im 1, musí (minimálně v době přerušení) ukazovat registr iy do oblasti systémových proměnných Basicu (na hodnotu 23610) a ty musí být v pořádku, protože tam má rutina uloženy proměnné o autorepeatu a tam taky ukládá informaci o stištěné klávese.

S módem im 2 je to kapánek složitější. Při signálu přerušení Z80 přečte hodnotu z datové sběrnice a z ní udělá nižší bajt adresy. Z registru I udělá vyšší bajt adresy. Z této adresy vyzdvedne dvoubajtovou hodnotu coby další adresu a na tu skočí. Prostě něco jako CALL (ADRESA). Opět mi není známo o periférii, která by poslala na sběrnici nějakou hodnotu, ale tento mód přerušení se na spektru dá využít.

Několik pravidel, která se prerušení týkají:

Přijde-li signál přerušení, právě prováděná instrukce se dokončí. A to i ta, která je vícebajtová a prefixovaná.

V případě im 0 a im 1 im2 se nelze spoléhat na to, že na sběrnici se většinou hodnota $FF. Třeba D80 občas nastavuje nějaká nesmyslná numera.

Procesor při skoku do přerušení uloží na zásobník hodnotu následující instrukce, kterou má pokračovat a nastaví di. Proto při návartu z přerušení použijeme sekvenci instrukcí ei , ret nebo ei , reti. Instrukce reti má na ZXS stejný význam jako ret.

cpu     z80undoc
        relaxed on

        org 25000
START   di                      ;nejprve zakaz preruseni
        ld      a,$FD           ;nastav vektor preruseni
        ld      i,a             ;to bude horni byte adresy cele tabulky
        im      2               ;nastav im 2
        ei                      ;a povol prerusovani
                                ;nasleduje hlavni provadeci smycka
LOOP1   ld      a,(VAR1)        ;ktera cyklicky meni barvu atributu
        dec     a               ;kazdych 25/50 sekundy
        ld      (VAR1),a
        jr      nz,WAIT1
        ld      a,(22528)
        add     a,8
        and     %111000
        ld      (22528),a
        ld      a,25
        ld      (VAR1),a
WAIT1   halt
        call    8020            ;dokud se nestiskne BREAK
        jr      c,LOOP1
        im      1               ;pak se nastavi normalni mod
        ret                     ;a vrati se do BASICu

PRERUSENI                       ;smycka, ktera bezi pod prerusenim
        push    af              ;uloz registr, ktery se v prubehu meni
        ld      a,(VAR2)        ;je to podobna smycka
        dec     a               ;akorat ze barvu meni kazdych
        ld      (VAR2),a        ;50/50 sekundy (kazdou sekundu)
        jr      nz,WAIT2        ;ale jiny atribut
        ld      a,(22529)
        add     a,8
        and     %111000
        ld      (22529),a
        ld      a,50
        ld      (VAR2),a
WAIT2   pop     af              ;vyzvedni registr
        ei                      ;a vrat se z preruseni do hlavni smycky
        ret

VAR1    db      25
VAR2    db      50

        org     $FD00           ;na adrese $FD00 (registr i=$FD)
        db      257 dup ($FE)   ;tabulka, ktera obsahuje 257krat hodnotu $FE
        org     $FEFE           ;a na adrese $FEFE
        jp      PRERUSENI       ;to hupsne do smycky c.2

A jak to vlastně celé funguje? Protože registr I má hodnotu $FD celá tabulka musí být na adrese s vyšším bajtem $FD. Musí být dlouhá 257 bajtů, protože když bude na sběrnici $FF bude se adresa skoku brát z adresy $FDFF a $FE00. Celá tabulka je vyplněna hodnotou $FE, takže vybraná adresa bude vždy $FEFE a tam se již nachází instrukce jp PRERUSENI. Hlavní smyčka je LOOP1 a ta je vždy 1/50 sekundy přerušena při čekání halt na signál přerušení. Tam to skočí do druhé smyčky PRERUSENI a ta skončí návratem z přerušení zpět do hlavní. Složité, ale užitečné hlavně v demech, kdy je druhá smyčka tvořena přehráváním hudby a hlavní smyčka se věnuje vlastnímu demu.

Toto vše se nazývá Maskovatelné přerušení.

Existuje ještě Nemaskovatelné přerušení (NMI), které není možné zakázat. To většinou nastane po stisku hardwarového tlačítka. To způsobí uložení návratové adresy (registru PC) a nastavení di a skoku na adresu $66 (102). Vůbec nezáleží na povoleném/zakázaném přerušení. V ROM ZX je „úmyslně“ udělaná chyba, tuto chybu odstranili ve Skalici v Didaktiku Gama. Návrat z nemaskovatelného přerušní by mělo být instrukcí retn. Tato instrukce nastaví zpět ei nebo di takové, jaké bylo.

Toto hardwarové tlačítko mají zařízení divIDE, D80 a MB02+. V ZXM se objevovali návody na výrobu generátoru signálu NMI, které současně s úpravou ROM a nahrání software do paměti způsobilo při stisku skok do paměťového monitoru. V D80 slouží k pořízení SNAPu, v divIDE na ovladání případného OS a v MB02+ taky.

Domácí úkol: Udělejte domácí úkol ze 4.dílu 🙂

Příště: Klávesnice.

  9 komentáre na “5.díl: Módy přerušení”

  1. hodne zajimave cteni; konecne v tom zacinam mit jasno; hned jak se dostanu k ZX (Pec+Emul, zivot je boj), tak si neco s prerusenim zkusim… dik Sweete za dalsi dil

  2. Neni zac. Sam jsem s ukazkovym programem zapasil. Mikezt ovsem nezklamal a pomohl.

  3. Sweete,

    super clanek, jen male info, jelikoz je pameti vzdycky malo, ja na inicializaci IM2 pouzivam tento postup (usetrim tim 3 byty, vlastne v podstate vice, nebot spousteci adresa je stejna jako adresa IM2 tabulky :).

    org 32768
    IM2
    jp START
    ds 254
    START
    di
    ld hl,IM2TAB
    ld de,IM2TAB+1
    ld bc,256
    ld (hl),INTERUPT/256
    ldir
    ld a,IM2/256

  4. Kurna nejak se podelalo formatovani toho prispevku … tak sorry 🙁

  5. Zajímací řešení. V našem zdrojáku ale generátor tabulky není, tabulka je již hotova. Takže my paměť ušetříme. Jediné, co neušetříme, je místo na CF, protože se to musí uložit včetně tabulky. Takže pokud bychom chtěli ušetřit pamět a prostor na disketě, tak tabulku vytvoříme již ve zdrojáku a celý produkt proženeme kompresí. Tím ušetříme paměť v běžícím programu a místo na harddisku.

  6. Nemusime ani komprimovat 🙂 staci program trochu rozLDIRovat 🙂 ale to by jsme asi jiz sli na komara tankem 🙂

  7. Navrat z preruseni pres RETN?

    To je nejaka specialita Assu, nebo mi uz hrabe a blbe si to pamatuju?

    Ja bych se totiz vracel z preruseni pres RETI.

    Fakt ted nevim…

    dex of MB-Maniax

  8. Xor, jsem debil.

    Ja si nevsiml, ze cumim do nemaskovatelneho preruseni.

    Ale stejne jsem ted z toho zmaten ako lesna vcelka.

  9. Reti je totež jako napsat ei a pak ret 😉 ale asi se tim ušetří nějakej ten bajt…

Je nám líto, ale formulář pro přidávání komentářů je momentálně uzavřen.