ZX Spectrum > PROGRAMOWANIE

Przerwania - ZX Spectrum 48

(1/5) > >>

dr.df0:
Witajcie,

Przeglądając kod mojego starego demka (z przełomu 1990/1991) znalazłem ciekawą (niestety bardzo słabo przenośną na klony, inne modele i rozszerzone gumiaczki) metodę uruchamiania kodu na przerwaniach.

Metoda polega na wykorzystaniu trybu przerwań IM 2 procesora Z80 (tryb ma chyba nazwę vectored interrupt), a polega na tym, że do rejestru I wstawia się starszy bajt adresu tablicy zawierającej adresy procedur obsługujących przerwania, której adres w teorii (chyba również w praktyce, choć podobno Z80 nie obsługuje poprawnie nieparzystych indeksów, czyli potrafi procedurę z spod nieparzystego indeksu również wywołać) powinna być w momencie wygenerowania przerwania wczytana z szyny danych z urządzenia zewnętrznego.

Trik, który stosowaliśmy polegał na dwóch założeniach:


* W niezmodyfikowanym ROM-ie ZX Spectrum 48k od adresu $3900 znajduje się ciągły blok ponad 257 bajtów wypełnionych wartościami $FF, więc ustawienie rejestru I na wartość $39 (przy trybie przerwań IM 2) powodowało przy każdym przerwaniu VBLANK skok do adresu $FFFF, bo niezależnie jaka wartość była aktualnie na szynie danych ($00 - $FF), to w bloku pamięci ROM wskazanym jako tablica wektorów przerwań ($3900 - $3A00, bo I = $39) zawsze otrzymywaliśmy adres procedury obsługi przerwania = $FFFF.

Uwaga: tablica wektorów przerwań musi mieć rozmiar 257 bajtów, a nie 256, bo potencjalnie na szynie danych może pojawić się wartość $FF i wtedy adres procedury obsługi przerwania jest pobierany z lokalizacji $39FF i $3A00 (257 bajt, licząc od $3900).


* W pamięci ROM pod adresem $0000 mieści się wartość $F3, więc jeśli do komórki pamięci $FFFF wpiszemy opcode dla rozkazu JR ($18), to rozkaz ten przy wykonaniu w trakcie obsługi przerwania pobierze swój operand z kolejnego adresu, czyli $0000, co w efekcie spowoduje skok pod adres $FFF4, gdzie umieszczaliśmy rozkaz JP irq_routine

Przykładowy kod, który korzysta z ten sztuczki i działa chyba tylko na oryginalnym ZX Spectrum 48k (w formacie pasmo) może wyglądać tak:


--- Kod: ---    org $8000

start:
   call irq_init

; basically do nothing, as the main job of changing backgroud colors
; is done in the irq routine
loop:
    halt

    jr  loop
   
irq:
    di
   
    push af
    push hl
   
    ld  hl, color
    ld  a, (hl)
    and 7
    out (254), a
    inc (hl)

    pop  hl
    pop  af

    ei
    ret

; VARIABLES
color: db 0

;; ========================================================
;;   IRQ Init Routine
;; ========================================================
irq_init:
    halt
    di

    ld  hl, $FFFF
    ld  (hl), $18 ; JR opcode

    ; set the IM2 mode to use jump table at $3900 (block of $FF in ROM)
    ld  a, $39
    ld  i, a
    im  2

    ; insert JP irq at address $FEFE
    ld  hl, $FFF4
    ld  (hl), $C3 ; JP opcode
    inc hl
    ld  (hl), LOW irq
    inc hl
    ld  (hl), HIGH irq

    ei
    retn

    end $8000

--- Koniec kodu ---

Tak to robiliśmy wtedy ... oczywiście ten kod można trochę poprawić (pracuje wtedy np. na 128k), używając spreparowanej tablicy wektorów w pamięci RAM, co realizuje poniższa procedura irq_init, którą można podmienić we wcześniejszym kodzie.


