Showing posts with label intel 8080. Show all posts
Showing posts with label intel 8080. Show all posts

Wednesday, January 11, 2017

NCD85 5. ATA interface

Vianočný čas som už tradične využil na bastlenie. Odladil som radič a jednoduchú testovaciu aplikáciu pre posledný doteraz neotestovaný konektor na NCD85v2. Má 40 pinov, určený je pre IDC konektor. Rozhranie má 16 dátových bitov, realizovaných portmi A a B. Ďalej má 2+3 adresové linky, plus linky na zápis a čítanie. Konkrétne sa jedná o IDE alebo Parallel ATA rozhranie realizované obvodom 8255 a zopár invertormi. Zapojenie je dnes už klasika v 8-bitovej retro technike.

Ako základ som vzal kód od Paula Stoffregena. Trochu som ho vylepšil, rozšíril ale hlavne prepísal do ASM pre 8085. Testovať som začal s CF kartami, a keď to už fungovalo tak som zapojil aj nejaké IDE disky. Mám zopár 16MB CF kariet a tie sa mi zdajú ideálne. Max veľkosť disku pre CP/M je cca 8MB, takže si viem predstaviť PCčkoidné CP/M, kde by boli dve disketové jednotky A: a B: a dva disky po cca 8MB C: a D: realizované jednou 16MB CF kartou.

Screenshoty z aplikácie
CF karta EMTEC 16MB

CF karta SILICON POWER 512MB

3.5" Disk 340MB, MAXTOR 7345AT bez LBA adresovania a bez 8-bitových prenosov


Sťahovať sa dá ako vždy na GitHub.

Monday, January 25, 2016

NCD85 4. MUART 8256 - 8080 Interrupts

Odskúšané, famózné, úžasné, ono to fakt funguje. 8256 dokáže spracovávať INTA signál a v správnom okamihu poslať na zbernicu patričnú RST inštrukciu. Paráda. Na skúšku som spustil 16-bitový timer T24, nastavil mu 1ms takt, 5000 ako začiatočnú hodnotu a bum. Po 5s sa vyvolalo prerušenie RST 6, blikla INTA LEDka a spustila rutina na obsluhu prerušenia. V nej je potrebné znova nastaviť timeout a v mask registri zase povoliť prerušenie od T24. To preto lebo prerušenia od timerov v 8256 sú iba jednorázové, hneď sa vypne príslušný bit v mask registri, aby nedochádzalo k opakovanému spúšťaniu. Ďalšia podivná vec je, že timer dopočíta do nuly a potom pretečie a ide od FFFF .. preto treba nastaviť aj novú začiatočnú hodnotu timeoutu.

Krásne to bliká, pretože na kratulinký signál INTA je pripojená "predlžovačka" impulzov 74123. Takže v takte 5s na mňa pomrkáva LEDka. Vyskúšal som aj prerušenie od sériového portu. Podľa očakávania, pri príjme znaku sa vyvolá príslušná rutina RST 4 a samozrejme blikne INTA LEDka.

Updatol som fotky v blogu o NCD85 1. Floppy radič, teraz sú už s takmer plne osadeným NCD85.

Pri ladení a testovaní prerušení som objavil chybu popisky na NCD. Popiska pri JUM4 je naopak, v polohe RST7.5 je v skutočnosti INT a naopak. Doplnil som to aj v blogu o NCD. Uvedomil som si ešte jeden zádrhel s konfliktným pripojením INTA signálu do PCF8584.

PCF8584 totižto tiež vie prerušovať a generovať RST inštrukciu. Zatiaľ to ani najmenej nevadí, pretože PCF používam ako I2C bus mastera a v polling režime. Ale ak by som niekedy chcel aby PCF8584 fungovalo aj ako slave (zatiaľ nechcem, napadá ma iba jedno jediné praktické využitie), tak by bolo vhodné aby pri oslovení iným masterom vyvolalo prerušenie CPU. Ak by niekto mal iba PCF8584 bez osadenej 8256, tak nie je žiadny problém. Jumper JUM3 sa nastaví na PCF (popiska INT). PCF pošle žiadosť o prerušenie a pri signále INTA vygeneruje RST 0 a všetko funguje ako má.

Ale pri osadení obidvoch obvodov PCF8584 aj 8256, sa musí kaskádovať prerušenie z PCF do vstupu EXTINT na 8256. Jumper JUM3 sa prehodí na polohu 8256. Vtedy je signál INT z PCF vedený do EXTINT vstupu 8256. Následne 8256 vygeneruje signál INT ktorý je pripojený na vstup CPU. A pri prijatí prerušenia na CPU by chceli obidvaja reagovať na signál INTA. A to by bol konflikt. Pri signále INTA som na jumper nemyslel. Tak sa asi bude musieť preškriabnuť INTA do PCFka .. a v software sa pollne interrupt register 8256, aby sa detektlo že ide o externý interrupt z PCFka. Vstup INTA na PCF mal ísť na jumper a mal sa dať voliť medzi VCC a signálom INTA z CPU.

Saturday, January 9, 2016

NCD85 2. I2C bus

A je to hotové :-) Vianočný čas už "tradične" využívam na bastlenie a hobby. Môj odhad na rozbehanie I2C controléra PCF8584 bol 3 dni. Nakoniec to trvalo viac ako dvojnásobok. Musel som sa uchýliť k mojej obľúbenej sofistikovanej debugovacej vedeckej metóde LED. Pripojil som LED na obidva vodiče SDA aj SCL a až vizuálne som odhalil kde sa to seká. (DS1307 sa rád zatne a zablokuje celú zbernicu).

Čo je I2C? Je to zbernica od Philips určená na komunikáciu čipov. Má dva vodiče, SCL a SDA a samozrejme zem. I2C umožňuje pripojiť veľké množstvo rôznych senzorov, pamätí, prevodníkov a displayov atď. Napríklad senzor tlaku, vlhkosti, teploty, kompas, senzor zrýchlenia, senzor ..? Alebo chceme pripojiť LCD (rozšírený je I2C backpack s PCF8574), rozšíriť počet vstupných a výstupných portov? Pripojiť jednu, dve, tri 256kB EEPROM? Nie je problém :-) A najlepšie na tom je, že všetky zariadenia sa pripojujú na tie isté dva vodiče. Nie je treba žiadne ďalšie vstupy/výstupy.

Na doske NCD85 je LM75 (alebo LM75A, TMP275), DS1307 a EEPROM rady AT24C. TMP275 je teplomer s rozlíšením až 0.0625°C a presnosťou 0.5°C v rozsahu od −20°C do 100°C. Je to lepšia alternatíva k "industry standard" LM75 od TI. Lepší ako LM75 je aj LM75A od NXP. DS1307 sú hodinky a kalendár a k tomu ešte 56 byte batériou zálohovanej RAM. Na držiak CR2032 batérie je na plošáku určená plocha na priletovanie. AT24Cxx sú EEPROM obvody s kapacitami od 128 byte po momentálne 256kB a za nejaký rok to bude zase viac. A to už by bolo použiteľné aj ako virtuálny disk. Majú garantovaný milión prepisov a udržanie dát na minimálne 100 rokov.

PCF8584 podporuje rýchlosť 100kHz, čo je základná najnižšia rýchlosť. Novšie čipy fičia už aj na 400kHz a 1MHz. K zbernici je nutné pripojiť pull up odpory. Samotné zariadenia (sú open drain) len spínajú vodiče zbernice k zemi. Tým je zaručené, že pri konflikte nedôjde k zničeniu ani jedného zariadenia. Veľkosť odporov nie je kritická, ide len o to aby dostatočne rýchlo zdvíhali úroveň do 1. Prekonávať musia len parazitické kapacity na zbernici. 10, 20 kilo prípadne aj nejaká tá LED, všetko jedno ;-) 100kHz zase nie je nejaká super vysoká frekvencia.

