Počítače s procesorem Capricorn: přednáška Bytefest 2022

Odkaz ke stažení prezentace z přednášky na akci Bytefest.

Již tradičně přináším ke stažení v .pdf prezentaci z Bytefestu.

První byla v roce 2014 přednáška Historické počítače s videoprocesorem TMS 9929A.

Po ní následovala přednáška z roku 2019 na téma MSX 2 a Turbo-R (k ní jsem nevydal samostatný článek, ale informace o obou platformách jsou rozptýleny ve více starších článcích a videích).

Nyní je na řadě přednáška letošní, z roku 2022, její .pdf si můžete stáhnout ZDE.

Přednášku můžete shlédnout ve videu na YouTube kanálu ByteFestu ZDE (bohužel nevkusně přerušenou novým bootováním prezentačního notebooku).

Na Bytefestu byly ke shlédnutí dva exempláře počítačů popisované řady, HP 85B a HP 86B, bohužel přítomnost velkého množství počítačů a snad rušení v rozvodné síti znemožnilo práci s disketovými jednotkami, takže předvedení programu demonstrujícího možnosti, hlavně grafické, proběhlo až po odjezdu velké části účastníků, kdy se elektromagnetické podmínky zlepšily.


Zdroj

Počítače s procesorem Capricorn (kozorožec).

Poněkud kryptický název přednášky jsem volil ze dvou důvodů – jednak přiznat rovnou, že jde o Hewlett Packard series 80, řekne si každý, že už ví, o co jde, a ztratí zájem; druhak ten procesor je tak zajímavý, že je přednáška více o něm a méně o samotných počítačích.

Series 80 přišla v době prvotního boomu osobních mikropočítačů, na trhu už bylo TRS, Commodore PET, Atari, Apple II a chystalo se IBM PC, tedy počítače primárně do kanceláří, malých laboratoří a potažmo domácností.

Series 80 se díky sběrnici HP-IB umožňující připojení různých měřících přístrojů (HP vyráběl i plynový chromatograf) prosadila především v laboratořích, výzkumu a průmyslu, přesto šlo i o jeden z prvních “strojů na VisiCalc“, na které byl portován první tabulkový procesor (ve dvou různých verzích pro 32 a 80 znaků na řádek) a mohly se tak uplatnit v kancelářích.

Při vývoji Series 80 šlo o zlevnění a zjednodušení řady 98xx, což byly šestnáctibitové pracovní stanice pro konstrukci a grafiku (na HP 9845C vznikala grafika pro film WarGames, Válečné hry).

Series 80 sestávala ze tří řad modelů.

První zahrnovala HP 83, HP 85A, HP 85B, HP 9915A a HP 9915B, druhá HP 86A a HP 86B, třetí HP 87 a HP 87XM.

Procesorem Capricorn byly osazeny i kalkulačky s jazykem Basic HP 75c a HP 75d.

HP 83 mělo 16 KiO RAM, nemělo zabudovanou tiskárnu a datovou pásku (používající kazetky D100), HP 85A bylo osazeno rovněž 16 KiO RAM, ovšem s tiskárnou a páskovou jednotkou, HP 85B mělo 64 KiO RAM (z nichž využívalo 32 a zbytek pak jako elektronický disk) a kromě tiskárny a páskové jednotky osazenu i Mass Storage ROM (pro připojení disketových jednotek přes HP-IB interface) a I/O ROM (pro ovládání paralelní brány přes GP IO interface).

HP 83 a HP 85 byly osazeny integrovanou malou CRT obrazovkou.

Počítače HP 9915A a HP 9915B byly průmyslovými verzemi počítačů HP 85A a HP 85B do racku, jako jediné ze series 80 byly osazeny i ventilátorem, byly bez tiskárny, pásková jednotka a externí klávesnice tvořily volitelné příslušenství, byly ale osazeny LED a přídavnými tlačítky, ovladatelnými pomocí Development ROM (dala se objednat i pro klasické HP 85), monitor šlo připojit externí.

