.. vim: noexpandtab fileencoding=utf-8 nomodified wrap textwidth=270 foldmethod=marker foldmarker={{{,}}} foldcolumn=4 ruler showcmd lcs=tab\:|- list tabstop=8 noexpandtab nosmarttab softtabstop=0 shiftwidth=0 :date: 2024.01.30 07:32:40 :modified: 2025.10.21 10:57:40 :tags: HW :authors: Gilhad :summary: Comp24-ideas :title: Comp24-ideas :nice_title: |logo| %title% |logo| %HEADER% Comp24-ideas -------------------------------------------------------------------------------- .. |Schema-8bitComp.png| image:: Schema-8bitComp.png :width: 250 :align: top :target: Schema-8bitComp.png * Schema-8bitComp.png |Schema-8bitComp.png| Cards -------------------------------------------------------------------------------- * Expansion card is connected via `system bus`. * Every physical card will consist of * ID - on this signal it enables its ID on data lines for Read * `74HC245` + pullups/pulldowns, set direction and Enable connected to ID signal * need for test, if card is present and what type it is * more card may return same ID, if they are of same type * I/O - basic enable for the whole card, A[0..4] select registers (may be divided between more devices) (not all must present) * `6522 VIA` - 16 regs, 2 CS - best fit - 2 may be used * `6821 PIA` - 4 regs, 3 CS - up to 4 with +1 decode * `6850 ACIA` - 2 regs, 3 CS - up to 8 with +2 decode * budu rad, kdyz se mi podari tam tuhle trojici dostat jednou, s LEDkama a s RS obvodem ono to zabere hodně místa * video * zkusil jsem `CompositeVideoTerminal `__ a chodí - co dál? Cpát to tam přez sdílenou RAM? * sdílená RAM a Arduina * Mega umí nativně rozšířenou RAM, ale potřebuje na to extra rychlý `74AHC373`, protože sdílí data a adresy * já bych spíš použil 3 porty (2xaddr+1xdata) kde to je o něco pomalejší, ale pokud to udělám ve strojáku, pořád by to mělo být dost rychle a bez chytáků * na základní video by asi stačila ATMEGA328p (UNO a pod.) se 2K+ RAM (text a pár fontů/spritů), * 1334 bytů pro text 46*29, 9*128=1.128K na půl font, může být ve flash * 2.25K na plný font * ideál je 4K+ pro text i s uživatelským fontem (pro hry) * na grafiku potřebuju asi 12K+ RAM (a velký datový tok při přenosech, možná 2 výměnné RAM?) * těch sdílených by mohlo být víc, jedna (dvě) pro video, jedna pro FS, dvě pro vypalování EEPROM, libovolně rozšiřujících * jedno arduino pro video, jiné pro FS a obecný I/O (a klidně příkazy typu I2C(123):3(45,56,78):5() - pošle 3 data, přečte 5 z dané adresy, podobně SPI, serial, PS/2 ... ) * Zajímavé obvody * `IDT7201` - FIFO - krásné, ale co s tím? HomeMegaFORTH branistorm -------------------------------------------------------------------------------- Potrebuju vymyslet (a popsat) rozhrani mezi 8bitovym pocitacem (CPU) a dvema Arduiny (A a B), ktere bude delat CPLD nazvane GLUE (jako lepidlo, ktere spojuje jednotlive casti). Ze strany CPU pujde o dve dvojice registru - (status_L, addr_L) a (status_H, addr_H) A dvojici registru pro chipy - status_A a status_B Ze strany Arduin půjde o signály privadene na jejich I/O piny Z pohledu CPU jsou v jeho pameti dve okna o velikosti 8kB (dolni (Low) na adrese 0x8000 a horni(High) na adrese 0xA000) do kterych je neco namapovane Jsou tri chipy RAM, kazdy ma 128kB (RAM_A sdilena s Arduinem A, RAM_B sdilena s Arduinem B, RAM_C pouze pro CPU) Kdyz chce CPU pouzit v nejakem okne nejakou pamet, zapise do prislusneho registru (napr. addr_L) pozadovanou adresu jako byte ve tvaru aa00bbbb, kde bity aa udavaji o ktery chip jde (00 RAM_C, 01 RAM_A, 10 RAM_B) a bity bbbb udavaji o kterych 8kB v ramci chipu pujde (4 horni bity adresy). (Důsledek - pro přirozené prázdné mapování by systém měl při startu namapovat do dolního okna 0000 0100 = 4 a do horního 0000 0101 = 5, stejně tak CPU, pokud se jen chce vzdát RAM. Na druhou stranu jiným mapováním lze přepsat i "ROM" i paměť pod "devices" i použít paměť nad 64kB) (Zda GLUE zvládne při resetu toto mapování je otázka, púředpokládejme raději stav po resetu za nedefinovaný.) (Poznámka: vzhledem ke způsobu mapování RAM_C nedochází ke kolizím, ale je možno si různě podrazit nohy zápisem do jiné části RAM - přepsat další instrukci, přepsat zásobník, zero page, nebo jakoukoli jinou nezdobu.) Nasledne CPU cte v cyklu odpovidajici stavovy registr (status_L), dokud tento neukaze, ze je mozno dotycne okno pouzivat. Stavovy registr ma nasledujici bity 000wm0c bit C je vlastneno CPU - 0 znamena pamet neni jeste pridelena, 1 pamet pridelena je M znamena modified, 1 znamena ze od minuleho prideleni byla pamet modifikovana Arduinem W je Wanted - 1 znamena, ze Arduino by do te pameti chtelo psat (treba mezitim dosla nejaka nova data zvenku) CPU take kdykoli muze cist stavovy registr chipu (status_A/status_B), s nasledujicimi bity 00dwmac bit A je vlastneno Arduinem - 1 znamena ano bit C je vlastneno CPU - 1 znamena ano M znamena modified, 1 znamena ze od minuleho prideleni byla pamet modifikovana Arduinem W je Wanted - 1 znamena, ze Arduino by do te pameti chtelo psat (treba mezitim dosla nejaka nova data zvenku) D je dirty - CPU tam zapsalo, ale Arduino to jeste necetlo Pokud CPU namapuje nejakou RAM (jakozto chip), pak mu patri az do chvile, kdy bude v obou oknech namapovano neco jineho (cimz se CPU toho chipu zase vzda) Obdobne to bude fungovat pro Arduina, Arduino si nemuze pripojit RAM, pokud ji vlastni CPU. Pokud si Arduino pripoji nejakou RAM, tak ji vlastni (a CPU si ji nemuze namapovat), dokud se ji nevzda. Kdyz si Arduino pripoji RAM, tak se predpoklada, ze ji precetlo a zapsalo. Arduino potrebuje vedet, jestli CPU do te pameti zapsalo a jestli ji CPU chce. A potrebuju pro kazde Arduino vymyslet signaly, aby to mohlo takhle fungovat (potrebuje vedet, jestli je jeho RAM volna, jestli ji CPU chce, jestli ji CPU zapsalo) A cele to nejak rozumne popsat. Big Picture -------------------------------------------------------------------------------- * `2025.10.21 11:00:32` CPU si bude s Arduinem předávat kus paměti, kam si budou psát vzkazy. CPU zadá požadavky, Arduino oznámí ne/splnění. * sdílená `RAM` je rozdělená na `BLOKy` * na jejím začátku je systémový BLOK(1), obsahující adresu prázdného BLOK(0), CPU BLOK(2) a Arduino BLOK(3/4) a možná i další systémová data * na začátku bude nějaké místo vyhrazené na stav Arduina (jako jestli má nezpracované vstupy, kolik požadavků ještě visí, kolik failnulo, kde začíná blok s jeho odpověďmi a tak podobně), bude to mít nějakou stálou strukturu, + to bude BLOK(3) pro `Arduino_A` a BLOK(4) pro `Arduino_B` * na začátku bude nějaké místo vyhrazené na stav CPU , + to bude BLOK(2) * tyto první dva BLOKy na sebe bezprostředně navazují(?) a mají pevnou(?) délku, každý zakládá vlastní řetězec * `BLOK` začíná hlavičkou (délka16,další12,segment4,typ8,reserved16)=8B a následují data délky délka16 (0..FFFF byte) * `další12` je 2B adresa v rámci 8kB s počátkem na začátku RAM/okna * `segment4` je 1B číslo 8kB bloku RAM (tohle CPU zadává při požadavku na namapování dolu/nahoru) začínající 00 (a končící 0F pro 128kB RAM) * nevyužité bity zapisující **musí** nastavit na 0 (aby čtení bylo jednoduché a nemuselo kontrolovat nic) * BLOK **může** překročit hranice i více segmentů, **neměl** by překročit vršek RAM (pokud to nastane, jde o o chybu a nedefinovaný stav - viz nasal daemons) * `typ8` je 1B číslo typu bloku, následující čísla jsou rezervovaná: * `0` - BLOK(0) je prázdný * `1` - systémový BLOK(1), obsahující adresu prázdného BLOK(0), CPU BLOK(2) a Arduino BLOK(3/4) a možná i další systémová data * `2` - CPU * `3` - Arduino_A * `4` - Arduino_B * `FF` - vyhražený BLOK (plánovaný pro případné rozšiřování typů) * o udržování systému BLOKů se stará každý uživatel, prázdné bloky se dají libovolně rozdělovat, spojovat a alokovat pro další použití, dealokace BLOKu se dělá jeho zařazením do seznamu prázdných a nastavením typu 0 * odkaz na blok 0:0 je NULL Scénář -------------------------------------------------------------------------------- Signály ================================================================================ GLUE -> CPU ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * `C_HALT` - `HALT` pro CPU, možná doprovázen `BREQ/DMA`, Active LOW * `C_DATA[0..7]` - data (oba směry) - registry CPU -> GLUE ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * `BA,BS` - pokud oba HIGH, CPU neblokuje sběrnice a DMA může běžet * `C_ADDRESS[0..15]` - adresa * `C_DATA[0..7]` - data (oba směry) - registry * `C_R/W` - požadavek na RAM/DEVICE * `CLOCK` - `E`, možná i `Q`? pro kvalifikování `C_R/W` * Arduino_A -> GLUE ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * `A_HALT` - Arduino chce zastavit CPU a udělat mu DMA * Normální stav ================================================================================ * `GLUE` převádí `CLOCK` + `C_R/W` na `R,W` pro RAM/DEVICE * `GLUE` dekóduje adresu pro RAM/DEVICE a nastavuje `RAM_C` `OE/ChipSelect` a `GA[13..15]` je podle `C_ADDRESS[13..15]` a `GA16` je `0` * `DEVICE` jsou připojené paralelně k RAM_C a mají vlastní OE/ChipSelect * `CPU` si normálně funguje, Arduina si normálně fungují a nikdo nic nesdílí/nepožaduje CPU chce použít sdílenou oblast ================================================================================ * (Analogicky pro `low`/`high` a `Arduino_A`/`Arduino_B`) * (Na začátku by měl BIOS při bootu namapovat `RAM_C`, ideálně nativně, ale stejně je lepší si to udělat v programu explicitně) * `CPU` zapíše do registru `addr_L` (nebo `addr_H`) požadovanou adresu ve tvaru `aa00bbbb` * `GLUE` při tomto zápisu: * uloží `C_DATA` do registru * ale nejdřív zkontroluje, jestli (`addr_L` a `addr_H` mají stejné `aa*` bity ) NEBO (`addr_L` a požadovaná adresa mají stejné `aa*` bity ) * pokud ne, tak odmapuje starou oblast (asi někde něco nastaví, teď `nevím`) * pokud aa==00, nastaví `status_L` (nebo `status_H`) `000wm0b` na w=0 m=0 a **c=1** čímž paměť přidělí (`RAM_C` jde vždy a Arduina s ní nic nedělají (DMA se nepočítá)) * pokud aa==11 nastane nedefinovný stav (nemáme další systém) * pokud aa==01 jde o `Arduino_A` (jinak o `Arduino_B`) * tohle se vlastně dělá kdykoli je `aa`!=0 a `A_SHARE_GRANTED` == LOW a `ownership` == `Arduino_A` * pokud je `A_SHARE_GRANTED` == LOW * nastaví `ownership` (interní RS) na CPU * upraví `status_A` * nastaví `status_L` na `status_A` (možná se přesměruje podle ownershipu?) * `CPU` příležitostně čte status_L, dokud nebude c==1 (nedostane RAM přidělenou) (Pokud mezitím zapíše do téhož registru, jde se od začátku) * číst ho nemusí, ale jen tam se dozví, zda paměť už dostal, nebo ne * CPU může žádat na obou oknech takřka naráz a pak čekat na přidělení prvního * a samozřejmě může žádat na obou to samé a dostat to, ničemu to nevadí (ale asi ani nepomáhá, i když při kopírování z jednoho BLOKu do jiného, nebo jiné podobné transformaci mají dvě okna - zdroj a cíl - docela smysl i když se náhodou sejdou) * `C_ADDRESS` ukazuje do jednoho z oken (řekněme `Low`) * `GLUE` to zjistí * pokud není c==1 tak to nějak zahodí, nebo zignoruje (nedefinovný nasal daemons) * podle `aa*` bude posílat signály tam nebo onam takto: * `A16` je výstup * první **b** jde do `A16` * ostatní jdou do `GA[15..13]` .. {{{ BOOT BOOT ================================================================================ * zapne se napájení * `Reset` linky jsou díky kondenzátorům chvilku dole, čili je signalizován Reset * `A_HALT` * pokud není `Arduino_A` připojeno, je díky pulup 100k rezistoru u `GLUE` nahoře, `C_HALT` je **nahoře=neaktivní** a vše jede normálně (viz `Po Resetu`) * pokud je `Arduino_A` připojeno je díky pulldown 3k3 rezistoru v Arduino_A dole - `GLUE` tedy nastaví `C_HALT` **dolů=aktivní** a `CPU` je haltnuté (a Reset je v CPU signalizován a uložen pro zpracování) * `C_HALT` je dole, tedy `GLUE` neřídí paměť a device podle `C_ADDRESS`, čeká na `Arduino_A` * `GLUE` nasdílí RAM_C ale Arduina nemají Shared Ram (není Selected)??? * Skončil `MasterReset`/`Reset` * Arduina bootují (bootloader, setup, ... ) chvíli se nic neděje, pak začnou jednat (`Arduino_B` nedělá nic zajímavého) * `A_SHARE_REQUEST` je defaultně stažený na LOW=nežádá o RAM_A * nastaví si `A_SHARED_SELECT` **HIGH=neaktivní** * `Arduino_A` se vzbudilo a stáhne aktivně `A_HALT` dolů (kde je díky jeho pulldownu) a začne plnit `RAM_C`, tedy `Zápis do RAM_C` .. }}} .. {{{ Zápis / Čtení RAM_C Zápis / Čtení RAM_C ================================================================================ * `Arduino_A` se vzbudilo a stáhne aktivně `A_HALT` dolů * `GLUE` tedy nastaví `C_HALT` **dolů=aktivní** (a možná i BREQ/DMA? ) a `CPU` je haltnuté (nebo brzy bude, no v extra blbém případě po asi 20 taktech CPU = IRQ, tedy asi 5 uS, pro Arduino tedy 80 taktů ) * `BA & BS` je nahoře, tedy `GLUE` neřídí paměť a device podle `C_ADDRESS`, čeká na `Arduino_A` * `Arduino_A` nastaví (a GLUE to kvůli `BA & BS` akceptuje, jinak ne): * `A_SHARED_SELECT` **HIGH=neaktivní** (ať si nepřepisuje Shared RAM) * `Shared_Address` na adresu * pro zápis `Shared_Data` na hodnotu * `A_G_A_DIR` na výstup * `A_G_D_DIR` na výstup pro zápis (na vstup pro čtení) * `A_G_ENABLE` na TRUE * když je `A_G_ENABLE` == TRUE (a `C_HALT` **dolů=aktivní**) `GLUE` nastavuje: * `A_S_ENABLE` na neaktivní * `A16` na INPUT * `GA_16` podle `A16` * `GA[13..15]` dá na HiZ (nastaví je Arduino přez 245) * `RAM_C` `R/W` podle `A_G_D_DIR` * `RAM_C` `CS` na aktivní * `G_A_DIR` podle `A_G_A_DIR` * `G_D_DIR` podle `A_G_D_DIR` * `G_OE` na aktivní * pro čtení zde `Arduino_A` přečte `Shared_Data` (čtení lze cyklit tady zapisováním nových `Shared_Address` a následným čtením `Shared_Data`)(zápis ne, kvůli neatomičnosti změn při zapnutém enable) * `A_G_ENABLE` na FALSE * když je `A_G_ENABLE` == FALSE (a `C_HALT` **dolů=aktivní**) `GLUE` nastavuje: * `RAM_C` `CS` na neaktivní * `G_OE` na neaktivní * `A16` * pustí na normální hodnoty `A_S_ENABLE`, `GA_16`, `RAM_C` `R/W`, `G_A_DIR`, `G_D_DIR` * tím je hodnota zapsána a opakuje se pro všechny další * `Arduino_A` vytáhne aktivně `A_HALT` nahoru * `GLUE` tedy nastaví `C_HALT` **nahoru=neaktivní** a `CPU` se rozběhne a pokračuje (nebo resetuje, pokud byl reset) * pokud `Arduino_A` drží `A_HALT` dole, nebere se ohled na `B_HALT` a `Arduino_B` ostrouhá a neví o tom (což může vést ke konfliktům, zvláště pokud `Arduino_B` zapisuje delší data než `Arduino_A` a tak u jeho dat platí jen konec = nadměrné zápisy) * Jak čtení, tak zápis může proběhnout i jindy než po resetu, pak to funguje jako DMA, je potřeba dát CPU čas dokončit instrukci .. }}} Zápis / Čtení RAM_A ================================================================================ * `Arduino_A` chce sdílenou paměť, nastaví tedy `A_SHARE_REQUEST` na HIGH a čeká, kdy GLUE nastaví `A_SHARE_GRANTED` na HIGH * GLUE: * `A_SHARE_GRANTED` je normálně LOW = nepřiděleno * pokud je `A_SHARE_REQUEST` HIGH a ownership (interní RS) u Arduina, drží `A_SHARE_GRANTED` na HIGH (duplicita, no action) * pokud není ownership u Arduina a bity `aaxxxxxx` v `addr_L` ani v `addr_H` nejsou `01*` přehodí se ownership na Arduino a nastaví se `A_SHARE_GRANTED` na HIGH