Zdroják drivera a testovacej aplikácie je tu:
i2c fun

Takto to môže vyzerať po boote:

A to som mal otvorenú vetračku.

Tuesday, March 17, 2015

NCD85 1. Floppy radič

Vianočný čas som využil na návrh dvoch PCB. Jeden pre môj audio projekt a druhý pre NCB. Nazval som ho NCD85v2 a jedná sa o radič floppy diskiet a iné. Konkrétne jedna 8255 pre IDE rozhranie, jedna MUART 8256 pre experimenty (s interrupt systémom starej dobrej 8080) a I2C radič (plus I2C RTC, EEPROM a teplomer). A nakoniec stránkovaná 512kB SRAM zálohovaná batériou. Floppy radič PC8477BV-1 je v PLCC68 puzdre, s rozostupom pinov 2,54mm. Preto sa letuje rovnako ľahko ako DIP obvody. Ostatné obvody sú všetky DIP.

Nakoľko som to nechcel komplikovať a ťahať drôtiky je tu jeden kompromis. Použitie 512k SRAM si vyžaduje vytiahnutie 128kB SRAM na NCB doske zo soketu. Ja sám sa zatiaľ nechystám využívať 512k SRAM na novej doske. Ale keby niekto potreboval veľa RAM a navyše zálohovanej tak je k dispozícii. IC3, IC4, IC15 je potrebný len pre SRAM.

Ako vidno zatiaľ som osadil len časť pre radič diskiet. Na začiatku som osadil iba radič diskiet. Umožňuje na rozdiel od drátového modelu pripojiť až 4 kusy mechaník. Používajú sa obyčajné PC káble na disketové mechaniky. Na jeden kábel je možné pripojiť dve mechaniky. Doska v pohode funguje aj na 8MHz. Pri takomto minimalistickom osadení je potrebné mať iba IC1,IC2, IC16, IC6, RN2, Q3, C1, C2 a blokovacie kondenzátory. Ja som osadil aj blikátka: IC8 a súčiastky okolo.

Na obrázku je vidno pôvodný radič realizovaný na univerzálke a dvojicu NCB+NCD.

Fotky sú ešte mizernejšie ako zvyčajne (len z lacného telefónu), pretože môj kompakt HP zdá sa vydýchol naposledy.. Fotky (nie všetky) sú už lepšie.

NCB a NCD sú prepojené cez ribbon kábel. Má 40 žíl, ako kábel k IDE diskom. Dosky sú spojené pomocou dištančných stĺpikov.



Tu už sú osadené aj PIO 8255, MUART 8256, I2C controlér PCF8584 a I2C slaves DS1307, TMP275, AT24C256 a batéria CR2032. Neosadená zostáva iba časť pre stránkovanú 512kB SRAM. Na tú sa zatiaľ nechystám.



V doske sú pripravené otvory pre montáž 3.5" mechaniky. Čelo mechaniky trošku pretŕča takže by to celé šlo zabudovať do nejakej krabičky s otvorom pre mechaniku.



Sú použité 2 kusy GAL22V10D v DIP puzdre. Jeden (IC16) je potrebné osádzať vždy. Druhý (IC15) len pri použití 512k RAM. V schéme sú aj rovnice pre GAL. Pri čiastočom osadení (bez RAM) je potrebné vyradiť MR a MW signály. Čiže sú dve verzie "programu" pre IC16. Jedna pre 512k SRAM a druhá pre použitie bez SRAM. V schéme sú rovnice pre plnú paľbu aj s RAM. Zjednodušené a upravené rovnice pre použitie bez 512k SRAM pod názvom NCDexp_noram.equ sú tu:
https://drive.google.com/folderview?id=0B2TmWnRjWCj2fmlrZktnRENtMENiZDlPUXJYWWJjRmFqOTZla3pqbk1Td2xyQW1jMlRXeWM&usp=sharing

Na stiahnutie schéma tu:
https://drive.google.com/file/d/0B2TmWnRjWCj2clVuT1JrT1o3RWM/view?usp=sharing

Priebežne ako budem oživovať ďalšie časti, budem rozširovať aj popis. Pridám aj vysvetlenie ako funguje stránkovanie - pravdepodobne v samostatnom článku.

Aktualizácia:
Už mám osadenú aj 8255 a funguje. Teraz už len napísať ovládač pre IDE disk :-)
Ďalšia aktualizácia - už mám osadenú a otestovanú aj 8256.
Ďalšia aktualizácia - už mám osadený a otestovaný aj radič I2C PCF8584.
Ďalšia aktualizácia - ovládač pre IDE disk je napísaný a otestovaný.
Jedna chyba sa predsa len našla. Popiska pri JUM4 je naopak, v polohe RST7.5 je v skutočnosti INT a naopak.

Friday, May 9, 2014

NCB85 8. Expansion board

Od polovice mesiaca marec som sa zaoberal rozšíriteľnou doskou pre NCB5v2. Pre mňa najdôležitejšie tam je mať rozhranie na pripojenie floppy disket. Ako prvé bolo treba vybrať konkrétny typ radiča. Rozhodnutie padlo na NSC PC8477B. Je to asi najlepší radič aký bol pre disketovky vyrábaný. Je softwarovo kompatibilný s NEC FDC765, Intel 82077AA a ďalšími. Pre hovorí aj jednoduchosť zapojenia. Stačí pridať kryštál, 2x 10p kondíky a jedno odporové pole 5x 1k. To je všetko. Proti hovorí to, že nie je dostupný v puzdre DIP40. Ale je dostupný v puzdre PLCC a to sa spájkuje rovnako ľahko.

Okrem toho som dal na rozširovaciu dosku buffer na oddelenie zberníc a jeden GAL, ktorý to riadi. Nechcel som robiť plošák bez overenia schémy. Celé som to spáchal na univerzálke.



Po oživení hardware prišiel rad na software. Po dlhšom boji mám funkčný driver pre floppy diskety. Video s ukážkou ako si NCB85v2 rozumie s touto fascinujúcou technikou je tu:



Ešte chcem overiť rýchlosť, zatiaľ beží CPU na vysokých 8MHz, ale mám pocit že ~5MHz by mohlo s odretými ušami stačiť aj na 1,2M / 1,44M diskety. Tak nakoniec sa moja predtucha potvrdila. Dokonca aj CPU s kryštálom 9,8304MHz (a teda beží na 4,9152MHz) v pohode stíha aj HD disketám s rýchlosťou 500kbps.

Vybral som si sektory o veľkosti 256 byte. Kompatibilita s PC ktoré používa sektory o veľkosti 512 byte je dnes už asi nepotrebná. Zatiaľ som otestoval nasledovné formáty/kapacity:
5,25", DD, 40 stôp, kapacita 360kB, 18 sektorov
5,25", HD, 80 stôp, kapacita 1040kB , 26 sektorov (v PC má táto disketa kapacitu 1,2MB, 15 sektorov x 512 byte)

Diskety 3,5" zatiaľ neriešim, jediný rozdiel by mal byť v polarite signálu DENSEL, takže neočakávam žiadne problémy.Už som vyskúšal aj 3,5" diskety. Formát som otestoval tento:
3,5", HD, 80 stôp, kapacita 1280kB , 32 sektorov (v PC má táto disketa kapacitu 1,44MB, 18 sektorov x 512 byte).
Všetko funguje bez chyby. Tieto mikro diskety majú tiež svoje čaro. Zaberajú menej miesta, stačí im napájanie +5V a robia menej rámusu :-)

Saturday, February 8, 2014

NCB85 7. nové NCB85v2