Řada HP 83/85 nebyla osazena konektorem pro HP-IB sběrnici (byl potřeba modul interface).

Řada HP 86 obsahovala model HP 86A osazený 64 KiO RAM, rozhraním Centronics pro připojení tiskáren a řadičem pro připojení dvou disketových jednotek HP 9130, model 86B byl osazen 128 KiO RAM (nadbytečnou využíval jako elektronický disk) a místo tiskárenského portu a diskového řadiče měl sběrnici HP/IB.

HP 86 neměl obrazovku zabudovanou a využíval externí monitor (zajímavé je, že dodávané monitory HP měly i zvukový vstup, který ale HP 86 nevyužívá).

Řadu 87 tvořil model HP 87 se 32 KiO RAM a HP 87XM se 128 KiO RAM, oba modely měly sběrnici HP-IB a zabudovanou poměrně velkou širokoúhlou CRT obrazovku.

Počítače obsahují oddělený textový a grafický režim (pokud vypíšete text a přepnete se do grafiky, text zmizí, po vykreslení grafiky a přepnutí zpět na textový režim zmizí naopak grafika a objeví se text, který předtím nebyl vidět).

Řada HP 83/85 má 32 znaků na řádek, 16 řádek (výška znaku 12 bodů), rozlišení grafiky 256×192 bodů.

HP 86 a 87 disponují 80 znaky na řádek, 24 řádky (nebo 16 řádků po softwarovém přepnutí), grafikou 544×240.

Externí ROM do ROM modulů nejsou záměnné, pro HP 83/85 jsou označeny bílými nápisy, pro HP 86/87 žlutými nápisy.

HP 85 sloužil jako předloha pro Tesla PMD 85 (proto ta shoda čísel), nešlo ale o kopii architektury, ale jen o inspiraci schopnostmi počítače (grafické možnosti a příkazy, které byly přiroubovány k NASCOM Basicu od Microsoftu, který byl určen jen pro textový režim, a tak vytvořen Basic-G, nebo implementace sběrnice IMS-2, jakési napodobeniny HP-IB, ke které se připojovala i původní disketová jednotka MFD-85).

Co se spolehlivosti počítačů týče, pokud je někde najdete a po vyčištění zapnete, pravděpodobně budou bez problému fungovat.

Jedinými slabými místy jsou pryžové kolečko pohánějící pásku v mechanice HP 85 nebo HP 9915 a zdroj řady HP 87, který přeci jen tahá kromě počítače i větší interní CRT.

K provozu CP/M existoval CP/M interface, obsahující procesor Z80 (HP od roku 1981 do 1985 vyráběla i počítače Series 100 pro provoz CP/M s dvěma procesory Z80).

Systémová ROM má 32 KiO, obsahuje Basic.

24 KiO ROM je napevno a 8 KiO se stránkuje spolu s externími rozšiřujícími ROM, kterých může být až 254.

RAM je takřka 32 KiO, na konci adresového prostoru je oblast vyhrazená pro I/O zařízení.

Při tvorbě procesoru vycházeli u HP z několika premis:

Akumulátor je “hrdlo flašky”, bottleneck, nejužším místem určujícím propustnost systému.

Práce s vnitřními registry proocesoru je rychlejší než práce s RAM.

Jeden zásobník pro běžnou práci nestačí.

Vidíme, že je tedy potřeba řešit podobné problémy, jaké řeší moderní procesory, třeba RISC s širokou registrovou sadou.

K tomu si tvůrci přidali propozice:

Propustnost systému zvýší možnost práce s většímu datovými objemy (více registry) naráz.

Zásobníky by měly být libovolně rostoucí nebo klesající, při možnosti práce s více údaji naráz by měly mít možnost je adresovat indexovaně a tím moci vytvářet seznamy.

