Navigátorposledních 10 z diskuze |
Kdyby tisíc přerušeníV tomto článku nahlédneme na používání přerušení C64 jiným než nejběžnější způsobem, avšak nejedná se zdaleka o kompletní popis všech možností přerušení. Nejčastější používání přerušení na C64 je IRQ vyvolávané rasterem, jehož spouštěcí rutina může vypadat nějak takto:
Mnozí jistě tuto rutinu znají, takže pro začátek kontrolní otázka: co přesně dělá instrukce STA $DC0D a proč tam je? Obvod 6526, v C64 použitý jako CIA1 a CIA2
VIC a CIA1 vyvolávají IRQ přerušení, jehož vector (pointer) je na adrese $FFFE (a při zapnutém kernalu se provádí nepřímý skok přes $0314). CIA2 je zdrojem NMI přerušení, které má vector na $FFFA (a při zapnutém kernalu se provede nepřímý skok přes $0318). VIC dokáže vyvolat přerušení v momentě, když raster paprsek dojede na hlídanou řádku, když se srazí dva sprity, když se srazí sprite a pozadí a když přijde signál od světelného pera. V jakých případech se má přerušení vyvolat, se nastavuje na adrese $D01A: Interrupt control register $D01A.
Příkaz:
aktivuje vyvolávání přerušení závislého na rasteru. Potom se do adres rasteru ($D012 a nejvyšší bit $D011) musí zapsat hlídaná řádka a až na ní raster dojede, vyvolá IRQ. Kdyby tam bylo LDA #$07, vyvolávalo by se IRQ nejen rasterem, ale i srážkou spritů mezi sebou a s pozadím. Aby bylo možné odlišit, co bylo příčinou vyvolání IRQ, musí se v IRQ přečíst adresa $D019, jejíž bity mají stejný význam jako na adrese $D01A: Interrupt status register $D019.
Bit7 má hodnotu 1, pokud alespoň jeden z dalších stavových bitů má také hodnotu 1. To znamená, že pokud je zdrojem IRQ VIC, nastaví se bity 0-3 (podle toho, co bylo příčinou) a zároveň se nastaví bit 7. Takže je možné pro počáteční větvení programu použít instrukce BMI/BPL, jestli zdrojem IRQ je VIC, nebo něco jiného. Pro další vyvolání přerušení je nejdříve nutné potvrdit, že to předchozí již bylo zpracováno. To se dělá zápisem na adresu $D019 a význam bitů 0-3 je totožný jako při čtení. Proto se na konci IRQ, které je vyvoláváno pouze rasterem, píše INC $D019 v naději, že se změní hodnota registru z $00 na $01 (a tím potvrdí zpracování IRQ vyvolaného rasterem). Na C64 to funguje, ale správně by se mělo psát:
Pokud na adrese $D019 není potvrzeno zpracování přerušení, nebude další vyvoláno i v případě, že nastala událost, která ho má znovu vyvolat. Kromě VICu může IRQ vyvolávat také CIA1. V principu je použití stejné, jen přístup k registrům je trošku odlišný. Stále se jedná o IRQ, jehož vector je na adrese $FFFE (a potažmo $0314). V jakých případech má CIA1 vyvolat IRQ se nastavuje zápisem na adrese $DC0D: Interrupt control and status register $DC0D. Write bits:
CIA vyvolá přerušení, pokud doběhne jeden z jeho dvou časovačů (A a B), TOD (Time Of Day) doběhl do hlídaného času (alarm), byla přijata data na seriové lince CIA a nebo signál na pinu FLAG. Do této adresy se nezapisuje tak jako do adresy $D01A, že bit s hodnotou 1 znamená zapnutí příslušné funkce a 0 její vypnutí. Hodnotu, kterou chceme některému z bitů nastavit, nastavíme v bitu 7 a bity 0-4, které mají hodnotu 1 převezmou tuto hodnotu. Bity 0-4 s hodnotou 0 zůstanou bez změny. Pro příklad:
nastaví bity 0-4 na nulu, takže se vypnou všechny signály CIA1, které by vyvolávaly IRQ. Příkaz
nastaví bity 0 a 1 na hodnotu 1, čímž CIA1 začne vyvolávat IRQ, pokud doběhne časovač A nebo B. Bity 2-4 zůstanou bez změny. Pokud mají časovače CIA vyvolávat přerušení, musí se nastavit jejich čas a spustit odpočet. Nejčastější použití CIA časovače na C64 je pro přehrávání samplů. Čas časovače A se nastavuje na adresách $DC04-$DC05. To může vypadat nějak takto:
nastaví čas na hodnotu $0080. Časovač B by se nastavoval na adresách $DC06-$DC07 a jednotka času je jeden takt procesoru. Tuto hodnotu $0080 časovač začne odpočítávat a až doběhne na nulu, vyvolá přerušení, což v tomto případě bude každých $80 taktů procesoru. Časovače CIA běží přímo v těchto obvodech nezávisle na okolí, takže nejsou odstavovány VICem na badline a v místech načítání spritů, tak jako CPU. Samotný běh časovače A se pustí na adrese $DC0E (časovač B má adresu pro spuštění $DC0F a její význam je totožný): Timer A control register $DC0E
Aby časovač začal odečítat, musí se zapsat:
Bit 0 s hodnotou 1 zapne časovač, bit 3 s hodnotou 0 aktivuje kontinuální běh (kdyby byl 1, časovač byl odpočítal jednou a zůstal zastavený) a bit 4 s hodnotou 1 při startu nastaví aktuální hodnotu času z adres $DC04-$DC05 (pokud by byl časovač stopnut ještě před tím než doběhl, zůstane v něm aktuální hodnota a aby při dalším startu začal počítat od začátku, zajistí tento bit). Když je vyvoláno IRQ obvodem CIA1, musí se přečíst jeho status a potvrdit zpracování. Obojí se děje přečtením adresy $DC0D, pořadí a význam bitů je stejný jako při zápisu: Interrupt control and status register $DC0D. Read bits:
Když se v rutině IRQ napíše:
přečte se status a zároveň se tím potvrdí jeho zpracování. To má za následek, že další čtení této adresy vrací 0, dokud nepřijde nějaký další signál vyvolávající přerušení. Proto je nutné si pro další zpracování tuto hodnotu po přečtení uložit. Bit 7 (podobně jako u VICu a adresy $D019) signalizuje, že zdrojem přerušení je CIA1 a kontrolou bitů 0-4 se zjistí, o jaký se konkrétně jedná signál.
Na závěr bych ještě zmínil, že NMI je nadřazeno IRQ, při výskytu v jeden moment má přednost. A nelze ho deaktivovat instrukcí SEI. Pokud během rutiny přerušení nastala mezitím opět událost, která ho má vyvolat, je přerušení po instrukci RTI vyvoláno znovu. Detailní popis registrů jsem si vypůjčil z této stránky: http://sta.c64.org/cbm64mem.html
CIA1 je používán Basicem a po resetu časovač A vyvolává IRQ. Aby se tato funkce odstavila a nekolidovala s přerušením vyvolávaném VICem, zajistí příkaz:
Pro vypnutí všech přerušení od obou CIA obvodů, nezávisle na předchozím stavu, by se mělo psát:
Na konci článku je uveden zdrojový kód programu, který využívá pro přerušení raster a všechny 4 CIA časovače.
|