NCB85 bolo navrhnuté ako minimalistická doska s 8085 procesorom. Chcel som ho využívať na testovanie úprav na kompileri SmallC. Časom naviac oproti plánovanému jednoduchému bootloaderu pribudol MON85 a nakoniec aj CP/M. Toto podstatne zvýšilo využiteľnosť a atraktivitu NCBčka. Dokonca aj v mojich očiach :-)
Fantastický popis NCB85 je na stránkach: Nostalcomp a 8bity. Popis CP/M pre NCB85 je tu: Borik
Po takmer dvoch rokoch sa prvá séria dosiek minula, ale občasný záujem tu stále je. To bol dôvod prečo som sa rozhodol pre druhú verziu.

Popis

NCB85v2 obsahuje výlučne súčiastky, ktoré sa montujú klasicky do diery. Minimálny rozostup pinov je 2.54mm, čo je vzdialenosť dvoch pinov na DIP puzdre. Na osadenie postačuje aj pištolová letovačka. Tú samozrejme neodporúčam, pretože nemá reguláciu teploty a veľmi ľahko môže zničiť dosku prehriatím a odlepením medi z podkladu.
Rozmery dosky sú jemne väčšie ako u prvej verzie. Tentokrát je to štandardných 16x10 cm.



Opravy
Nové NCB85v2 opravuje chybu prepojenia výstupu časovača so vstupom RST6.5. Teraz tam je správne vradený invertor.
Naviac opravuje aj druhú chybu časovača - príliš krátky prerušovací impulz. Pôvodne mal pri auto-reload mode výstupný impulz z timera 8155 dĺžku iba 10 alebo 16 strojových cyklov. V prípadne kryštálu 6.144MHz a deličky 7490 to bolo 10. V prípade 9.8304 MHz kryštálu a deličky 7493 to bolo 16 strojových cyklov. Lenže viaceré inštrukcie 8080 potrebujú až 18 strojových cyklov. Kedže sa prerušovací vstup testuje jeden krát za dobu vykonávania inštrukcie, dochádzalo k nevyhnuteľnému. Niektoré impulzy na prerušovacom vstupe sa strácali.
Nové NCB85v2 má do časovača privedený signál nezávislý od rýchlosti CPU a už pri kryštáli 6.144Mhz bude dĺžka výstupného impulzu 20 strojových cyklov. Pri použití rýchlejších kryštálov to bude zodpovedajúco viac.
Tentokrát je možné použiť aj 2716 a 2732 EPROMky v DIP24 puzdre. Na pine 24 je privedené VCC. Pri použití 27128 bude A13 stále na VCC. V starom NCB85 by bolo na GND.

Kompatibilita
Nové NCB85v2 je spätne plne kompatibilné. Všetko čo fungovalo na starom NCB85 funguje aj na novom. Sú tu staré známe 8251A a 8155 spolu s 64k RAM a 2-8kB ROM.
Adresy IO ostali rovnaké:
8251A - 08H..09H
8155 - 00H..07H
MON85 aj CP/M aj skúšobné programy využívajúce 8155 fungujú ako predtým. CPU môže mať osadený akýkoľvek kryštál, ale z hľadiska výkonu bude rozumné minimum asi 6MHz.
CMOS obvody OKI vraj dokážu fungovať až s kryštálmi 24MHz. Osvedčené CPU Toshiba spoľahlivo fungujú s kryštálmi 9.8304MHz. Rýchly test ukázal funkčnosť dosky s CP/M s kryštálom 12.228MHz.16MHz!! Pri 20MHz ešte stále nabootuje CP/M, ale potom sa už občas nejaká chybička objaví.

Zmeny
Rýchlosť sériového prenosu cez 8251A je nezávislá od hodín CPU a je voliteľná hardwarovo. Jedným jumperom je možné zvoliť baud rate v rozsahu od 600 do 38400 baud.
Pribudol dvojitý UART 16552. V pomerne malom puzdre sa nachádzajú hneď ďalšie dva sériové porty. To navyšuje celkový počet sériových portov na 3.
Pribudli dva "klasické" obvody 8255 a 8253/8254. Prvý je pripojený do DSUB 15 pin konektoru, ktorý je zapojený rovnako ako rozhranie pre PMD32. Port B a polovica portu C sú vyvedené na klasické headre so zámkom.
8253 je vyvedený na headre s tým, že k RST6.5 je možné pripojiť jeho timer/counter 0 namiesto timeru/counteru z 8155.

Konfigurácie
NCB85v2 je možné osadiť v minimálnej konfigurácii s 8251A/8155 a neosádzať 16552, 8253 a 8255. CP/M s BIOS V1.2 funguje cez 8155. Generátor baud rate potrebuje kryštál 9.8304MHz.
Samozrejme je možné osadiť 8255 a ďalšie obvody a neosadiť 8155.Časom snáď pribudne Už máme aj CP/M BIOS V2.0 upravený na porty 8255. PMD32SD sa pripája priamo ku NCB85v2 cez DB15 konektor. CP/M ponúka okrem filesystému aj veľký výber interpretrov, prekladačov (BASIC, C, PL/M, Lisp ..) a ladiacich nástrojov (DDT, SID, MAC, ..). Takto je možné písať programy v plnohodnotnom operačnom systéme, ktorým ostane k dispozíci 34 IO-pinov, štyri timer/countery a dve sériové linky.

Rozšíriteľnosť
Na doske je rozširovací konektor IDC 40 pinov. Vyvedené sú dátová a adresová zbernica. Riadiace signály WR/M, RD/M, WR/IO, RD/IO, RESET, INTR, INTA, ALE a pár ďalších.
Počíta sa s rozširovacou doskou, ktorá bude obsahovať radič disketových mechaník, stránkovanú a zálohovanú RAM 512kB s možnosťou non volatile RAM disku. Ďalej radič I2C zbernice s nejakým I2C obvodmi priamo na doske (IO porty, real time clock / calendar, teplomer, EEPROM). Tieto obvody by malo byť možné využívať aj v prípade, že rozširovacia doska bude pripojená k inej doske, napríklad nejakej s CPU Z80. Iba pre CPU 8085 a teda dosku NCB85v2 tam ešte bude veľmi zaujímavý obvod 8256. Tento obvod kombinuje v jednom puzdre UART, IO, timer/countre a radič prerušení(8251+8255+8253+8259)!

Nové chyby :-(
Objavil som jednu popisku (na plošáku) pri JUM4, ktorá má správne byť pri JUM3. Hovorí, že treba vytiahnuť príslušný jumper ak sa zapojí JUM5 na aktiváciu ALL RAM (CP/M) módu.
Jedna malá chyba je v zapojení tretieho sériového portu. Pin 31 obvodu TL16552D mal ísť na VCC. Ale nie je to nič vážne, pri osadení JUM9 to bude fungovať. TL16552D je jediný obvod, ktorý som zatiaľ neosadil a neotestoval. Nemám ho, ale už som ho objednal z USA. funguje to aj bez JUM9. Obidva kanály UART 16552 sú funkčné a otestované :-)





Dostupnosť
Ponúkam zopár dosiek a nasledovné súčiastky ako nekompletné kity: 8251A a 8254 aj so socketmi, 8085 CPU, 8155, kryštál 6.144MHz, 9.8304MHz a 16MHz. V prípade záujmu môžem ešte poskytnúť 7400, 7432, 74138, 74573, RAM, 8255, 8256 a naprogramované EPROMky.

Na stiahnutie
Schema

Thursday, January 30, 2014

NCB85 8. nedokumentované inštrukcie 8085

Trocha som zase pátral po informáciach o (nedokumentovaných) inštrukciách CPU 8085. Našiel som dva pekné 8085 cheatsheet-y

Jeden je tu:
http://saundby.com/electronics/8085/8085Ref.pdf

Druhý od Pavla Zímu je tu:
http://pastraiser.com/cpu/i8085/i8085_opcodes.html