Síla procesoru je taková, že i při běhu na taktovací frekvenci 0.613 MHz jde o počítač na svou dobu výkonný (Apple ][ mělo 1.023 MHz, Atari 800 1.79 MHz).

Vnitřně používá procesor dva šestibitové registry DRP (data registr pointer) a ARP (address register pointer), ukazující do pole 64 registrů.

Dále je zde čtyřbitový extended registr E, účastnící se mimo jiné rotací, a příznaky.

64registrové pole je rozděleno zarážkami, první polovina, 32 bajtů, na dvojice po 16 bitech, druhá polovina na 4 oblasti po osmi bajtech (každá 64 bitů).

Některé registry mají zvláštní funkci, registr 0 složí podobně jako DRP a ARP jako pointer do pole registrů.

Registr 1 není normálně pomocí DRP a ARP adresovatelný a dá se adresovat jedině pomocí registru 0.

Registrový pár 2 a 3 slouží jako index registr X (hodnota vytvořená z baze a offsetu se uloží do dvojregistru X a touto hodnotou v registru je pak adresována buď hodnota v paměti, nebo pointer v paměti ukazující na hodnotu).

Dvojregistr 4 a 5 je programový čítač.

Dvojregistr 6 a 7 je zásobník návratových adres a je vytvořen jako rostoucí k vyšším adresám.

K mnoha instrukcím existuje jednobajtová a vícebajtová varianta.

Vícebajtové pracují tak, že zpracovávají data z registrů pointovaných ukazatelem DRP nebo ARP až k nejbližší zarážce, pokud tedy DRP ukazuje na počátek osmice, zpracuje se celá osmice, pokud na poslední bajt před zarážkou, zpracuje se jen ten.

Výjimkou jsou instrukce skupiny multi-byte shift right (logical / extended), které rotují doprava a tudíž sestupně k nejbližší nižší zarážce.

Podobně pracují instrukce s dvěma parametry, zpracovává se oblast pointovaná ukazateli DRP a ARP, a to až k zarážce, výsledek se ukládá do jedné z nich, obvykle pointované DRP.

Instrukce load a store mezi registry způsobují jen přenos dat, ale jejich multibajtové varianty nejsou záměnné.

Liší se tím, že load provádí přenos až k zarážce cílové oblasti, zarážky v oblasti zdrojové zcela ignoruje, zatímco store provádí přenos k zarážce oblasti zdrojové a ignoruje zarážky oblasti cílové.

Příznaky jsou k dispozici tyto:

• registr E (4bitový extend register), využívá se mimo jiné při rotacích a v podmínkách skoků.

• DCM – příznak decimal mode (BCD)

• CY – carry, příznak přenosu

• OVF – overflow, příznak přetečení

• LSB – least significant bit (ten s nejnižší hodnotou) při jednobajtovém zpracování

• MSB – most significant bit (ten s hodnotou nejvyšší)

• Z – zero, příznak nuly

• LDZ – left digit zero, při multibajtovém zpracování stav nibblu (4 bity, jedna BCD číslice) na pozici nejvyšší hodnoty

• RDZ – right digit zero, při multibajtovém zpracování stav nibblu na pozici nejnižší hodnoty

Assembler je poněkud mimozemský a chová se trochu jinak než jak to známe dnes.

Na diapozitivu jsou uvedeny dva příklady:

60 LBL LDMD R70,R40
70 Label jsb=numval
80 PUBD R52,+R12
90 PUND 52,+12
100 CLB R40 !THIS IS A COMMENT

a druhý

LDB R0, = 26
LDB R*, R30
STB R40, R*

Pokud se podíváme na první, máme tam návěští LBL, instrukci LDMD (load multi-byte direct) s dvěma parametry.

Dá se čekat, že po přeložení na adrese určené návěštím LBL najdeme operační kód instrukce LDMD.

Ale ten tam ve skutečnosti nebude.

Najdeme-li kód této instrukce v přeloženém kódu, dá se očekávat, že za ním budou následovat parametry.

