forum speccy.pl
ZX Spectrum => PROGRAMOWANIE => Wątek zaczęty przez: dr.df0 w 2021.10.14, 19:43:20
-
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:
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
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.
;; ========================================================
;; 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
Pozdrawiam i ciekaw jestem waszych uwag!
-
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 (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 (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?
-
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.
-
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?
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.
-
ale na 100% były jakieś sytuacje/maszyny na których taka obsługa przerwań nie działała.
All-RAM?
-
To też, ale chodzi mi po głowie jakaś wersja Unipolbrita czy coś takiego...
Sprawdziłem - ROM do TC2068, który przychodzi w pakiecie z Fuse ma kod w całym obszarze FFów - wolne miejsce jest od $3CDC do $3D00 gdzie zaczyna się generator znaków, czyli nie ma dwóch FFów w odpowiednim miejscu na żadnej z trzech stron.
-
TS2068/TC2068/UK2086 mają 24KB ROM (16K + 8K). Timexowe MMU tym rządzi i przełącza pomiędzy tymi ROMami. Część BASICa jest w dodatkowych 8K. Musiałbym zaglądnąć do instrukcji serwisowej TS2068, aby dokładnie sprawdzić mechanizm przełączania przy starcie systemu, bo jest to tam dobrze opisane.
-
Wiem, że tam jest 24 kilo, ale w tych podstawowych 16 w miejscu, gdzie są FFy jest dodatkowy kod - nie patrzyłem czego dokładnie dotyczy, po kawałkach tekstu, które widzę ("Start tape, then press any key", "Program:","Number array:","Character array:","Bytes:") z jakiegoś powodu jest tam przeniesiona część obsługi taśmy.
-
ROM TS/TC2068 był przepisany od nowa, posiada dodatkowe słowa BASICa, mechanizmy obsługi stronicowania pamięci, obsługę AYka i jeszcze kilka innych rzeczy. Stad jego rozdmuchanie do 24K i inny układ niż oryginalny. Zajrzyj do manuskryptu, tam są także odnośniki do oryginalnego ROMu Sinclaira.
https://www.speccy.pl/forum/index.php?topic=5346.msg82029#msg82029
-
Ta... Zrobiłem diff'a na rozkompilowanych ROMach - 800kilo i ponad 4000 linii różnicy ;)
Istotne w kontekście tego wątku jest to, że przy przepisywaniu nie pomyślano o zachowaniu naszych sześciu bajtów i co za tym idzie przerwania nie będą działały.
-
Dzięki za kolejny fajny wątek!
-
też dzięki za wszystkie rzeczowe komentarze - okazuje się, że po 30-tu latach, też można się jeszcze czegoś ciekawego nauczyć :)
-
No coz, do odkrycia jeszcze troche zostalo, np. jak "zrobic" floating bus na Timexie :-)
Oczywiscie bez zmian sprzetowych.
-
Przyznam, że nie bardzo rozumiem. Jak można w sprzęcie "zrobić" zmianę sprzętową bez zmian sprzętowych?
-
Czary Panie, czary!
-
Gryzor, trojacek, Klaud - proszę nie tworzyć offtopów w tym wątku.
-
jak "zrobic" floating bus na Timexie :-)
Oczywiscie bez zmian sprzetowych.
-
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?
To wszystko prawda (w sensie, że nie wiem jak z rosjaklonami). Odradzane jest (było) to rozwiązanie z powodu potencjalnej niekompatybilności w przypadku fizycznego podłączenia czegoś do szyny, jakiegoś cudactwa co sieje swoje sygnały. Rzekomo nawet dżojstik Kempston'a miał już wpływać szynę (tu już niech sprzętowcy się wypowiedzą). Czyli wracamy raczej do kwestii kompatybilności sprzętowych. W przypadku egzekucji kodu na emulatorze powinno być w pełni bezpiecznie (z dokładnością do ROMu), jak i na żywym HW, bez przystawek.
@Phonex pozdro i dzięki za poturbowanie MK 232 (ówczesny element mojej wieży turbo-korbo-stereo texniksa im. Kasprzaka). Przyspieszyłeś erte moje życie dwukrotnie xD.
-
[...] Odradzane jest (było) to rozwiązanie z powodu potencjalnej niekompatybilności w przypadku fizycznego podłączenia czegoś do szyny, jakiegoś cudactwa co sieje swoje sygnały. Rzekomo nawet dżojstik Kempston'a miał już wpływać szynę (tu już niech sprzętowcy się wypowiedzą). Czyli wracamy raczej do kwestii kompatybilności sprzętowych. [...]
Pamiętaj o tym, że jeśli Z80 przyjmie przerwanie na linii /INT uaktywnia linie /M1 i /IORQ, a przy wywołaniu portów we/wy linie /IORQ oraz /RD. Aby każdy interfejs poprawnie odczytywał zamiary procesora i był aktywny wtedy, kiedy potrzeba, musi brać pod uwagę stan /IORQ i /RD. Są interfejsy odczulone na wywołanie przerwań i "milczą" jeśli linia /M1 jest w stanie niskim. ALE w wielu oryginalnych ZX Spectrum 16K/48K miał Z80 od Ziloga z uszkodzoną linią M1 (zapewne sir Sinclair tanio kupił te niepełnowartościowe procesory), więc badanie stanu tej linii nic nie pomoże i może zaszkodzić. Ponad to mnogość różnych interfejsów oraz uproszczenia w ich konstrukcjach mogą powodować kolizje na szynie danych. Nawet taki Kempston może być problematyczny, ponieważ można go zbudować z wykorzystaniem tylko linii /IORQ i A5 w dekoderze adresów (na dwóch diodach i jednym rezystorze) z pominięciem /RD. W takim przypadku niezależnie od tego czy procesor przyjął przerwanie, czy ma zamiar odwołać się do urządzeń we/wy, o ile linia adresowa A5 będzie w stanie niskim, Kempston "rzygnie" danymi i stąd potrzeba zarezerwowania 257 bajtów na obsługę przerwań. A gdzie? Tam gdzie jest wolne miejsce w RAM, albo korzystając z obszaru z 0xFF w ROM, wedle uznania programisty.
Interfejsów zgodnych z Kempstonem powstała niezliczona ilość, a nie wiesz, co ktoś wsadził do jego wnętrza. Odwołujemy się do czasów, kiedy w "krajach wiecznego szczęścia, dobrobytu i realnego socjalizmu" kupienie czegokolwiek było wyzwaniem, a układy scalone nie były łatwo dostępne w sklepach dla hobbystów. Stosowano co było dostępne, kosztem niezgodności z przyjętymi standardami skoro działa. Obecnie, nie mamy takich problemów, ale wykopujemy interfejsy z szaf, strychów, zapomnianych skrytek i chcemy, aby one też działały "jak dawniej", stąd wyzwanie dla programistów z zapewnieniem wstecznej kompatybilności.
-
Ha, ha - dobry ten floating bus, ciekawe ile osob kuma dowcip :)
-
Gryzor- prosiłem o nie pisanie nie na temat. Offtopy zaśmiecają forum. Patrz punkt 7 regulaminu. Masz 7 dni spokoju od pisania.
-
@Phonex pozdro i dzięki za poturbowanie MK 232 (ówczesny element mojej wieży turbo-korbo-stereo texniksa im. Kasprzaka). Przyspieszyłeś erte moje życie dwukrotnie xD.
Też pozdrawiam!
Parafrazując klasyka "Mamy pańskie dema (lub demo*) i co nam pan zrobi?"
https://www.speccy.pl/archive/author.php?id=134 (https://www.speccy.pl/archive/author.php?id=134)
*Thompson czy Hacker Thompson? Mam niejasne wspomnienie że to dwie osoby...
Jeżeli Turbo Pascal 3.0 jest Twój, to sorry za wrzucenie wersji ze zwykłym loaderem - to zemsta za ubiegnięcie mnie w publikacji w demie muzyczki z Prodigy ;)
A serio - to wersja dyskowa, nie mogłem pozwolić, żeby krążyło demo z lepszym loaderem niż Zero Music 8)
A serio serio - jak wrzucałem to miałem tylko taką wersję i już nie pamiętałem że był początkowo taki fajny loader taśmowy. Znalazłem dużo później w sieci...
Sorry za offtop, nie mogłem zostawić bez odpowiedzi :)
-
TP 4.0 i ripy ZXowych muzyczek to moje. Tak było. Wiem, żenada... :\
Ale raczej nie było innych inkarnacji Thompsona. Bo hakier z niego był to raczej średnio-kiepski :/
Jakiegośtam dongla na PCcie połamałem dla kumpla-handlarza na Grzybowskiej za pomocą SoftICE'a, ale to znacznie później.