Obsahujú aj nedokumentované inštrukcie, ten od Pavla dokonca aj ich časovanie a popis zmeny príznakov.

No a čo je hlavné, podarilo sa mi získať takmer 40 ročný dokument, priamo z ... :-) Nie celý. Ten veľmi milý pán, ktorý to skladoval celé tie roky mi oscanoval časť popisujúcu to čo nikdy nemalo byt zverejnené. Kedysi pracoval v ... a priamo na 8085.

Takže tu je to prepísané a k dispozícii ďalším fandom do vykopáviek. Z pochopiteľných dôvodov sem nebudem dávať scan. Z tých istých dôvodov sú tu aj bodky namiesto mena istej známej firmy. Pre známych je dokument k nahliadnutiu u mňa :-)

Začnem tým čo sa vyskytuje na toľkých miestach na webe:

Popis

DSUB
BC pair is subtracted from HL Pair affecting all flags. HL = HL - BC. Táto inštrukcia je opak DAD B.
Hex Code: 08h
States: 10
Flags: Z,CY,S,P,AC,V,K

JNK [16bit location]
Jump to Location if 'K' flag is reset
Hex code : DDh
States: 7/10
Flags: unaffected

JK [16bit location]
Jump to Location if 'K' flag is set
Hex Code: FDh
States: 7/10
Flags: unaffected

ARHL
Arithmetic right shift of HL register pair. MSB of the H register which means the mark does not change. The least significant bit of L register enters into the CY flag.
Hex code : 10h
States: 7
Flags: CY,V

RDEL
Rotate Left DE Pair
Hex code: 18h
States: 10
Flags: CY - depends on Bit 15

LDHI data
Add Immediate to HL pair. DE = HL + imm
Hex Code : 28h
States: 10
Flags: unaffected

LDSI data
Add Immediate to Stack Pointer. DE < - SP + imm Description: Adds an 8 byte number to the SP
Hex Code : 38H
States: 10
Flags: unaffected

RSTV
Description: Does a RST 8 instruction when the 'V' (must be overflow)flag is SET.
Hex Code: CBh
States: 6/12
Flags: unaffected

LHLX
Description: Loads HL Pair with the contents of address stored in the DE pair. HL = [DE]
Hex Code: EDh
States: 10
Flags: unaffected

SHLX
Description: Stores the HL Pair contents to the address specified in the DE pair. [DE] = HL
Hex Code: D9h
States: 10
Flags: unaffected

Popis príznakov

Pribudli dva nové príznaky K a V. Mali hlavne uľahčiť prácu s číslami so znamienkom.
K príznak je bit 5 v PSW registri. V je bit 1.

V príznak je: carry príznak do najvyššieho bitu "exclusive-or" carry príznakom z najvyššieho bitu(čo je C, bit 0 v F registri) - čo je štandardný výpočet pretečenia pre sčítanie a odčítanie so znamienkom.
Popis flagu podľa dokumentu je:
Overflow. Set if signed overflow occurs. V is affected by DAD, DSUB, RDEL, the rotates and any instruction which affects S, AC and P.

Skoro všade je príznak K popísaný zmätočne a navyše aj nesprávne. Dá sa nájsť takáto rovnica:
K = S1 & S2 | S1 & R | S2 & R.
Je to zle, neplatí to v určitých prípadoch. K príznak je v skutočnosti: V príznak "exclusive-or" S príznak.
Správny popis flagu podľa dokumentu je:
Greater than. Set if a signed greater than occurs in a comparison or subtraction (i.e. BC > HL in DSUB). Cleared if not. K is also affected by any instruction which affects S, AC and P although the result is meaningless. Additionally, INX, DCX set K if carry (borrow) occurs. This makes efficient double length loop counting possible.

Ultimátny dôkaz majú na "svedomí" fanatici, ktorý leptajú staré procesory a pod mikroskopom skúmajú kremík. Reverzným inžinierstvom už pred rokom prišli na to čo mám teraz potvrdené aj z dokumentu od toho milého pána.
http://www.righto.com/2013/02/looking-at-silicon-to-understanding.html

A pikoška na záver. Dôvod "utajenia" nebol ani problém s chybovosťou a ani (teda nehralo to hlavnú úlohu) nekompatibilita s prichádzajúcim 8086. Bol prozaickejší. Je na to pekné české "nejsou lidi". Ale je fakt, že to nemalo prioritu. Bol to dead end. 8086 už takéto príznaky nemalo.

Na stiahnutie:
Tundra 80C85 datasheet (kde to je tiež zle :-))
80C85

Thursday, May 23, 2013

SCC11. SmallC - PMI80

Neuveriteľné (pre mňa) sa stalo skutočnosťou. Na jednodoskáči s klávesnicou a sedemsegmentovým displayom beží program napísaný v C. Trocha to rozpíšem. Jedná sa o PMI80. Ten program v C sa samozrejme nezadáva cez klávesnicu a ani sa nekompiluje na PMI80. Program sa kompiluje pomocou SmallC na PC a napáli sa do EPROM. Je to o dosť zdĺhavejšie ako mať k dispozícii veľkú RAM a sériový bootloader. Práve preto som kedysi postavil NCB85.

Tu beží program v C
Istý Jakub si na aukro.cz kúpil toto PMI80 z obrázku. A nedalo mu to, skúsil na ňom C spôsobom ako som opísal. A nutno povedať, že s úspechom.


Data a Code segmenty
Pri preklade do RAM je vcelku jedno, kde sa nachádza program a kde premenné. Iné je to ale pri použití ROM. Program je v ROM, pretože jeho obsah je pevne daný a nemení sa. Ak teda zrovna nepoužívame samomodifikujúci sa kód. Ale premenné musia byť v RAM. Na toto majú assemblery možnosť definíce dátového a kódového segmentu alebo aj ďalších segmentov. Linker potom priradí každému segmentu adresu a vygeneruje správne skoky a návestia. Ja som nazval v SmallC dátový a programový segment takto:
Programový kód je umístěn do oblasti uvozené:
.area SMALLC_GENERATED (REL,CON,CSEG)
globální proměnné pak do:
.area SMALLC_GENERATED_DATA (REL,CON,DSEG)
Jakub poslal aj popis ako sú uložené dáta a program.
Lokální proměnné jsou jako obvykle umísťovány na stacku. Pro použití s PMI-80 je potřeba oblast SMALLC_GENERATED_DATA přesměrovat někam mezi adresy 0x1c00 a 0x1fff, kde je jediný 1KB RAM (přičemž je třeba mít na zřeteli, že od konce RAM směrem dolů roste stack). Já programová data umísťuji od adresy 0x0800 kde na mém upraveném PMI začíná třetí KB ROM a je to začátek druhého EPROM čipu. Programy do PMI dostávám pomocí mazačky a programátoru EPROM. Majitel neupraveného PMI bude muset linkovat na adresu 0x0400, nebo také do RAM (ale opravdu jí není mnoho). Já zatím do RAM program nelinkoval, protože stejně zatím nemám žádný loader, kterým bych ho bez použití naprogramované EPROM dostal na místo.
takto vyzerá výpis na display
update_disp(mpx,seg)
   unsigned char mpx;
   unsigned char seg;
   {
     mpx;
#asm
     mov b,l
#endasm
     seg;
#asm
     mov a,l
     out 0xF8
     mov a,b
     out 0xFA
#endasm
   }
a takto krátený hlavný program
for (a = 0; a < 37; a++) { //pres celou tabulku znaku v kodu monitoru
   disp_buff[0] = (a >> 4) & 0x0f;
   disp_buff[1] = (a ) & 0x0f;
   disp_buff[2] = PMI_CH_equal;
   bin2bcd(a, &disp_buff[3]);
   disp_buff[6] = PMI_CH_equal;
   disp_buff[7] = PMI_CH_equal;
   disp_buff[8] = a;

   for (c = 0; c < 100; c++) {
     for (b = 0; b < 9; b++) {
       update_disp(~b, seg_data[disp_buff[b]]);
       delay(10);
     }
   }
}
C na PMI80. Kto by si to bol kedy pomyslel ? Kto by mal záujem o podobné hrátky bude sa musieť spojiť s Jakubom. Ja PMI80 nevlastním ;-)