Ale není tomu tak, ve skutečnosti za operačním kódem instrukce LDMD bude rovou následovat kód další instrukce, tedy JSB (skok na podprogram).

Následuje dvakrát instrukce PUBD (push byte direct) se dvěma parametry, ve kterých najdeme i znaménko plus, jako by se cosi z parametrů mělo sčítat.

Při provádění instrukce se ale sčítání neprovádí.

Obě pushovací instrukce jsou zapsány každá jinak, ale opravdu se přeloží jinak?

Parametry R20 nebo R40 si můžeme ještě vysvětlit jako registr 20 či registr 40, ale co pak kryptické zápisy R* nebo dokonce R#, případně pokud ve zdrojáku místo R40 najdeme X40?

Za některé tyto efekty jsou odpovědné dvě zvláštní instrukce.

Instrukce ARP a DRP uloží hodnotu do registrů ARP a DRP.

Kód instrukce ARP je (oktálově) 000-077, nebo 0xx, kde xx je číslo registru v bance registrů, na který má ARP ukazovat.

Výjimkou je instrukce ARP 1, tedy instrukce s operačním kódem 001, která způsobí, že nebude zpracováván registr ukazovaný ARP, ale registrem R0.

Proto pomocí ARP nelze přistupovat k registru R1, který je tím přístupný pouze přes adresování registrem R0 (kdy R0 = 1).

Podobně u instrukce DRP je (oktálově) kód 100-177, nebo 1xx, kde xx je číslo registru v bance registrů, na který má DRP ukazovat.

Výjimkou je opět instrukce DRP 1, tedy instrukce s operačním kódem 101.

Proto ani pomocí DRP nelze přistupovat k registru R1, který je opět přístupný pouze přes adresování registrem R0 (kdy R0 = 1).

Adresování registrem R0 se zapisuje právě jako R*.

Kódy ostatních instrukcí jsou pak (oktálově) v oboru 2xx a 3xx.

Ve zdrojových textech programů se instrukce ARP a DRP obvykle nevyskytují.

Jsou jen v přeloženém kódu, do kterého je překladač doplňuje automaticky.

Programátor může překladač donutit vynechat instrukci ARP nebo DRP parametrem R#.

Instrukci LDB R40, R50 tak přeloží jako 140 050 240 (DRP 40, ARP 50, LDB).

LDB #R,R70 vynechá DRP, přeloží tedy jako 070, 240 (DRP 70, LDB).

LDB R#,R# pak přeloží jako 240 (samotné LDB).

Pokud ale překladač vidí, že registry ARP nebo DRP jsou už naplněny správnými hodnotami, příslušnou instrukci ARP nebo DRP nevygeneruje.

Tak PUBD R10,-R6 : POBD R10,-R6 (což je push a pop pracující s klesajícím zásobníkem R60, hodnota je v registru R10) vygeneruje kód 110 006 346 342 (DRP 10, ARP 6, PUBD, POPD).

Pokud je ovšem použito návěští, překladač negarantuje obsah ARP a DRP a tak po návěští instrukce ARP a DRP vygeneruje.

Například PUBD R10,-R6 : LBL POBD R10,-R6 přeloží jako 110 006 346 110 006 342 (DRP 10, ARP 6, PUBD, DRP 10, ARP 6, POPD).

Pokud programátor neurčí jinak, například PUBD R10,-R6 : LBL POBD R#,-R6 se přeloží jako 110 006 346 006 342 (DRP 10, ARP 6, PUBD, ARP 6, POPD).

Režimů adresování má procesor několik.

Lze adresovat registrem, a to bezprostředně (registr obsahuje hodnotu), přímo (registr tvoří pointer na adresu v paměti obsahující hodnotu) nebo nepřímo (registr tvoří pointer na adresu v paměti obsahující adresu paměti obsahující hodnotu).

Při adresování literálem se literál uvozuje znakem =, ukládá se jako parametr za kód instrukce (na kterou ukazuje PC).

