Kereken egy éve (2017 szeptembere), hogy rábukkantam Ben Eater videó sorozatára a YouTube-on, amiben egy 8 bites CPU megalkotását mutatja be több mint 40 videón keresztül.
Mindezt olyan részletességgel és mindenre kitérően magyarázza el, hogy biztos vagyok benne, hogy az elektronikában laikusok is megértik és akár reprodukálhatják is ezt a “kis” gépet.
Nem véletlen az idézőjel, hiszen ahhoz képest, hogy ez túlnyomórészt csak egy CPU, 14 próbapanelen terül el!
Miután végignéztem a videókat és annak ellenére, hogy még magam sem értettem meg mindent, már biztos voltam benne, hogy egy ilyet én is akarok építeni!
Mindig is érdekelt a processzorok belső felépítése, hogy mégis mi történik a számítások és az utasítások végrehajtása közben, milyen módon képes elvégezni a feladatokat…
Nosza, gondoltam, vágjunk hát bele, úgy is mindjárt itta tél, kell valami hobbi a hideg hónapokra! :)
Első körben be kellett szereznem azt a temérdek alkatrészt ami kell a projekthez.
A gép túlnyomó része a 74LS sorozatú TTL IC-kből építkezik, ami elég elterjedt a 8 bites gépek világában, de más helyeken is megtalálhatóak, ahol TTL szintű logikai kapukra van szükség.
Ezeket az IC-ket ide haza is könnyen be lehet szerezni, minden nagyobb elektronikai áruházban.
Persze a gépnek vannak speciális IC-i, mint a memória, vagy az adder, illetve az EEPROM-ok. Ezekből nem is találtam Magyarországon megfelelőt, így maradt az e-bay.
Még ezek megérkezésére vártam, ami közel egy hónap volt, addig tanulmányoztam a videókat, és az IC-k működését. Ez hasznos időtöltésnek bizonyult, mert kapcsolási rajzot Ben nem készített, így valóban csak a videók és az elmondottak alapján lehet építeni.
Szerencsére a belföldi rendelés pár napon belül megérkezett. Ezekből pedig már lehetett ezt-azt összelegózni, még vártam az e-bay-es csomag befitására.
Első körben az a modul készült el, ami nélkül egy CPU sem menne semmire a tudásával: az órajel generátor.
Ennek az alapja a szintén elég elterjedt
NE555-ös időzítő IC.
Az órajel sebessége egy potméter segítségével szabályozható, illetve átkapcsolható manuális módba. Ekkor egy gomb megnyomásával mi magunk adhatunk ki órajelet, ami főleg debugolás esetén tud hasznos lenni.
Így hát meg is volt az első sikerélmény: Villog a LED, tehát van egy működő órajel generátorom! :)
Miután megérkeztek külföldtől a maradék alkatrészek is, folytattam az építkezést az alábbiakkal:
A, B regiszter: Feladatuk annak két 8 bites értéknek a tárolása amivel műveletet fog végezni az ALU. Próbáltam minél helytakarékosabb lenni, így ezt a két regisztert, ami 6 IC-ből áll, egy panelre sűrítettem. Szerencsére pont jól elfért.
A képen az A regiszter látható.
ALU: Ahogy a nevéből is következik (Arithmetic Logic Unit) ez végzi a számítási és logikai műveleteket. Ennek lelke a két 4 bites adder IC, ami az A és B regiszterben tárolt értékeket vagy összeadja, vagy kivonja, attól függően majd mit szeretnénk.
PC, azaz Program Counter: A memória címek lapozásért, illetve az ugrásokért felel. Lelke egy 4 bites bináris számláló IC. Mivel 4 biten számol, azaz maximum 15-ig, ezért a kezelhető memória mérete 16 byte összesen! :)
Memória: Mivel a Program Counter 4 bites, így memóriából is csak 16 byte került be.
Ez azonban bővel elég ebben az alapgépben, mert a programozást kézzel kell majd végezni, két DIP kapcsoló segítségével.
Az egyikkel beállítjuk a memória címet (4 biten) amire írni szeretnénk, a másokon pedig a tartalmát (8 biten). Kapcsoló fel: 1, kapcsoló le: 0
Majd egy gomb megnyomásával beírjuk az értéket a kiválasztott címre.
Mit ne mondjak, rettenetesen szenvedős úgy programozni, hogy a memória címeket és az utasításokat, bináris számként kell kapcsolgatni! Igaz 16 byte-on még pont képes ezt az emberi agy ezt kezelni. :)
Instrukciós regiszter: Ebbe a regiszterbe kerül az épen aktuális utasítás a memóriából és mindaddig itt marad, még végrehajtásra nem kerül. Lényege, hogy tárolja az utasítást a mikrokódot tartalmazó EEPROM-ok számára, még azok nem végeznek a végrehajtásával, közben különféle memória műveleteket is lehessen végezni.
Mikrokód vezérlő: Ez az egység felel a gép minden egyes részegységek vezérléséért (Memória, Program Counter, ALU, Regiszterek, stb. ). Amikor egy parancs bekerül az interakciós regiszterbe, az tulajdonképpen egy címre állítja az itt található EEPROM-ok négy (4 bit) cím bemenetét.
A maradék cím bemenetet (3 bit) pedig a Program Counter modulban is használt bináris számláló címzi, méghozzá minden órajelnél eggyel nagyobb értékkel.
Ez teszi lehetővé, hogy egy utasítás több órajel alatt (maximum 8) végrehajtható legyen.
Szegmens kijelző: Hogy a műveletek kimentettét barátibb formában is lássuk, ne csak binárisan LED-ek segítségével, rendelkezik a gép négy darab szegmens kijelzővel is. Az első kijelzőn csak a – (mínusz) jel jelenhet meg ha a szám negatív, míg a másik három a 0-tól 255-ig való szám kijelzésre szolgál.
Erről sajnos csak egy kissé homályos képet találtam.
LED-ek: A gépben nagy szerepe van a LED-eknek, még ha nem is a működést tekintve, de jól láthatóvá teszik az adatok mozgását, változását, aktuális értékeket.
Minden regiszter, ALU, memória és még a kontroll szignál vezetékek is kaptak LED-es visszajelzést.
Nos, ezek kerültek a Ben-féle gépébe, amit első körben megépítettem. A végeredmény pedig az alábbi képen látható.
Sajnos erről a kezdeti verzióról nem rendelkezem jobb képpel.
A gép tudása összefoglalva:
- 16 byte RAM
- Szegmens kijelző
- Manuális kapcsolós programozás
- Matematikai műveletek: Összeadás, kivonás
- Utasításkészlet: ADD, SUB, JMP, LDA, LDI, STA, OUT, HLT, NOP
Az utasításokról részletesebben később még lesz szó.
Sok-sok munkaóra volt mire megépítettem és hibátlanul működött, de végül nagyon öröm volt látni, ahogy egy egyszerű Fibonacci számsor számítást tudott futtatni a gép! :)
Ez volt tehát a Ben-féle gép megépítése, de nem ez jelentette az igazi kihívást. Jöjjön most a keményebb része a dolognak!
Építés közben rengeteg ötletem volt, hogyan és mivel lehetne ezt az alapgépet fejleszteni és még többet kihozni ebből a koncepcióból.
Bele is fogtam, ekkor már mindenféle iránymutatás nélkül a továbbfejlesztésekbe, amik nem mindig mentek zökkenőmentesen, de amit sikerült elérnem, arra még én sem számítottam!
Lássuk hát sorjában mik ezek a fejlesztések.
Memória bővítés
Első a memória mérete volt, amin mindenképp változtatni szerettem volna, mert hát valljuk be, 16 byte az roppant kevés bármire is.
Beszereztem egy új RAM IC-t, ami 16 biten címezhető, és 8 bites kimenete van. Így hát lepucoltam a már meglévő memória modult és bedrótoztam az új IC-t.
A 16 cím lábból 8 ment a buszra, a másik 8 pedig használaton kívüli lett, mert ugye ez egy 8 bites gép, nincs szükség többre és nem is tudtam volna kezelni többet.
Elméletben ez már 8 bites címzés, azaz 256 byte a memória, de gyakorlatilag a Program Counter még mindig 4 biten pörög, így továbbra is 16 byte-ot tudtam elérni.
Ezt sem nagy ördöngösség megoldani, csupán ki kellett egészíteni a PC-t még egy bináris számláló IC-vel, hogy 8 biten számoljon, azaz így már 255-ig.
Meg is történt a módosítás, így most már teljes 8 biten mehetett a memória címzés.
A mikrokódon is jócskán kellett alakítani, hogy kezelni tudja a teljes 1 byte-os utasításokat és az újabb 1 byte-os operandusokat, de ezzel nem volt különösebb probléma.
Az utasítás kezelés régi verziója ugyanis 4 biten reprezentálta magát utasítást és a maradék 4 biten az operandust. Ennek hátránya, hogy maximum 16 utasítás lehet. Bár ez ott ugye elég volt.
Nálam most teljes 1 byte-os utasítások lehetnek, így ezekből maximum 256 darab. Operandus szintén lehet 1 byte-os, és igazából semmi akadálya multi byte-os operandusoknak sem. Igaz ilyen parancsom még nem nincs, aminek egynél több kellene.
Tesztelés képen be is “írtam” egy közel 20 bytos programot a kis DIP kapcsolókkal és örömmel konstatáltam, hogy működik. Legalábbis ha 20 byte-on működik, akkor biztos 256-on is :)
Programozás
Volt tehát 256 byte memóriám így a következő fejlesztés már adta magát: Kellene valami megoldás, amivel gyorsabban tudok programokat betáplálni, mert a DIP kapcsolós megoldással egy komolyabb programot beírni agyrém lenne, főleg ha valamin még módosítani kell közben.
Meg is született az elképzelés, miszerint párhuzamos (LPT) porton keresztül, PC-ről fogom betölteni a programokat!
A párhuzamos portnak szerencsére van 8 bitnyi adat szála és még négy kontroll szála is. Nem is kellet nagyon más, mint egy 74LS245-ös busz meghajtóval a gép adatbuszára kötni a port 8 bitjét. A kontroll szálakat pedig némi logikai IC támogatásával a memória címzés és írás megvalósításához használtam fel.
Így gyakorlatilag a gép legtöbb elemét megkerülve közvetlen a memória IC-be tudtam pumpálni az adatokat a porton keresztül.
Ehhez írtam egy egyszerű progit, ami a programot tároló fájl tartalmát (hexadecimális kódok egymás után) sorba betölti a gép memóriájába.
Szépen működött is a dolog, de még nem volt elég felhasználóbarát, hiszen a programokat továbbra is binárisan kellett megírni, sőt még át is váltani hexába és úgy elmenteni a fájlba, majd betölteni.
Ekkor megszületett az ötlet, hogy milyen jó lenne egy Assembly fordító, amivel kvázi már magas szinten tudok programozni a gépre!
Keresgéltem univerzális és viszonylag egyszerű fordítókat, és végül rábukkantam a CustomASM nevű fordítóra. Ennek az a legnagyobb erőssége, hogy bármilyen processzorhoz illeszthető. Létre lehet hozni egy utasítás leíró fájlt és abban sorban felvenni az utasításokat amiket a CPU használ, valamint megadni, hogy fordításkor milyen hex kód legyen ezek kimenete.
Illetve egy csomó frappáns dolgot tud, ami elég hatékonnyá teszi a fejlesztést olyannyira, hogy el lehet végre felejteni a bináris számokat való programírást!
Fel is vettem azt a néhány parancsot amit akkor ismert a gép és máris mehetett a kódolás Assembly nyelven.
Jelenleg ez az utasítás definiálós fájl így néz ki.
Viszont én még mindig nem láttam elég felhasználóbarátnak ezt a megoldást, mivel a fordító és a betöltő is csak parancssorból volt használható. Ezért ezt a két eszközt egyesítettem egy programban, ami már grafikus felületen tette lehetővé a kódolást, fordítást és a betöltést is.
A bal oldali részben az assembly forráskód, ami a jobb felső részen lévő gombokkal fordítható, illetve betölthető a gép memóriájába.
Alatta pedig hexadecimálisan is lehet látni a lefordított kódot, valamint némi debug eszköz is helyet kapott lentebb.
Mivel a gyakorlatban is remekül működött már a fordítás/betöltés, így ismét átalakításra került a memória modul. Leszedtem minden DIP kapcsolót és az ezeket érintő áramköröket. Ezzel végleg leszámolva a manuális programozással! Sejthetitek, nem is hiányzott ez már ezek után! :)
Kijelző
Szuper, hogy már volt 256 byte memóriám és saját fordítóm, program betöltővel, de mit lehet ekkora memóriával kezdeni, ha csak számokat jelezhetek ki 0-tól 255-ig?
Egy összeadásban, vagy számsor számolásban nem sok érdekes van ugye…
Szemezgettem már különféle LCD kijelzőkkel és végül meg is rendeltem egy kétsoros (2×16 karakter) kis kijelzőt.
Az egyik jó tulajdonsága hogy 4, vagy 8 biten is lehet vele kommunikálni, így elvileg simán illeszthető az én gépemhez is.
Nos igen, sikerült is az illesztés, de az út ami odáig vezetett, hogy szépen működjön is, nem volt egyszerű.
Rengeteg drótozás és logikai IC beiktatása kellet, hogy végül kommunikálni tudtam vele.
Így nézett ki egy kísérleti megvalósítás akkoriban:
A kijelző önmagában még nem használatra kész ha áram alá helyezzük, mivel még inicializálni is kell. Ezt könnyen meg lehet tenni 4 byte-nyi utasítással, amit át kell neki adni. Viszont pont ez volt az egyik probléma, hogy hogyan inicializáljam a gép bekapcsolásakor. Mert bár programból is meg lehetett volna ezt tenni, de nem tetszett az az elgondolás, hogy minden programnak a kijelző inicializálásával kellett volna kezdődnie.
Másik probléma az volt, hogy a kijelző a karakterek megjelenítéséhez BCD kódot használ, még nekem bináris számaim vannak 8 biten.
Az alapgépben a szegmens kijelzők vezérléséhez már használva volt egy EEPROM, így ezt alapul véve, módosítottam ennek tartalmán LCD vezérléshez. Kvázi egy Binary→BCD dekódert készítettem.
Kapott a kijelző modul is egy bináris számláló IC-t, ami a gép bekapcsolásakor 4 biten végigpörgeti az EEPROM cím bemenetét, majd leáll a számlálás.
Ezen a belapozott területen van az LCD inicializáló kód, amit igy megkap a kijelző, ezáltal hazsnálatra késsen áll. Sőt még maradt is pár byte-om, így belefért egy OK üzenet kiíratása is!
Tehát a gép bekapcsolása után szépen inicializálódik a kijelző és megjelenik az OK felirat, illetve a gépen lévő reset gomb megnyomására szintén lefut ez, ezzel törölve mindent ami a kijelzőn látható, resetelve ezt is.
A decimális számok BCD-re való átalakításáért tehát az EEPROM felel.
A nyolc cím bemeneten megkapja a bináris számot, és a maradék három cím lábat használja a helyi értékek lebontásához. Ezt a három lábat a mikrokódokat tartalmazó EEPROM-ok vezérlik közvetlenül, attól függően milyen kijelzőt érintő parancsot adok ki, amelyek a következők lehetnek:
- LCD – Parancsot adhatunk át a kijelzőnek, tehát minden olyan utasítást amit maga a kijelző ismer. Például ugrás a következő sorba, kurzor pozicionálása, sor törlése…
- OUT.d: Decimális kijelzés. A kiírandó számot ekkor bontja le az EEPROM három BCD kódra és adja át sorba a kijelzőnek.
- OUT.c: Karakter kijelzés. Ekkor nincs decimális lebontás. A 8 biten konkrét karakter BCD kódját lehet a kijelzőnek átadni.
Flag regiszter
Szuper, van temérdek memória, fejlett karakteres kijelző, de ez még mindig kevés ahhoz, hogy komplexebb programokat tudjak létrehozni, ugyanis feltételeket nem tudok írni, mert nincs mihez feltételeket kötni. :)
Ez volt tehát a következő amin változtattam!
Feltételes ugrásokat akkor lehet csak csinálni, ha van valamink amire tudunk hivatkozni mint feltétel. Ehhez pedig szükség van egy úgynevezett Flag regiszterre, amiben az ALU-ban lévő érték bizonyos tulajdonságait tároljuk.
Ehhez az A, B regiszterekben is használt 4 bites regiszter IC-t vetettem be, csak itt a 4 bit értéket maga az ALU állítja be, amikor kiszámolásra kerül egy érték.
A beállításra kerülő flag-ek az alábbiak lettek:
- Zero flag: Igaz, ha a szám 0
- Carry flag: Igaz, ha a szám nagyobb mint 255 (unsigned int)
- Negative flag: Igaz, ha a szám negatív (unsigned integer)
- Overflow flag: Igaz, ha a szám -128 és 128 között van (signed int)
Az egyes flag bitek akkor igaz állapotúak, ha a logikai áramköri megvalósítás erre állítja őket.
Példának okáért vegyük a legegyszerűbb esetet a zero flag beállítását. Ehhez csupán 8 dióda kellet az ALU 8 bitjére, amelyek kimenete közösítve van. Tehát ha szám nem nulla, akkor igaz értéket kapunk (van áram a közösített kimenetelen), ami igaz pont nem jó, mert nekünk akkor kell igaz érték, ha a szám 0 (nincs áram). Ehhez csak egy hex inverter IC kellet, ami pont a fordítottját adja vissza a bemenetnek (1→0, 0→1).
Így ennek az IC-nek a kimenete már mehetett a Flag regiszter első bitjére, ami így igazat (áramot) kap ha a szám 0. Ha pedig nem 0 a szám, akkor értelem szerűen a flag értéke 0 lesz.
Hasonló elven működik a másik három flag értékének beállítása is, azaz a megfelelő bitek vannak összefésülve, hogy megkapjuk a flag értékeket (0 vagy 1).
Maga a flag regiszter kimenete egy AND logikai kapura csatlakozik. A kapu másik fele pedig a mikrokód EEPROM-okra, kimenete pedig a Program Counter Jump bemenetére.
Ez azt eredményezi, hogy ha ugrani szeretnék valahova, – például abban az esetben ha egy szám értéke 0 -, hogy a mikrokód EEPROM áram (igaz) alá helyezi az AND kapu első bemenetét, és ha a flag regiszter áram (igaz) alá helyezte a másik bemenetet (tehát 0 a szám), akkor az AND kapu igaz kimenetet fog adni, ezzel áram alá helyezve a Jump logikát a Program Counterben, ami így ugrani fog a programban megadott címre.
Lehet így szárazon kicsit bonyolultnak hangzik, bocsi! :) A valóságban ez mindössze két IC, amik a jobb oldalon láthatóak. Bal oldalon pedig maga a Program Counter.
Ez lenne tehát a feltételes ugrások logikája, amivel háromféle ugrást valósítottam meg. Ezek a következő assembly utasításokkal használhatóak:
- BEQ: Ugrás a megadott memória címre ha a szám 0
- BCS: Ugrás a megadott memória címre ha a szám nagyobb mint 255
- BMI: Ugrás a megadott memória címre ha a szám negatív
Bekerült még egy CMP, azaz összehasonlítást végző utasítás is, ami tulajdonképpen kivonja az A regiszer értékéből a B regiszter értékét és az eredménytől függően beállnak a flag regiszter értékei.
Ha az eredmény 0, akkor az azt jelenti, hogy egyenlő a két szám, egyébként pedig nem. Erre már lehet a fent említett BEQ utasítást használni, hogy akkor ugorjuk x címre, ha a két szám megegyezik azaz egyenlő.
Mikrokód
Még mindig hiába a sok fejlesztés, hiszen a mikrokód közben nem sokat változott és nem igazán tudja kihasználni a fejeltebb hardvert! :)
Egyrészt jó lett volna ha minden utasítás többféle címzési módban használható, másrészt jó lett volna, ha a jelenlegi 16 kontroll szignálnál több is lenne, mert a Flag regiszter esetében már csak a BEQ-ra maradt elég kimenet az EEPROM-okon.
A mikrokód két EEPROM-ban volt tárolva, azon okból kifolyólag, mert a kontroll szignálok nem mások, mint ezen IC-k kimenetei, amiből egy chipen nyolc van.
Hogy legyen még több vezérlési kimenetem, kibővítettem ezt a részt még két EEPROM-mal, így már 32 kontroll szálam lehetett maximum, ami bőven elégnek tűnt akkor!
Átalakítottam a mikrokódok működését is, hogy a 8 helyett már 16 órajeles is lehessen egy utasítás végrehajtási ideje, ami összetettebb utasítások esetén jól jön majd később.
És persze a fontosabb utasításoknak többféle címzési módot is adtam. Például az összeadás kétféle címzési módon történhet:
Van még az Implied mód, amit olyan utasítások használnak, amiknek nem kell operandust megadni, mint pl. a HLT (megáll az órajel generálás), vagy a NOP (tétlenség). Ezek fixen 1 byte-ot foglalnak.
A jelenleg legfrissebb mikrokód itt látható. Ez egyben az EEPROM égető kód is, amiket Arduinoval szoktam a chipekbe írni, egy kisebb elektronikai körítéssel. Mivel az Arduinonak nincs annyi digitális kimenete amennyi kellene az EEPROM-ra, ezért két serial to parallel shift regiszterrel lett megvalósítva plusza néhány kimenet.
A mikrokód fejlesztés kapcsán merült fel bennem, hogy az is hasznos lejhetne ha tudnék subrutinokat írni, mivel azokkal rengeteg kódismétlést meg lehetne spórolni egy programnál, ami ennyi memóriánál azért fontos szempont.
Ennek a koncepciója elég egyszerű elgondolású lett. Mivel a memóriám 16 bites, de én csak 8 biten címzem azt, és mivel maradt még 8 bitem, így erre alapoztam meg egy 1 byte-os stacket kivitelezését.
Azaz ha a stacbe akarunk tenni egy címet, akkor a memória címzésnél a mikrokód a RAM 15. címét állítja csak igazra, és erre a címre írja be azt a címet ahol épen a Program Counter áll. Ezt a JSR (Jump to SubRoutine) utasítás teszi lehetővé.
Visszatéréshez a RTS (ReTurn from Subroutine) használható, aminek hatására a mikrokód a stackben eltárolt címet visszatölti a Program Counterbe, majd ehhez hozzáad 1-et. Így a PC az az utáni címre fog ugrani, ahonnét a subrutin meghívásra került, ezzel folytatva onnét a fő programszál futását.
Persze mivel 1 byte-os stackről beszélünk, nem lehet egymásba ágyazott subrutin hívásokat kezdeményezni, mivel ahhoz már egy stack pointert is kellene építeni, ami eléggé megbonyolítaná a már így sem egyszerű elektronikát.
Valamint olyan összetett programot szerintem nem fogok írni, ami ezt indokolná. De aztán még ki tudja, lehet kap egyszer egy tovább fejlesztést a stac is!
Kontroller
Most, hogy már szinte mindenem volt, ami egy komplexebb program megvalósításához kellet, felmerült a kérdés, hogy jó, de mit írjak rá!? :)
Megvoltak az egyszerű számolásos programok, elágazásokkal stb, de az ugye nem túl izgalmas és látványos. Kellet valami felhasználói interakciót is belevinni a dologba!
Gondoltam, ezek után csak nem olyan nagy dolog egy kontrollert hozzábillenteni a rendszerhez!
Rendeltem e-bay-ről (honnét máshonnan :) ) egy vacak, utángyártott Nintendo kontrollert. A vacak szó szerint értendő, mivel már eredeti állapotában sem működtek jól a gombok. De mivel az ára ~800 Ft volt, nem is vártam tőle sokat.
Igazából nem volt gond, mert én az egész elektronikát kicseréltem benne mikrokapcsolókra. A gép felől pedig a már jól ismert 4 bites regiszter IC került be, ami a lenyomott gombok bináris kódjait hivatott tárolni.
A koncepció tehát elég egyszerű: Ha lenyomunk egy gombot, akkor az áramot ad a regiszter IC egyes bemeneti lábaira.
És mint tudjuk 4 biten 16 szám tárolható, így ez ennek a 8 gombnak elég ez az egy IC. Igaz ez kizárja azt, hogy billentyű kombinációkat is lehessen használni, de ez most még nem is volt cél.
Mikrokód szinten bekerült egy IPR (Input Port Read) utasítás, ami ennek a regiszternek az értékét áttölti az A regiszterbe. Ezután erre az értékre már a korábban említett CMP / BEQ párossal lehetett feltételt írni.
Azaz ha megnyomjuk például a felfele gombot, aminek értéke 4 és a vizsgált érték is 4-et adunk meg, tehát ha egyenlő a két szám, akkor az azt jelenti, hogy igen, felfele gombot nyomtunk, ugorhatunk egy subrutinra.
Egy kis videó a kontrollerről, amit egy gyorsan összedobott gyűjtögetős játékon teszteltem.
Dátum-idő és szorzás
Időközben találtam egy régi alaplapot, amin felfedeztem egy 4 bites RTC IC-t. Kicsit tanulmányozva az adatlapját, gondoltam ezt egyszerűen be lehetne drótozni az én gépembe, miért is ne alapon.
Ki is forrasztottam és pár alkatrész (kristály, kondi, elem) társaságában már ketyegett is az óra!
A dátum és az idő értéket 4 biten, helyi értékenként adja vissza úgyhogy kicsit trükkös a kezelése, ha netán az órát, vagy a percet 8 biten szeretnénk tárolni.
Ugyanis meg kell szorozni az óra első számjegyét tízzel, majd hozzáadni a másodikat.
Pl.: 1 * 10 + 2 = 12 óra
Oké, de a gépem nem tud szorozni! :)
Szerencsére nem volt nagy kunszt egy bal irányú bit eltolás utasítást írni a mikrokódba, mert az tulajdonképen egy szám saját magával való összeadását jelenti.
Például:
2 → 0010
2 + 2 = 4
4 → 0100
Máris 1 bittel balra tolódott az érték.
Így hát lett egy ASL (Arithmetic Shift Left) utasításom, ami már majdnem jó, hiszen a szám kettővel való szorzását végzi el. Ha ezzel kétszer eltolunk egy értéket balra, majd hozzáadunk kettőt, akkor az megfelel a tízzel való szorzásnak.
Persze azt is lehetett volna, hogy a számot tízszer összeadom, de az nagy kódot és sok processzor időt eredményezne és nem is túl elegáns megoldás.
Tehát lett egy kis extra hardverem, ami sok pluszt nem ad ugyan a géphez, de nagyon jó mondjuk egyszerű random szám generálásház.
És persze a bit eltolást is hasznos volt kifejleszteni, mert még jól jön majd pár programban. A jobbra való eltolást nem valósítottam még meg, mert azt osztással lehetne csak, amit jelenleg nem tudom, hogy tudnék kivitelezni egyszerűen. Ezt majd az egyik továbbfejlesztésben megpróbálom megoldani.
Természetesen az RTC kezeléshez is kellet pár saját assembly utasítás, ezek a következők lettek:
- RTR: Real Time Read – Dátum/idő kiolvasása a chipből.
- RTW: Real Time Write – Dátum/idő írása a chipbe.
Burkolat
A gépben ekkora már fél évnyi munka volt, és ezalatt végig az asztalomon terült el és bizony a por nem kímélte ezalatt. Azt gondolom mondanom sem kell, hogy milyen rámállom takarítani egy ilyen konstrukciót. Ecset, porszívó, törlőkendő…
Itt volt az ideje valami burkolatot csinálni neki, ami megvédi a portól, könnyen mozgathatóvá teszi, de mégis jól szerelhető marad.
Kis találtam mi legyen a megoldás. Felül, illetve körbe fa burkolat, a tetején pedig egy levehető plexi lap!
Elugrottam hát a legközelebbi Praktikerbe és megvettem mindent ami ehhez kell.
Íme egy kis képcsokor ennek készítéséről és végeredményéről.
Ezen helyet kapott hátul egy tápcsatlakozó, kontroller port, program betöltő port.
Elöl pedig a Halt/Run kapcsoló, manuális órajel generátor gomb, reset gomb és egy három állású kapcsoló, amivel három-féle sebesség választható az automatikus órajel generáláshoz.
Eközben meg is kapta a gép, a roppant frappáns ANDOR nevet, ami az angol AND, OR szavakból ered! :)
Ez is felkerült hát a burkolatra és ettől fogva a projekt is ezt a nevet viselte.
A végleges gép
Egy kis tudás összehasonlítás Ben gépe és ANDOR között, avagy miből lett a cserebogár.
A jelenleg használható utasítások és jelentésük.
Akik annak idején, vagy netán manapság is foglalkoznak Commodore gépekkel, azoknak ismerősek lehetnek a feni utasítások jó része.
Mivel én is elég sokat kódoltam C64-en assemblyben és elég jól ismerem magát a gépet is, így az utasítások megalkotásában a C64-et vettem alapul.
Gyakorlatilag tehát aki tud C64-re programozni assemblyben, az tud ANDOR-ra is! ;-)
Végül ezen a képen látható minden IC, ami jelenleg be van ültetve. Ez a nagyon hasznos Fritzing nevű programmal készült, amivel egyszerűen lehet próbapaneleken áramkörüket tervezni.
Árok party
Nem titkolt célom volt, amikor már láttam a fényt az alagút végén, hogy az idei (2018) Arok Partyra kivigyem a gépet és amellett, hogy élőben demózzam, még a Wild Compoba is benevezzek vele. Mert hát valljuk be, mi a vad, ha nem ez? :)
Mit ne mondjak, álmomban sem gondoltam volna, hogy akkora sikert fog aratni a gép, hogy egész nap kíváncsiskodók hada fog körbevenni és faggatni róla, hogy mi ez, hogy működik, mit tud, hadpróbálja ki… :)
Külön öröm volt, amikor néha egy-egy apuka, vagy anyuka is megtalált a gyerkőccel, aki nekiállt az ugrálós játékkal játszani!
Bár volt aki megjegyezte: „Jah, csak ennyi!?” – Oké, hát nem fut rajta még a FarCry, bocsi :D
Miután mindenki látta aki szerette volna és elérkezett az este, elindultak a különféle kategóriák anyagainak vetítési, köztük a Wild composoké is.
Végül ebben a kategóriában ANDOR a 2. helyezést zsebelhette be.
Külön erre a rendezvényre készítettem egy videót a gépről, ami igyekszik emészthető formában bemutatni a vasat.
Kicsit részletesebb Arok Party beszámolót itt olvashattok tőlem.
Jövőbeli tervek
Van pár! :) Ezek egy részét már el is kezdtem fejlesztgetni, csak még az ANDOR-ba nem építettem be őket. Ennek egyik oka, hogy majd a fél gépet szét kell robbantani és újra építeni. Ezt megelőzően viszont szeretnék minden modulról kapcsolási rajzot készíteni, ami nagyban meg fogja könnyíteni az összerakást.
Az egyik nagyobb fejlesztés a memória címzés 16 bitre való bővítése lesz. Ehhez a Program Countert kell majd 16 bitesre alakítani, valamint felhasználni a memória IC mind a 16 cím bemenetét és persze a mikrokódot is elég jól átírni, hogy kezelni tudja majd a 2×8 bites címzést.
Mivel az adatbusz marad 8 bites (nem akarok még 8 drótot mindenhova :) ), így a 8 biten felüli memória kezelés kétlépcsős lesz. Először az alsó 8 biten adjuk át a címet a memóriának, második lépésben pedig a felső 8 bitet. Ugyanez lesz az eljárás ha a Program Counternek kell átadni egy címet.
Ezzel ugyan ki fog esni a stack, ami jelenleg a memória modul 15. címén érhető el, de ez majd kap egy külön regisztert, az még bővel elfér majd.
Így a maximálisan megcímezhető memória mérete 64 KB lesz, ami gyakorlatilag mindenre elég! :)
De mit is lehet majd csinálni ilyen temérdek memóriával?
Nos a második nagyobb fejlesztés az a kijelző cseréje lesz. A jelenlegi kijelző csak karaktereket tud megjeleníteni a saját karakter készletéből, illetve amit még én definiálhatok benne, és ebben ki is merül a tudása.
Az új kijelző viszont teljesen grafikus lesz, 128×64 pixeles felbontással.
Tehát akár monokróm képeket, animációkat, játékokban spriteokat is meg tudok rajta jeleníteni, amikhez kell majd a sok memória.
Emellett ez is tud karakteres módot is, így a szöveges kijelzés is adott lesz továbbra is. Sőt, a két mód keverhető, így akár egy rajzra egyszerűen lehet szöveget elhelyezni.
Már Arduinoval tesztelgettem és szuperül működik a kijelző. Mehet lassan be a régi helyére, ami persze az egész kijelző logikai vezérlésének átalakításával fog járni.
Harmadik nagy fejlesztés a hang lesz! Mert hát mégis milyen 8 bites számítógép az amivel nem lehet egy jó kis chiptune muzsikát tolni? :)
Nos ehhez is már be van szerezve minden, ami kell. A lelke egy SN76489 nevezetű IC lesz, ami egy 8 bites, 4 csatornás hang generátor.
A kijelzőhöz hasonlóan már ezt is tesztelgettem Ardiunoval, oly sikeressen, hogy igazából ez is kész az ANDOR-ba való integrálásra.
Kapott egy kis erősítő áramkört is, így majd a belső hangszórón is jól hallható lesz, de természetesen csatlakoztatható lesz rá fejhallgató, vagy külső hangfal.
És hogy hogy fog szólni? Így!
Ez a három nagy fejlesztés van jelenleg kilátásban, amik reményeim szerintem még idén megvalósulnak.
Nem lesz kis munka, mivel a gép eddigi részeit is kicsit újra kell gondolni hozzá.
Példának okáért a kontroll szignál vezérlés négy EEPROM-ja nem lesz már elég, ezért kellene egy ötödik. Ennyit viszont már nem szeretnék, sőt, inkább csökkenteni az EEPROM-ok számát. Így a kontroll szignál vezérlést is át fogom alakítani pár multiplexer beiktatásával. Cél a maximum két EEPROM, de egynek örülnék igazán!
Továbbá a program betöltő is teljesen újra lesz gondolva. Sőt, már ennek is kész a prototípusa.
A párhuzamos portot leváltom soros portra. Igaz, hogy több elektronika kell így a kezeléséhez, de amit nyerek vele azért megéri.
Párhuzamos porton való program áttöltéshez ugye a host gépen is kell hogy legyen párhuzamos port. Oké, a PC-mben van egy LPT kártya és Árokra is egy olyan laptopot vittem, amin van van, de azért ez nem valami univerzális megoldás manapság.
Soros porthoz viszont lehet kapni USB→RS232 átalakítót, vagy egy egyszerű FTDI panelt.
Én jelenleg egy FTDI panelel oldottam meg az USB→Soros átvitelt.
Tesztek alapján remekül működik, már ez is része lehet a gépnek.
Végül pedig kapni fog egy új burkolatot is, hiszen megváltoznak a kivezetések és újak is bekerülnek. Illetve kozmetikailag is próbálok majd még szebb drótelvezetéseket kivitelezni.
Jelenleg ez minden ami tervbe van véve! Nem is tervezem ennél már jobban bonyolítani, mert átláthatatlan lesz és nem is szeretnék egy mindenre alkalmas gépet készíteni, hiszen akkor soha nem végeznék, valahol meg kell húzni egy határt.
A 2019-es Arok Party-n pedig újra látható lesz a már remélhetőleg végleges ANDOR!
Szeretnél még többet megtudni?
Tudom, elég hosszú lett ez a kis fejlesztési történet és minden tiszteletem a tiéd hogy elolvastad!
Ha érdekelnek a jövőbeli fejlesztések és figyelemmel kísérnéd ANDOR tudásának fejlődését, akkor iratkozz fel a YouTube csatornámra!
Ha még mélyebben szeretnéd beleásni magad a hardveres / szoftveres részletekbe, akkor kövess GitHub-on is.
Ez a repó szinte állandóan változik és jelenleg leginkább saját magamnak gyűjtöm ide a dolgokat. Viszont igyekszem majd ezt a részt is érdekessé tenni a látogatók számára is!
Szeretnéd a kapcsolási rajzokat is nézegetni? Nincs akadálya, itt megnézheted őket.
Ezek a rajzok szintén folyamatos alakítás, feltöltés alatt vannak. Idővel minden elkészül és felkerül ide!