Saturday, May 11, 2013

SCC.10 printf

printf je užitočná a pomerne silná metóda, ktorá je prítomná v prekvapujúco veľa jazykoch. Okrem iných aj Fortran, Cobol, Java, PHP, Perl .. Mňa na nej vždy fascinovalo to, že má premenlivý počet parametrov. Napríklad:

printf("V zivote je %d dobrých vecí, hlavne %s stojí za to", my_number, her_name);

V tomto prípade má 3 parametre. Prvý je string obsahujúci formattery a nasledujú hodnoty pre formattery. Prvý je číslo ktorá sa zobrazí v decimálnom tvare a druhý parameter je string ktorý sa len prekopíruje na zodpovedajúcu pozíciu. Dlho som si lámal hlavu nad tým, ako len môže byť printf napísaný ... Veď čo ak by tie parametre boli štyri alebo povedzme sedem prípadne iba jeden ? Dosť záhadné :-)

Tajomstvo printf je jednoduché. C robí PUSH parametrov metódy na zásobník v opačnom poradí. Najskôr sa PUSHne posledný param a potom druhý od konca a tak ďalej. Až na koniec sa PUSHne prvý parameter. A to znamená, že sa nachádza hneď nad návratovou adresou, ktorú PUSHlo volanie našej metódy CALL printf

Preto stačí v implementácii printf získať obsah dvoch byte nad aktuálnym SP. To bude pointer na string obsahujúci formattery. A sme doma :-) Pretože z toho stringu už vieme zistiť koľko parametrov má naše volanie printf. A každý z nich sa nachádza zase o dva bytes vyššie.

Metóda printf nie je súčasťou SmallC, ale nie je problém ju napísať. Ja sa na to chystám už mesiac ;-) Sú tu ale dve veci. Dobrá a zlá. Zlá správa je, že v SmallC sa parametre volania ukladajú na stack v opačnom poradí ako je špecifikácia C. Čiže pascalovským spôsobom a tým pádom bude formátovací string najďalej od SP. Takže sa to nedá ? Ale dá, je tu aj dobrá správa. SmallC vie posielať do volanej metódy okrem parametrov (ktoré su PUSHnuté na stacku) aj počet parametrov. Posiela sa v ACC. Takže SmallC implementácia bude neštandardná. Počet parametrov si nezistí sama, ale bude sa spoliehať na číslo v ACC.

Aby to bolo úplne cool, bolo by fajn napísať to celé v ASM. Ak by to niekto chcel urobiť, môžem mu poslať nejaké podklady.

Tuesday, April 2, 2013

NCB85 6. CP/M 64k V2.2

Dnes ráno mi prišla doštička interface k NCB85 a PMD32SD od Martina. Kábel som už mal pripravený tak som rýchlo osadil súčiastky, naprogramoval EPROM a zapol hyperterminál. Po zapnutí som videl toto:



Keby to vždy išlo takto hladko :-) Odteraz sa budem snažiť testovať a ladiť na NCB85. ZetaSBC ale ostáva na stole, budem sa snažiť overovať programy na obidvoch CP/M strojoch.

Monday, March 25, 2013

NCB85 5. File I/O

Prvý program Hello World overil funkčnosť konzolového I/O a cross compilácie. Druhý program otestoval spracovanie vstupných parametrov z CP/M príkazového riadku. Ďalším krokom je test file systému. Pripravil som krátky program, ktorý vypíše na konzolu obsah súboru. Názov súboru sa zadáva ako parameter. Ak sa nezadá žiadny parameter, alebo viac ako jeden parameter, program vypíše usage. Ak sa nepodarí otvoriť súbor, tak vypíše chybové hlásenie.
/*
* File: main.c, march 2013
* file test on CP/M
*/
#include <stdio.h>

FILE *input;

/**
* main routine
* @return
*/
main(int argc, int argv[]) {
    char k;
    print("File test\r\n");

    if (argc == 2) {
       print("file:");
       print(argv[1]);
       print("\r\n");

       if ((input = fopen(argv[1], "r")) == NULL) {
          print("Open failure\n");
          exit(1);
       }

       while ((k = fgetc (input)) != EOF) {
          putchar(k);
       }

       fclose(input);
    } else {
       print("usage: fltst file.ext");
    }
}

print(char *str) {
    while (*str) {
       putchar(*str++);
    }
}

CRTSO sa zase trošku zmenilo. Pribudla inicializácia STDIO systému. Toto je asi aj finálna verzia. Už tam je všetko, čo je potrebné na prácu v CP/M.
    lxi h,0
    dad sp
    shld stksav ; save the stack pointer
    lhld 6 ; pick up core top
    lxi d,-10 ; decrease by 10 for safety
    dad d
    sphl ; set stack pointer
    call stdioinit ; initialize stdio
    lxi h,0x0080
    push h
    call Xarglist
    lhld Xargc
    push h
    lxi h,Xargv
    push h
    call main ; call main program
    jmp 0
stksav: .ds 2
crtsoend:
    .end

Do projektu pribudli ďalšie podporné súbory: io8080.c, bdos1.c a exit.c

Building project
scc8080 -t -a main.c
as8085 -l -o -s -p -g main.s
scc8080 -t -a bdos.c
as8085 -l -o -s -p -g bdos.s
scc8080 -t -a chio8080.c
as8085 -l -o -s -p -g chio8080.s
scc8080 -t -a arglist.c
as8085 -l -o -s -p -g arglist.s
scc8080 -t -a charclass.c
as8085 -l -o -s -p -g charclass.s
scc8080 -t -a io8080.c
as8085 -l -o -s -p -g io8080.s
scc8080 -t -a bdos1.c
as8085 -l -o -s -p -g bdos1.s
scc8080 -t -a exit.c
as8085 -l -o -s -p -g exit.s
as8085 -l -o -s -p -g cret.asm
as8085 -l -o -s -p -g crun8080lib.asm
aslink -n -i -u -o -m -b CRET=0x0100 -b LIB8080=crtsoend+0x0100 -b SMALLC_GENERATED=crun8080_end+crtsoend+0x0100 cmd cret.rel crun8080lib.rel main.rel bdos.rel chio8080.rel arglist.rel charclass.rel io8080.rel bdos1.rel exit.rel
sort -k1.8,1.9 -k1.4,1.7 cmd.ihx > cmd.hex
hex2bin -e com -c cmd.hex
hex2bin v1.0.1, Copyright (C) 1999 Jacques Pelletier
Lowest address = 00000100
Highest address = 00001DD3

Build finished


Výsledný COM sa nafúkol na cca 7.5kB. Z toho sú ale 2kB buffer pre čítanie sektorov z filesystému. To preto, lebo je dovolené mať otvorené naraz až 4 súbory. Odhadom ďalšie 0.5kB sú pomocné štruktúry ako 4x FCB atď.

NCB85 4. Command line params

Hello World bol prvý krok. Ďalší krok je otestovanie parametrov zadávaných v príkazovom riadku CP/M. CRTSO bude trošku zložitejšie.

; Run time start off for Small C.
.module CRET
.area CRET (REL,CON) ;program area CRTSO is RELOCATABLE
.list (err, loc, bin, eqt, cyc, lin, src, lst, md)
.nlist (pag)
.globl crtsoend