Adresuje buď bezprostředně (hodnota je za kódem instrukce), přímo (za kódem instrukce je adresa hodnoty v paměti) nebo nepřímo (registr tvoří pointer na adresu v paměti obsahující adresu pointeru v paměti obsahujícího adresu hodnoty v paměti).

Při indexovém adresování se používají tři parametry, v tom druhém se indexující registr (obsahující offset) neoznačuje R, ale X, třetí je literál obsahující bázi.

Součet hodnoty báze (počáteční adresa tabulky, je uložena jako parametr za kódem instrukce) a offsetu (je v indexujícím registru) se uloží do registrového dvoupáru 2, 3, tedy do indexregistru X, jehož hodnota se použije jako adresa v paměti, která buď obsahuje hodnotu (přímé adresování) nebo ukazatel na adresu obsahující hodnotu (nepřímé adresování).

Instrukce load a store mohou být tedy jednobajtové nebo vícebajtové (podle šířky dat ke zpracování) s adresováním bezprostředním, přímým (D – direct), nepřímým (I – indirect), což dává 12 kombinací LDB, LDBD, LDBI, LDM, LDMD, LDMI, STB, STBD, STBI, STM, STMD, STMI, které ještě rozšiřuje možnost adresování indexem.

Instrukce se zapisují jako na Z80 jménem instrukce “INSTR kam, co” nebo při indexovém adresování “INSTR kam, Xco, odkud”.

Instrukce push a pop (PU, PO) jsou rovněž jednobajtové (B) nebo vícebajtové (M), se zásobníkem klesajícím (ten značí – před označením registru zásobníku) nebo rostoucím (označený +), adresováním přímým nebo nepřímým, což dává 8 kombinací.

Při nepřímém adresování neobsahuje zásobník přímo hodnoty jako při adresování přímém, ale ukazatele na hodnoty v paměti.

Provádění rotací se liší podle toho, zda se prování v režimu binárním nebo dekadickém (BCD).

V binárním se účastní carry a rotuje se po bitu, v BDC režimu se účastní čtyřbitový E registr a rotuje se po nibblech.

Při logical shift vstupuje do rotace nulový bit nebo nibbl a vysouvá se do carry nebo E, při extended shift vstupuje do rotace aktiální hodnota carry nebo E, do kterého se pak při rotaci cyklicky vysouvá nová hodnota.

Rotace jsou jednobajtové nebo vícebajtové, vlevo nebo vpravo – ELB a ELM extended left shift, ERB a ERM extended right shift, LRB a LRM logical right shift a LLB a LLM logical left shift.

Registrová sada obsahuje i instrukce pro sčítání ADB, ADM, ADBD, ADMD, logický and ANM a ANMD, porovnání CMB, CMM, CMBD, CMMD, logický or ORB a ORM, odčítání SBB, SBM, SBD, SBMD a xor XRB, XRM.

Instrukce pro dekrementaci DCB, DCM pracují tak, že přičítají dvojkový nbeo desítkový doplněk (v závislosti na zvoleném režimu), inkrementace ICB, ICM přičítá jedničku dvojkovou nebo BCD, instrukce pro doplňky jsou k dispozici jak pro jednotkový či devítkový NCB, NCM, tak dvojkový či desítkový TCB, TCM.

Pak jsou tu instrukce testu TSB, TSM, mazání CLB, CLM, instrukce přepínající binární a desítkový režim BIN a BCD.

Instrukce pracující s registrem E jsou CLE pro mazání, DCE pro dekrement a ICE pro inkrement.

Instrukce SAD a PAD uloží nebo vyzvednou ze zásobníku obsah registrů ARP, DRP a příznaky (bez E registru).

Instrukce skoku na podprogram je JSB, při indexovaném adresování zapisovaná JSB X v parametru.

Jako zásobník návratových adres (rostoucí k vyšším adresám) slouží registrový pár R6 (tedy registry 6, 7).