--- Kod: ---;; ========================================================
;;   IRQ Init Routine - more generic
;; ========================================================
irq_init:
    halt
    di

    ; fill 257 bytes starting from $FD00 with $FE,
    ; so IRQ in IM 2 mode will always jump to $FEFE
    ld  hl, $FD00
    ld  de, $FD01
    ld  bc, 257
    ld  (hl), $FE
    ldir

    ; set the IM2 mode to use jump table at $FD00
    ld  a, $FD
    ld  i, a
    im  2

    ; insert JP irq at address $FEFE
    ld  hl, $FEFE
    ld  (hl), $C3 ; JP opcode
    inc hl
    ld  (hl), LOW irq
    inc hl
    ld  (hl), HIGH irq

    ei
    ret

--- Koniec kodu ---

Pozdrawiam i ciekaw jestem waszych uwag!

Phonex:
Tak się wtedy robiło. Tą sztuczkę na forum opisywał rafamiga parę lat temu.
Kto ją spopularyzował w "środowisku"? Nie pamiętam, ale oczywiście też stosowałem.
Ten napisał rafamiga https://www.speccy.pl/forum/index.php?topic=4489.msg72050#msg72050
Ten napisałem ja https://www.speccy.pl/forum/index.php?topic=4489.msg72225#msg72225
Zajrzałem na szybko i jedyna różnica, to z przekory (tak! przypomniałem sobie - chciałem się odróżniać 8) ) użyłem tablicę pod $3B00, a nie $3900 ;)

I to działa na ZX128! Bez żadnego dołączonego interfejsu na szynie jest $FF, więc adres bierze spod $39FF (lub $3BFF lub też $3AFF). W tych trzech strategicznych miejscach projektanci ZX128 specjalnie zostawili dwa $FF! Widać, że specjalnie bo w jednej z tych lokalizacji przed nimi jest skok omijający o dwa bajty :D
W czasie dyskusji na ten temat ktoś (chyba trojacek) napisał, że w zasadzie nawet z dołączonymi interfejsami w momencie odczytu wektora nie ma szans, żeby na szynie było cokolwiek innego niż $FF.
Na Pentagonie też działa. Ta jego część jest zgodna ze 128.

Także nie wiem do końca, czemu ten sposób jest odradzany? Może na innyh klonach nie działa...
Albo może chodzi o niezgodność z dodatkowymi ROMami ZX128? Że np. w edytorze Basica nie działało by? A w +3 w czasie operacji dyskowych?

KWF:
Dzięki za podzielenie się i wyjaśnienia. Swoją drogą, kilka tygodni temu z matem pisałem o lokalizacji wektora przerwań na Discorcie. W zasadzie kiedy wywoływane jest przerwanie wszystkie urządzenia powinny być odłączone od szyny danych, w 99% przypadków (w zasadzie zawsze, o ile nie mamy jakiegoś interfejsu siejącego po szynie danych) procesor odczyta $FF. W „wolnym” bloku ROM są możliwe trzy alokacje wektora przerwań ($3900, $3A00 i $3B00) i z tego co pisał mat, to wystarczy 6 bajtów (3 lokacje po 2 bajty), aby obsłużyć przerwania. Ma to znaczenie, w przypadku modyfikowanych ROMow, wiec warto byłoby zostawiać te 6 bajtów z wartością $FF, a resztę wykorzystać zgodnie z własnym uznaniem.

matofesi:

--- Cytat: Phonex w 2021.10.14, 21:48:19 ---Także nie wiem do końca, czemu ten sposób jest odradzany? Może na innyh klonach nie działa...
Albo może chodzi o niezgodność z dodatkowymi ROMami ZX128? Że np. w edytorze Basica nie działało by? A w +3 w czasie operacji dyskowych?

--- Koniec cytatu ---

Tak - chodzi głównie o inne maszyny - jakieś nietypowe klony w których ludzie dokładają kod w "wolnym" miejscu nie zwracając uwagi na FFy czy też urządzenia podmieniające ROM, które również nie zwracają uwagi na to, żeby zachować te 6 bajtów.

Nie pamiętam o co dokładnie chodziło (ponad 30 lat minęło ;)), ale na 100% były jakieś sytuacje/maszyny na których taka obsługa przerwań nie działała.

trojacek:

--- Cytat: matofesi w 2021.10.15, 09:33:56 ---ale na 100% były jakieś sytuacje/maszyny na których taka obsługa przerwań nie działała.

--- Koniec cytatu ---

All-RAM?

Nawigacja

[0] Indeks wiadomości

[#] Następna strona

Idź do wersji pełnej