lxi h,0
dad sp
shld stksav ; save the stack pointer
lhld 6 ; pick up core top
lxi d,-10 ; decrease by 10 for safety
dad d
sphl ; set stack pointer
lxi h,0x0080
push h ; line buffer is at 0080H
call Xarglist
lhld Xargc
push h
lxi h,Xargv
push h
call main ; call main program
jmp 0 ; warm boot, reload CCP
stksav: .ds 2
crtsoend:
.end

Musel som upraviť dodaný CRTSO k SmallC pretože nefungoval. Pridal som riadok s LXI H,0080 a PUSH H. Následne volaná C rutina Xarglist totižto očakáva vstupný parameter char pointer na buffer s obsahom príkazového riadku. Rozparsuje buffer podľa medzier a naplní Xargc a Xargv globálne premenné. Pôvodný stack ukazoval na priestor v CCP, kde bolo miesto na 8 úrovní. Túto hodnotu síce ukladáme, ale po ukončení sa aj tak nepoužije. Jednoduchšie je zavolať warm boot, ktorý reloadne CCP.

C program

/*
* File: main.c, march 2013
* command line arguments testing on CP/M
*/

/**
* main routine
* @return
*/
main(int argc, int argv[]) {
    int i;
    print("Argument test\r\n");

    for (i=1; i < argc; i++) {
       print("arg:");
       putchar('0' + i);
       print(", value:");
       print(argv[i]);
       print("\r\n");
    }
}

print(char *str) {
    while (*str) {
       putchar(*str++);
    }
}

V main metóde sa zmenila hlavička. Už máme dva parametre. Prvý je počet parametrov argc. Ale čo ten druhý ? Malo by tam byť napr. char *argv[]. Čiže pole pointerov na char. Žial SmallC umožňuje iba jednu úroveň indirekcie. Využíva sa tu trik, že pointer je rovnako veľký ako int. Takže to pole integerov je vlastne to isté ako pole pointerov. Toto je ďalšia oblasť, kde by sa mohlo SmallC vylepšiť.

Spustenie programu na CP/M

A0>cmd a b -t
Argument test
arg:1, value:A
arg:2, value:B
arg:3, value:-T


To vyzerá dobre :-)

Build

K main.c, bdos.c a chio8080.c pribudli ďalšie dva súbory: arglist.c a charclass.c.
Building project
scc8080 -t -a main.c
as8085 -l -o -s -p -g main.s
scc8080 -t -a bdos.c
as8085 -l -o -s -p -g bdos.s
scc8080 -t -a chio8080.c
as8085 -l -o -s -p -g chio8080.s
scc8080 -t -a arglist.c
as8085 -l -o -s -p -g arglist.s
scc8080 -t -a charclass.c
as8085 -l -o -s -p -g charclass.s
as8085 -l -o -s -p -g cret.asm
as8085 -l -o -s -p -g crun8080lib.asm
aslink -n -i -u -o -m -b CRET=0x0100 -b LIB8080=crtsoend+0x0100 -b SMALLC_GENERATED=crun8080_end+crtsoend+0x0100 cmd cret.rel crun8080lib.rel main.rel bdos.rel chio8080.rel arglist.rel charclass.rel
sort -k1.8,1.9 -k1.4,1.7 cmd.ihx > cmd.hex
hex2bin -e com -c cmd.hex
hex2bin v1.0.1, Copyright (C) 1999 Jacques Pelletier
Lowest address = 00000100
Highest address = 00000827
Build finished
Výsledný COM už narástol na 727 bytov hexadecimálne.

Sunday, March 24, 2013

NCB85 3. Cross compiled Hello World

Používať moderné IDE na vývoj pre CP/M nie je žiadna prevratná myšlienka. Fakt ale je, že to skoro nikto nerobí. Snáď preto, že starí CP/M harcovníci majú odpor k Windows, alebo možno preto, že iba nepoznajú silu a výhody moderných IDE. Preto som sa do toho vrhol ja.

Každý C program začína metódou "main()". Lenže v CP/M sa programy spúšťajú od adresy 0x0100. Ako na to ? Písať k main niečo ako ORG 0x0100 by nebolo to pravé orechové. Robí sa to inač. Každý program v C má zavádzač. Nazýva sa C Run Time Start Off, skrátene CRTSO. Pre CP/M by mohol vyzerať takto nejako:
;   Run time start off for Small C.
;   cseg
    .module CRET
    .area CRET (REL,CON) ;program area CRTSO is RELOCATABLE
    .list (err, loc, bin, eqt, cyc, lin, src, lst, md)
    .nlist (pag)
    .globl crtsoend
    lxi h,0
    dad sp
    shld stksav
    lhld 6 ; pick up core top
    lxi d,-10 ; decrease by 10 for safety
    dad d
    sphl ; set stack pointer
    call main ; call main program
    lhld stksav ; restore stack pointer
    sphl
    ret ; go back to CCP
stksav: .ds 2
crtsoend:
    .end
Všimnime si volanie "call main". Áno to je ono. Tu nám zavádzač spúšťa našu main metódu. Tá bižutéria okolo, je už len presunutie zásobníka. Vlastnej tvorbe a fantázii sa medze nekladú. Musel som upraviť SmallC verziu pretože, neviem prečo ale bola zlá. Hneď na začiatku bolo SPHL. Nastavenie SP na hodnotu v HL. Ale to je asi blbosť. Veď CP/M nedáva v HL žiadnu hodnotu hovoriacu o zásobníku. Zase keby som nechal SP bez zmeny, tak by ukazoval niekam do CCP kde je priestor iba pre 8 úrovní. Preto som zvolil inú taktiku. Radšej si ho alokujem tam kde bolo CCP a miesta mám habadej.

C zdrojáky

SmallC nám všetky C zdrojáky preloží do ASM. Ďalší krok je spustiť assembler ktorý spracuje tieto vzniknuté ASM. Posledný krok je link. Linker nám musí zostaviť výsledný program, pozostávajúci z viacerých REL súborov. REL sú relokovateľné fragmenty. Je to výsledok volania assemblera. Linker ich zostaví do jedného celku, pričom na adrese 0x0100 bude ako prvý CRTSO. Ostatné fragmenty už môžu ísť v ľubovoľnom poradí za ním. Pri Hello World si vystačíme s tromi C súbormi.

/*
* File: main.c, march 2013
* hello world on CP/M
*/

/**
* main routine
* @return
*/
main() {
    print("Hello World!!");
}

/**
* prints zero terminated string
* @param str
* @return
*/
print(char *str) {
    while (*str) {
       putchar(*str++);
    }
}


Druhý súbor je z knižice SmallC. Je to chio8080.c
#define EOL 10
getchar() {
    return (bdos(1,1));
}

putchar (c) char c; {
    if (c == EOL) bdos(2,13);
    bdos(2,c);
    return c;
}


BDOS služba 1 je vstup jedného znaku z konzoly. BDOS služba 2 je výstup jedného znaku na konzolu. Posledný súbor je bdos.c ktorý už len zavolá CALL 5 volanie CP/M BDOS. Listing neuvádzam. Je to len CALL 5 a nejaké POP a PUSH.

COM file

Výstupom linkera je Intel HEX súbor. CP/M potrebuje spustiteľný COM file. Je možné nahrať na CP/M stroj HEX súbor a pomocou príkazu LOAD ho prekonvertovať na COM. Dá sa to ale aj priamo na Windows. Použijeme utilitu hex2bin, ktorá robí presne to isté. Naviac nám do build okna vypíše aj veľkosť výsledného COM.