Při indexovaném aresování se sečte adresa v parametru za kódem instrukce s AR, na výslednou hodnotu se skáče.

Instrukce RTN způsobí vyzvednutí návratové adresy ze zásobníku R6 a návrat z podprogramu.

Pak jsou tu instrukce skoků.

Nepodmíněný JMP a skoky podmíněné.

Zvláštností jsou JPS a JNG (jump on positive/negative), což je xor MSB a příznaku přetečení, JOD, JEV (lichá / sudá), k nim se přiřazují skoky podle dalších flagů včetně E (JEZ, JEN), celkem 16 instrukcí skoků.

Nyní tedy známe dost na to, abychom dokázali přečíst ukázkový zdroják.

BIN
JSB =ONER
LDM R50,R40
LDM R40,=1,0,0,0,0,0,0,32C
JSB =SUB10
POMD R70,-R12
LDM R50,=0,0,0,0,0,0,0,50C
JSB =MPY10
POMD R70,-R12
LDM R50,R40
LDM R40,=0,0,0,0,0,0,0,90C
JSB =DIV10
RTN

Jde o část rutiny, rozšiřující Basic o příkaz pro převod stupňů Fahrenheita na Celsia (C=(F-32)*5/9).

Instrukce BIN přepne na binární režim (který vyžaduje rutina ONER v ROM).

JSB =ONER zavolá podprogram ONER v ROM (načtení parametru, hodnoty ve Fahrenheitech), literál je uvozen znakem =.

Následuje instrukce LDM R50,R40.

Nyní víme, že se přeloží jako DRP 50, ARP 40, LDM.

Hodnoty jsou v osmičkové soustavě, přenese se tedy osmice bajtů (parametr načtený rutinou ONER do R40).

Dále následuje naplnění R40 druhým potřebným parametrem, číslem 32.

LDM R40,=1,0,0,0,0,0,0,32C

Víme, že se přeloží jako DRP 40, LDM, následuje 8 bajtů dat, kterými se v jedné instrukci naplní 64bitová osmice registrů.

Jde o číslo ve formátu floating point se znaménkem, mantisou a exponentem, který zpracovává ROM.

Jako soustava je uvedeno C, což není ani dvojková, ani šestnáctková, ani osmičková, ba ani desítková soustava, ale BCD.

32D (desítkově) by se uložilo jako 0010000, zatímco v BCD se rozloží do nibblů jako 00110010.

Následuje JSB =SUB10, skok na podprogram v ROM pro odčítání (F-32).

Rutina uložila nepotřebnou hodnotu na zásobník R12, který je klesající, hodnotu z něj odstraníme (popnutím do nepotřebného místa v registrech): POMD R70,-R12, přeloží se jako DRP 70, ARP 12, POMD-.

Pak je to podobné už předchozímu, do registru R50 naplníme číslo 5.

LDM R50,=0,0,0,0,0,0,0,50C

Víme, že se přeloží jako DRP 50, LDM, následuje 8 bajtů dat.

Opět se celých 64 bitů naplní do registrů v jedné instrukci.

JSB =MPY10 skočí na rutinu násobení (*5).

POMD R70,-R12 opět odstraní nepotřebnou hodnotu na zásobníku R12 vyzvednutím do nepotřebného registru R70.

LDM R50,R40 přesune výsledek násobení z regustru R40 do registru R50, opět všech 8 bajtů jednou instrukcí.

Víme, že se přeloží jako DRP 50, ARP 40, LDM.

Následuje naplnění další hodnotou, LDM R40,=0,0,0,0,0,0,0,90C, potom opět zavolání rutiny v ROM, JSB =DIV10, která provede dělení (devíti).

RTN vyzvedne návratovou adresu (ze zásobníku návratových adres R6) a vrátí se tam, odkud byla volána (do kódu, který výsledek převodu zpracuje).

No a to je tak nějak všechno.