Building project
scc8080 -t -a main.c
as8085 -l -o -s -p -g main.s
scc8080 -t -a bdos.c
as8085 -l -o -s -p -g bdos.s
scc8080 -t -a chio8080.c
as8085 -l -o -s -p -g chio8080.s
as8085 -l -o -s -p -g cret.asm
as8085 -l -o -s -p -g crun8080lib.asm
aslink -n -i -u -o -m -b CRET=0x0100 -b LIB8080=crtsoend+0x0100 -b SMALLC_GENERATED=crun8080_end+crtsoend+0x0100 hello cret.rel crun8080lib.rel main.rel bdos.rel chio8080.rel
sort -k1.8,1.9 -k1.4,1.7 hello.ihx > hello.hex
hex2bin -e com -c hello.hex
hex2bin v1.0.1, Copyright (C) 1999 Jacques Pelletier
Lowest address = 00000100
Highest address = 00000374
Build finished


Po nahratí na CP/M stroj a spustení COM súboru nám to naozaj vypíše Hello World!!
Niekomu by sa COM súbor zdal moc veľký. Je to spôsobené tým, že je tam prilinkovaná kompletná run-time knižnica crun8080lib. Táto obsahuje aj napríklad rutiny na násobenie, delenie, rotácie, switch príkazy a kopu ďalších, ktoré v Hello World nepoužívame.

Monday, March 18, 2013

NCB85 2. XMODEM

Dotaz na Rádio Jerevan: Je pravda, že každý návštěvník Rudého náměstí v Moskvě dostane auto?
Odpověď: V principu ano. Ovšem nejedná se o Rudé náměstí v Moskvě, ale o Náměstí Gorkého v Kijevě. Také se nejedná o auta, ale o kola. A nejsou rozdávána, ale kradena.

S nadpisom tohoto blogu je to tak trošku podobné. Nejedná sa o NCB85 ale o ZetaSBC. Prisahám, že to sú všetky rozdiely ;-)

Pripravil som kratučké video, ktoré ukazuje ako používať výbornú utilitku XMODEM na prenos file medzi CP/M a Windows. V tomto videu je použitá ZetaSBC a nie NCB85, nakoľko ešte nie je hotový PMD32SD a interface. Prenos je smerom z PC na Zetu. Samozrejme ide to aj opačne. Video je tu preto, lebo som zistil, že nie všetci CP/M používatelia o takejto možnosti vedia. A nie je celkom triviálne prísť ako na to. Dík Martine za asistenciu :-)



Celkom na záver si neodpustím ešte jeden krátky.

Dotaz na Rádio Jerevan: Kde vlastně sedí ten, co vymýšlí vtipy na Radio Jerevan?
Odpověď: To bohužel nevíme, ale sedí zcela určitě!

Thursday, February 28, 2013

SCC1. Úvod do SmallC

Bol socializmus. Hrávali sa dve hymny. Československá a sovietska. V televízii boli dva programy. Amatérske rádio prinášalo články o splnených úlohách a zjazdoch KSČ. Na viedni bežal KITT. Vrchol techniky boli sedemmelódiové digitálky. Potom prišli 8-bity. V tuzexe sa dal kúpit Sinclair Spectrum. V predajniach občas mali Atari 800XL. Na stanici mladých technikov dostali dve PMDéčka. Programy sa nahrávali na kazety. Prvý program, ktorý som naťukal bol v Basicu na PMD85. Dodnes si pamätám na neuveriteľný pocit z toho, že to čo píšem na klávesnici vidím na obrazovke.

Nadšene som hltal príručku k PMD85 a učil sa príkazy Basic. V tej dobe zároveň vychádzal v Elektróne hi-tech seriál o programovaní v assembleri 8080. Nejakým spôsobom sa mi dostal do rúk program DDT602. Bol to celobrazovkový assembler a disassembler pre PMD85. Potom sa mi dostala do rúk aj kópia Monitor PMD85. Zase som mal čo študovať. V tej dobe som už počul o jazyku Pascal. Ale na PMD85 nič také nebolo. Po prechode na výšku, som už kontakt s 8-bitmi stratil úplne. Prišla doba PC, diskiet a harddiskov. A tak som sa nejako nikdy nestretol s CP/M a ani som netušil, že na 8080 existovali aj C kompilery.

Prešlo veľa rokov. Vlastne ich bolo asi 20. Pri browsovaní na mňa na full HD LCD jedného dňa vyskočil mne neznámy pojem SmallC. Ostal som dosť prekvapený, pretože sa jednalo o C kompiler pre 8-bitový procesor z počítačového praveku Intel 8080. Vždy som chcel spoznať ako funguje kompiler. Assembler 8080 som si ešte matne pamätal. Neváhal som a stiahol som si zdrojáky. Vznikali niekedy v lete 1980 !!!

SmallC nie je plnohodnotný kompiler C. Keď ho Roin Cain napísal podporoval iba while cykly a z typov len char a int. Ďalej jednorozmerné polia a pointre. Napriek tomu to bol veľmi silný nástroj. Ron na motorke odniesol zdrojáky vytlačené na papieri do redakcie Dr'Dobbs časopisu. Vyšli v júli 1980 v čísle 45. Ron sa radšej nepochválil, že C kompiler ktorý práve napísal je len jeho druhý program v C. Prvý bol obligátny Hello World. Aj tak mu nechceli veriť, že na tom výstupe z tlačiarne je C kompiler, pretože .... tam videli C zdrojový kód. V tej dobe sa jednalo o nevídanú vec. Kompiler ktorý prekladá sám seba.

Ron dal kód k dispozícii verejnosti a rýchlo vznikali varianty a rozšírenia jeho kompileru. Mne sa zapáčila verzia, ktorá bola portovaná na UNIX. Napísal ju Chris Lewis a pridal rozšírenia oproti verzii 2.0. Po jemných úpravách sa dala preložiť aj s gcc. Pri spustení vygenerovala pekný core :/ Tak som pátral ďalej a po úprave spracovania args a argv začala fungovať.

Wednesday, February 27, 2013

SCC2. SmallC - deklarácie premenných

SmallC je jednopriechodový kompiler. Nežartujem. Číta C kód z textového súboru alebo konzoly. Nepoužíva lex/yacc. Ron si napísal vlastný parser, lexer a generátor kódu. Na výstupe generuje asm kód. Tento je spracovávaný asemblerom. Ja som upravil SmallC tak, aby produkoval kód pre 5-priechodový ASXXXX. Nežartujem, naozaj je 5-priechoddový ;) Výsledkom ASLINK linkera je Intel Hex súbor.

Všetky knižky o kompileroch venujú veľa priestoru teórii. To by až tak nevadilo, keby častokrát úplne nevypúšťali časť venujúcu sa generovaniu kódu. A práve pohľad na generovaný kód pomôže pochopiť ako funguje kompiler. 8080 je tak trochu už 16-bit procesor. Má tri registrové páry zložené z dvojíc registrov: BC, DE a HL. Tieto registrové páry umožňujú 16 bitové operácie ako add, sub, lhld, shld, lxi. SmallC používa takzvaný primary/secondary register koncept. Používa len dva registrové páry. Primárny je HL, secondary je DE. BC sa nepoužíva.

SmallC má jednu vynikajúcu vlastnosť. Umožňuje interaktívnu prácu. Človek napíše riadok C kódu, stlačí ENTER a hneď dostane výstupný asm kód. Je to perfektné pre zoznámenie sa s kompilerom. Poďme si to vyskúšať. Tu je preložená verzia pre Windows. scc8080. Záujemci o linux verziu si zdrojový kód https://github.com/ncb85/SmallC-85 iste bez problémov skompilujú sami.

Otvoríme si prompt a spustíme kompiler: scc8080 -t
Flag -t hovorí, že vstupné riadky budú kopírované do výsledného asm kódu ako komentáre. Nezadali sme názov file, takže vstup aj výstup bude na konzole. Mali by sme vidieť takéto niečo:
; Small C 8080
; Coder (2.4,84/11/27)
; Front End (2.7,84/11/28)
; Front End for ASXXXX (2.8,13/01/20)
;program area SMALLC_GENERATED is RELOCATABLE
.area SMALLC_GENERATED (REL,CON)
.module SMALLC_GENERATED
.list (err, loc, bin, eqt, cyc, lin, src, lst, md)
.nlist (pag)
.area SMALLC_GENERATED (REL,CON,CSEG)
napíšem: int a; a stlačím CTRL-Z a ENTER čím pošlem EOF znak. Na niektorých OS je treba poslať znak CTRL-D. SmallC vidí koniec file EOF a preto už nečaká na ďalší riadok ale skončí. Mal by vypísať toto:
.area SMALLC_GENERATED_DATA (REL,CON,DSEG)
.globl a
a:
.dw #0

;0 error(s) in compilation
; literal pool:0
; global pool:1
; Macro pool:45
; .end

Vo výstupnom asm je label s názvom našej deklarovanej premennej a má rezervované miesto 2 bytes (DB - Define Byte, 8 bits. DW - Define Word, 16 bits) čo je správne, pretože a je int. A nielen to, má aj východziu hodnotu. Tá je nastavená na 0. SmallC sa postará o to, aby globálne premenné mali garantovanú hodnotu. Vhodné sú ďalšie experimenty, deklarácia viacerých premenných, rôznych typov (int, char, unsigned int, unsigned char).

Tuesday, February 26, 2013

SCC3. SmallC - krátky program

V minulom článku sme skúsili interaktívny režim SmallC. Teraz skúsme kratučký program a pozrieme sa na vygenerovaný kód. Spustime kompiler príkazom scc8080 -t
Zadajme:
int gla, glb = 3;
char msg[]="hello world", glc, *glpc;

method_a () {
   gla = glb;
   glc = 'x';
   glpc = msg;
}
Dostaneme:
; gla = glb;
lhld glb
shld gla
do primárneho registrového páru sa načítala hodnota na adrese glb a uložila sa na adresu gla
; glc = 'x';
lxi h,#120
mov a,l
sta glc
do HL sa načítalo 'x' čo je ASCII 120, všimnime si, že aj typ char sa načítava do registrového páru. Následne sa už správne uložila len hodnota z L do A a v poslednom kroku sa uložil A na adresu glc
; glpc = msg;
lxi h,msg
shld glpc
do HL sa načítala adresa začiatku poľa msg. V C sú stringy interpretované ako char array. Adresa poľa msg sa uložila na adresu glpc.

Na konci nasledujú deklarácie:
gla:
.dw #0
gla je int, má rezervované dva byte. Keďže nemá inicializačnú časť, bola mu defaultne daná hodnota 0
glb:
.dw #3
glb má hodnotu 3, presne ako má v inicializačnej časti
msg:
.db #104,#101,#108,#108,#111,#32,#119,#111,#114,#108
.db #100,#0
msg je pole bytov, inicializované na znaky hello world, ukončené 0.

Monday, February 25, 2013

SCC4. SmallC - funkcie

Jedna z najväčších výhod C jazyka sú lokálne premenné. Lokálne premenné nemajú miesto vo výslednej binárke, ale sa alokujú dynamicky. Počas behu programu, pri potrebe lokálnej premennej sa na zásobníku alokuje pamäť. Napríklad obyčajný PUSH posunie SP o dva byte. Na vzniknutom mieste môžeme ukladať hodnoty. Pri ukončení potreby lokálnej premennej sa urobí POP. Tým sa zásobník vráti do pôvodného stavu. Skúsme takýto kód
main() {
int la;
la = 5;
}
Začiatok metódy je označený labelom main:
;main() {
main:
Ďalej dostaneme:
;int a;
push b
;a=5;
lxi h,#0
dad sp
push h
lxi h,#5
pop d
call ccpint
Deklarácia premennej v metóde spôsobí okamžitý PUSH aby sa alokoval priestor. Ďalej nasleduje dvojica metód LXI a DAD ktoré nastavia do HL adresu premennej a.
Táto adresa je hneď uložená na stack. Toto je typické pre kód generovaný podľa primary/secondary register konceptu. Pretože nemáme viac registrov, každá hodnota sa musí hneď ukladať na stack aby sa uvoľnili jediné dva registre. Toto je na jednej strane jednoduchšie na implementáciu a aj výsledný asm kód je ľahko čitateľný. Na druhej strane je to veľmi neefektívne. Moderné procesory majú desiatky registrov a namiesto ukladania na stack sa alokujú ďalšie a ďalšie registre. Ale napísať túto časť kompileru (register alocation) patrí medzi najťažšie úlohy.
Ďalej nasleduje načítanie hodnoty 5 do HL a do DE sa popne adresa lokálnej premennej. A zavolá sa rutina z knižnice, ktorá uloží HL na adresu DE. Mimochodom tieto tri inštrukcie sa dajú nahradiť jedinou. Existuje aj nedokumentovaná inštrukcia 8085 s názvom SHLX. Prepínač -u v SmallC zapne generovanie kódu s nedokumentovanými inštrukciami. Pri zapnutí -u sa vo výpise obajví aj ďalšia nedokumentovaná inštruckia - LDSI.

Koniec metódy:
pop b
ret
Pop opraví SP a ret ukončí metódu.
Ako sa zmení kód ak budeme mať dve lokálne premenné ? Nechávam to na vlastné pokusy.

Sunday, February 24, 2013

SCC5. SmallC - príkazy

Príkazy sú prekvapivo jednoduché na implementáciu. Skúsme sa pozrieť na if. Zadajme:
main(){
    if (1) {
    } else {
    }
}
Dostaneme:
main:
;if (1) {
lxi h,#1
mov a,h
ora l
jz $2
;} else {
jmp $3
$2:
;}
$3:

A koniec mainu:
}
$1:
ret
Hmm je treba komentár ? Do primárneho registrového páru HL sa načítala hodnota výrazu a kombináciou mov a ora sa testuje na nulu. V C je všetko okrem nuly true. Medzi jz $2 a jmp $3 by išiel kód príkazov, ktoré sa majú vykonať pri splnenej podmienke. jmp $3 tam je kvôli tomu, aby sa nevykonal kód príkazov else vetve. Je zaujímavé pozrieť si, ako sa interpretujú ostatné príkazy ako case, while, for..

Saturday, February 23, 2013

SCC6. SmallC - pohľad do kódu

Videli sme aký jednoduchý je kód pre príkazy. Ich implementácia v kompileri tiež patrí medzi jednoduchšie časti. Toto je zjednodušený listing. Ukazuje akým spôsobom kompiler vygeneroval postupnosť inštrukcií z predchádzajúceho článku.
flab1 = getlabel ();
test (flab1, FALSE);
statement (NO);
if (!amatch ("else", 4)) {
  generate_label (flab1);
  return;
}
gen_jump (flab2 = getlabel ());
generate_label (flab1);
statement (NO);
generate_label (flab2);
Na prvom riadku sa inkrementne počítadlo labelov. Potom funkcia test vyhodnotí výraz a vygeneruje trojicu inštrukcií mov a,h a ora l a jz flab1. Nasleduje volanie statement, čo je spracovanie nula alebo viacerých príkazov, ktoré sa majú vykonať ak je podmienka splnená. Kompiler hneď generuje zodpovedajúce inštrukcie ak nájde príkazy. Potom sa testuje, či je prítomná else vetva. Ak nie (podmienka je vtedy splnená) tak sa vygeneruje sa flab1 pre funkciu test, ktorá už generovala jump na tento label. Return už len skončí. Ak ale máme aj vetvu if, tak sa generuje jump flab2, ktorý obskakuje vetvu if. Za týmto jumpom sa až vygenruje flab1 pre test zo začiatku metódy. A logicky sa volá statement, aby sa vygeneroval kód pre všetky príkazy v else vetve. Potom už konečne ide label2 pre obskakovací jump. Jednoduché že ?