Home | Artikel | VCFe Softe Hardware

VCFe Vortrag vom 2009.05.01 - Softe Hardware - Emulation von hochintegrierten Chips auf Mikrocontrollern


Inhalt

Einführung

Wer nicht nur passiv bestehende Rechnerarchitekturen vergleichen, sondern auch aktiv eigene entwerfen und ausprobieren will, steht vor dem Problem diese implementieren zu müssen.

Kleine Logikchips wie die späte 1960er und frühe 1970er 74(x)xx TTL Technologie erlaubten jedermann relativ einfach Rechner zu entwerfen, und lösten ein kurzes (etwa 10 Jahre dauerndes) goldenes Zeitalter der Rechnerarchitekturen aus. Die resultierenden Rechner waren aber aufwendig zum löten und gross, weil hunderte von Chips verbaut wurden.

Spätere hochintegrierte Chip Technologien beschränkten Architekturdesign auf Firmen wie Intel, die mit industriellen Millionenbudgets für die notwendige Chip Fabrikation hantieren können. Leider basierten die Architekturen grossteils auf bewährten 1960er Designs, und verloren damit die ganzen 1970er Erfahrungen. Das nervt den historisch wissenden und experimentierfreudigen Bastler.

Heute existieren grosse konfigurierbare Logikchips, in die man beliebige Schaltungen hineinladen kann, bis zu etwa 3% der Grösse (und 30% Taktfrequenz) der heutigen industriellen hochintegrierten Chips. Aber die industriellen closed source Softwaretools dafür sind seit Jahrzehnten schnarchlangsam und barbarisch mühsam und frustrierend. Die Gründe dafür sind bekannt und keine Besserung zu erwarten. Womit viele Hobbyisten diese Chips meiden wollen.

Viele fallen als Ausweg darauf zurück, ihre Designs auf einem 80x86er PC zu emulieren, oder bestenfalls auf einem ARM oder MIPS basierten NAS oder WLAN Rechnerchen oder gar einem PDA. Oder sie geben eher jegliche Hoffnung auf, eigene Rechner zu bauen.

Dieser Vortrag beschreibt eine vierte Methodik, wie man auf der Basis von heutigen billigen und kleinen (aber inzwischen trotzden schnellen) Mikrocontroller Steuerungschips, sowie den Softwaretechniken von PC Emulatoren, eigene Chip Designs emulieren kann, auf etwa dem Leistungs- und Komplexitätsstand von 1980er hochintegrierten Homecomputer Chips. Das ohne dazu die PC Anschaffungs, Volumen, Stromverbrauchs und Lüfterlärm Kosten und fehlendem Look and Feel von traditioneller Homecomputer Emulatoren zu haben. Dazu werden mehrere AVR Mikrocontroller von Atmel(miss-)braucht.

Als Beispielchip wird ein mit einem VGA Monitor kompatibler Videogenerator gezeigt, der in etwa halbwegs zwischen einem VC-20 (Featuresatz, Farben, Softfont, keine Sprites) und dem Atari 800 bzw C64 (Auflösung 40x25) liegt, sowie Pläne für beliebige Mikroprozessoren, von etwa zwischen Z80 bzw 6502 (Adressbereich 64k) und 8088 (Befehlssatzumfang) Leistung, sowie ein ganzes darauf aufbauendes System.

Dieser Vortrag baut auf 2 früheren Vortragen auf, über 2006.05.01 - Rechnen mit Bauklötzchen - Rechnergrundlagen und deren Implementationen und 2008.04.26 - 8008 8080/8085 und Z80/U880 - Maschinencode und Assembler.

Wie letztes mal, wo ich zuerst mit 80% Maschinencode eine Basis legte, und dann darauf aufbauend schnell 20% Assembler, ist es auch hier zuerst 50% Mikrocontroller und Ein-/Ausgabe und 10% Video als Basis, und dann darauf aufbauend 40% meine Projekte.

Dieser Vortrag wurde später, nach einer Wiederholung am 2009.05.23 am LUG-Camp, aufgrund Zuhöhrer Feedback leicht überarbeitet (Beschreibung Videospeicher Layout und wie man damit arbeitet).

Fabrikationstechnologien für Rechner

Wer alte historische Rechner der 1940er-1960er anschaut hat noch einfache Technologie vor sich. Seien das einzelne Relais oder Röhren oder Transitoren, oder seien das kleine SSI Einzelgatter oder MSI Gatterkombinations Chips der TTL 74(x)xx Familie. Jedenfalls waren es aber universelle Standardbauelemente. Selbst die teuren Chip Entwurfs- und Fabrikationsvorbereitungskosten wurden damit anteilig über viele Kunden ihre Millionen Exemplare geteilt, die damit einzeln billig sein konnten. Der Preis dafür waren viele dieser kleinen Teile, die sich aufaddieren konnten zu einer grossen Materialschlacht, mit viel Löt-/Montageaufwand, Platzverbrauch, teuer, langsam und auch stromfressend.

Schaltungsspezifisch war damals nur deren Menge und Verdrahtung, also letztlich die Platine(n), dessen Fabrikationsvorbereitungskosten auch niedrig sind (primitive Techniken dazu kann jeder Bastler ausführen). Also konnte jeder damit etwas entwerfen und bauen, solange er die Entwurfskosten (v.a. Zeit) sowie die Logistik und Bauteilekostensumme hinbekam, was in den 1970ern, dank Einzelgatter und Gatterkombinations Chips, auch recht anspruchsvolles einfach machte. Dies führte zu einer Explosion von Designs (Rechner und auch alles andere elektronische).

In den 1970ern gab es dann einen Übergang zu MOS VLSI hochintegrierten Chips, die dann ab 1980 die Computerei dominieren. Viel drin, trotzdem klein, billig, zuverlässig, und mit Ausnahmen geringer Stromverbrauch. Das erlaubte anfangs 1970er den Mikroprozessor, sowie die dazu passenden ROM/PROM/EPROM/EEPROM bzw SRAM/DRAM Speicherchips, und damit Rechner aus wenigen grossen Chips. Damit entstanden die frühen Homecomputer (Altair, Kim-1, Apple 1 und 2, PET 2000-8000, ZX80, CPC, MSX, LC80, KC 85) und PCs (CP/M, PC und PC/XT und PC/AT, Robotron). Es erlaubte Mitte 1970er auch standard Peripheriechips (PIO Ports, Seriellports, Floppy- und Harddiskcontroller) für kompaktere und billigere PCs. Und schliesslich Ende 1970er spezialisierte Peripheriechips für kompakte aber graphisch leistungsfähige Homecomputer (Atari 800 GTIA+ANTIC, TI-99 und MSX und andere TMS9918, VC20 VIC, C64 VIC-II, Amiga Agnus+Denise+Paula) bzw leistungsfähige PCs (spätere 286|386er-Chipsets+VGA).

Das ist alles gut vom Standpunkt eines kompakten und effizienten massenproduzierten konsumierbaren Industrieproduktes her, aber wehe man will selber etwas entwerfen. Die hochintegrierten Chips sind nun selber schaltungsspezifische Spezialbauelemente, und jeder muss neben seinen Designkosten/Zeit auch die Chip Fabrikationsvorbereitungskosten alleine decken, v.a. die ganzen teuren Belichtungsmasken herstellen. Dazu kommt auch noch dass diese Kosten bei grösseren Chips ansteigen. Man muss, pro Schaltungsrevision(!), je nach Chipgrösse im Bereich $30'000-30'000'000 rechnen. Und dazu kommt auch noch etwa 2-6 Monate Produktionsdurchlaufzeit abwarten.

Firmen mit Millionenumsatz können die nötigen Kosten decken. Also kein Problem für Intel&Co, die damit ihre Mikroprozessoren und später Peripheriechips in grossen Stückzahlen verkaufen. Selbst wenn sie eine ganze Fabrikationsanlage für $1'000'000'000 (nötig für Jahr 2000er Prozessoren) bauen müssen, gibt das geteilt durch 10'000'000 Stück, einen Kostenanteil von $100/Stück.

Aber immer teurer, und immer weniger Leute die mehr Power brauchen, wird auch da irgendwann Mitte/Ende 2010er das kommerzielle Ende geben, lange bevor die Halbleiterphysik aufgibt. Wir haben bereits am VCFe 6 gewitzelt, dass das vermutlich etwa die Playstation 5 oder 6 sein wird, weil viele Zehnmillionen Gamer sich zu sehr viel Umsatz aufaddieren, den kein anderer Markt bieten kann. Aber seit einem Vortrag über die Technologie und Designfolgen moderner Konsolen (PS/3 vs Xbox360 vs Wii) weiss ich, dass selbst die PS/3 Entwicklung etwa $3'000'000'000(!) gekostet hat, und schon die PS/4 ein grosses Fragezeichen dahinter hat. Dies zumal die Wii, nur ein verbilligter und leicht optimierter und trotzdem völlig ausreichender Neuaufguss der Gamecube, sich überall weit mehr verkauft. Dazu kommt noch dass in Japan die Handkonsole NDS alle TV Konsolen zusammen schlägt, weil genug Power ausser für 3D Ego Shooter. In den USA halten sich TV Konsolen zwar noch, aber die Xbox360 hat dort weit mehr Erfolg, trotz 2/3 Entwicklungskosten. Dazu kommen als weitere Limite auch Softwarekosten, was wenige Titel ergibt, und damit weniger Käufer, PS/3 Games $30'000'000, Xbox $20'000'000, Wii nur $15'000'000, bei der PS/2 waren es noch $10'000'000. Und die Xbox bekommt auch eher PC Game Ports ab, weil sie eine PC-ähnliche Architektur hat.

Für kleinere Stückzahlen, so etwa im Bereich 10'000-1'000'000 wurden um 1980 herum "halb fertige" Chips erfunden, sogenannte Gate Arrays. Bei diesen sind alle Transistoren und ein Vorrat an Verdrahtungsstücken für alle Schaltungen identisch, und damit fertig produzierbar. Nur noch eine (oder wenige) Schicht(en) (Rest-)Verdrahtung muss funktionsspezifisch addiert werden, was die Anzahl schaltungsspezifischer Belichtungsmasken auf etwa 1/3-1/10 reduziert, und damit die Vorbereitungskosten. Diese Chips kosten dementsprechend pro Chiprevision je nach Grösse ab etwa $10'000-$30'000. Und die 2-6 Monate warten werden zu etwa 1-2 Monate reduziert. Der ZX81 war wohl der erste Homecomputer auf Basis dieser Technologie, sein ULA Gate Array Chip ersetzte die 18 TTL Chips des ZX80, daneben waren nur noch standard Prozessor, ROM und RAM sowie Spannungsregler, also 4+1=5 Chips statt 4+18=22, und er konnte erst noch leicht mehr (SLOW Modus, Anzeige während rechnen, dafür verlangsamt).

Für ganz kleine Stückzahlen, so maximal 10 (und damit eigentlich für Hobby ausreichend), bieten spezialisierte Chiphersteller sogar vollständige Chips zu ähnlichem Preis ($10'000..30'000) an, indem sie Kleinmengen mehrerer verschiedener Designs in einem einzigem Fabrikationsdurchlauf einmalig herstellen, und damit die Maskenkosten durch die Designs teilen. Das ist aber auch nur für von Unis gesponsorten Chipdesign Studenten ihren Arbeiten bezahlbar.

All das ist unerreichbar teuer für die vielen "normalen" Hobbyisten, die nur eines oder wenige Exemplare ihres eigenen Experimentes bauen wollen. Ebenso für Hersteller mit kleinem Volumen, oder die alle paar Exemplare etwas ändern wollen. Also blieben die Kleinen technologisch stehen, mit 1970er SSI+MSI TTL Logik, und eventuell Mikroprozessoren sowie ihren ROMs+RAMs sowie Peripheriechips dazu. Das Resultat blieb einige Platinen gross, das Ergebnis ähnlich wie bei Dennis Kuschel seinen 5 Platinen MyCPU (und das ist noch ohne die 1-2 Platinen Speicher und 1-3 Platinen IO, letztere soviel trotz hochintegrierten Seriellchips!) oder gar 6 Platinen VGA.

Aber es geht auch anders. Man kann auch hochintegrierte Standardchips nehmen, die zwar in Massen hergestellt wurden, mit Innenschaltung fix vorgegeben, und damit billig sind, die aber darauf ausgelegt wurden programmierbar oder konfigurierbar zu sein. Angefangen hat das mit dem (Miss-)brauch von PROM oder EPROM Programm Festspeicher Chips (ROMs scheiden da auch aus), mit Logiktabellen drin, als Logikchipersatz. Gerade für Sequenzgenerierung, Statemachines, Decodierung, komplexe Kombinationen ist das weit verbreitet.

Solche Logiktabellen haben eine sehr lange Tradition. Bereits in den 1950ern hat man im MIT Whirlwind Röhrenrechner die Ablaufsteuerung mit Logiktabellen aus Dioden (eine eingelötet oder nicht) gebaut, zum Platz und Kosten der sehr grossen und teuren Röhrenlogik reduzieren. Dabei wurden 5bit Befehlscode (vom 16bit Befehl, restliche 11bit sind Adresse) zu 2^5=32 Befehlen decodiert, und diese an 120 funktionsauslösenden Leitungen vorbeigeführt, wo eine eingesetzte Diode die jeweilige Funktion für den spezifischen Befehl auslöste. Röhrenverbrauch 5 Treiber/NOT-Inverter (pro Bit einer), 32 AND-Kombinierer (pro Befehl) und 120 OR-Sammler (pro Leitung).

Später wurden auf Logiktabellen aufbauend einige Grossrechner und Minicomputer mit microcodierter Logik implementiert. Quasi ein kleiner simpelst-Computer (die Microengine) der den eigentlichen Rechner emulierte. Wobei es 2 Sorten davon gab, die hardwareaufwendige aber schnelle "horizontale" Mikrocodierung, die nur Signaldecodierung machte, und die einfachere aber langsamere "vertikale" Mikrocodierung, die die ganze Ablaufsteuerung macht, und dabei auch x-fache Mehrfachnutzung von wenigeren und einfacheren generischen Schaltungen erlaubte. Beide waren auch kombinierbar. Alle kleineren IBM 360er/370er, die DEC PDP-10 ab KL-10, fast alle PDP-11, aber auch die 68000er und 32000er Mikroprozessoren, benutzen dies.

Auch Intel ihre 4004 und 8008 Chips wurden ursprünglich enwickelt als Mikroengines, mit sehr schmalem (8bit) vertikalen Mikrocode und sehr häufiger Mehrfachnutzung eines 4bit bzw 8bit Einzelregisters (Akkumulator) und generischer Logik (ALU) und Speicher, um einen Tischrechner bzw einen Terminalcontroller zu emulieren. Daher auch der Name Mikroprozessor, ein Alternativname zu Mikroengine. Das hatte nichts mit dem erst später entstandenen Begriff Mikrocomputer zu tun (das lief umgekehrt ab). Der 4004 verlangte noch nach speziellen ROM Chips, der 8008 konnte normale ROMs (oder damit auch PROMs oder EPROMs) benutzen. Die hier im Vortrag vorgestellte Methodik läuft auf diese Art von vertikalem Mikrocode hinaus.

Genau diese Whirlwind Diodenstruktur wurde später in Form von ROM Chips dupliziert, nur mit allen Dioden im Chip fabriziert, und dann ausgelesen per wellenförmigen Leitungen die mit den Dioden verbunden oder an ihnen vorbeigeführt wurden. Solche ROM Chips brauchen zwar auch einen Fabrikationsdurchlauf, wegen den datenspezifischen Leitungen, aber das war auch mit nur einer Belichtungsmaske, und dazu eine sehr simple. Und weil es viele verschiedene ROM Inhalte braucht, und diese sich nur in den Daten unterscheiden, kann man diese billig mit einer automatisierten datengesteuerten Maskenfertigung herstellen, deren Kosten wiederum auf die vielen Kunden aufgeteilt wird. Das waren dann nur etwa $3000, sowie nur noch etwa 3 Wochen warten. Es gab einige standard ROM Inhalte, wie den 2513 5x7Pixel Font für Drucker (im Apple 1 Videogenerator missbraucht). Aber grossteils waren die ROM Inhalte spezifisch, wie die Basic ROMs verschiedenster Homecomputer, oder die Game ROM Module der Videokonsolen.

Es geht aber auch anders. PROMs (Programmable ROMs) boten schon sehr früh eine Alternative zu dieser datenspezifischen ROM Fabrikation. Sie haben auch alle Dioden drin, aber immer alle verbunden, und sind daher als billige fixfertige Standardchips ab Stange zu kaufen. Sie werden dann vom Benutzer in Minuten programmiert bzw konfektioniert. Dies geschieht per durchbrennen von Nickelbrücken, zwischen den Leitungen und Dioden, und damit die unerwünschten Dioden "abkoppeln". Dazu wird ein starker Stromstoss benutzt, von einer hohen Programmierspannung (12.5-25V) getrieben. Daher auch der Begriff ein PROM/EPROM/EEPROM (oder heute auch eine CD) "brennen". Damit sind PROMs auch erstmals hobbytauglich. Beispiele sind Wozniak sein Diskcontroller des Apple II (PROM als Statemachine), oder die MIT Lisp Maschine (512x4bit PROMs als 9Ein/4Aus Tabellen für den Shifter), aber auch für Programme wie dem Apple 1 sein Woz Monitor (2 256x4bit als 256x8bit Speicher).

Später kamen EPROMs und EEPROMs, wo nur isolierte Kondensatoren geladen werden mussten, die damit auch entladbar sind, und damit die Chips löschbar und wiederbenutzbar. Das spart wegwerf Chipverbrauch bei Debuggen, und erlaubt experimentelle Programmiertechniken. Bei EPROMs macht man dies mit etwa 30 Minuten UV Licht Bestrahlung (braucht ein teureres Keramikgehäuse mit Quarzglas "Fenster"), bei EEPROMs mit weiterem Stromstoss in Millisekunden. Flash Chips sind verbilligte EEPROMs, die nur blockweise löschbar sind, nicht einzelne Bytes, was sich als überschüssiges Detail erwiesen hat. Die ganzen PCs vor Mitte 1990er hatten EPROMs für ihr BIOS, seither ist Flash normal. Historische Randnotitz: Die Firma Intel war anfangs ein EPROM Hersteller, z.B. das 1701 256x8bit EPROM, und sind auch heute ein grosser Flash Hersteller, auch für USB Sticks. EPROMs und Flash benutzt man auch bis heute für Logiktabellen, siehe auch Dennis seine MyCPU, die hat 6 Stück 27xxx EPROMs (je 3 für Rechenlogik (= Kombinationen) und Ablaufsteuerung (= Sequenz und Decodierung)), sie wäre sonst noch einiges grösser als 5 Platinen.

ROM (oder PROM oder EPROM oder EEPROM oder Flash) Tabellen haben ein Problem. Bedingt durch die Absicht bei Speicherchips, mit minimaler Menge Adressleitungen maximal viel Speicher auszuwählen, haben sie als Logiktabellen eine maximale Tabellengrösse für die Anzahl Eingänge die kombiniert werden. Alle ROM Sorten brauchen 2^Eingänge * Ausgange an Datenbits, was schnell viel wird. Eine 10Ein/4Aus Tabelle braucht erst 2^10*4=4096bits, 12Ein/4Aus schon 2^12*4=16384bits, 14Ein/4Aus sogar 2^14*4=65536bits. Das wird schnell gross. Die obigen MyCPU EPROMs sind immerhin 1 27C64 (2^13*8=65536bits) und 2 27C801 (2^20*8=8388608bits) bzw 3 27C010 (2^17*8=1048576bits).

Gewiefte PROM Hersteller haben diese danach zu Spezialchips weiterentwickelt, für genau solchen Logikersatz kompakt implementieren, sogenannte Programmierbare Logikbausteine (PLD, Programmable Logic Devices). Wobei Konfigurierbare Logik wohl der bessere Begriff wäre, weil kein abzuarbeitendes Program drin ist. Deren Vorteil ist keine feste volle Decodierung der Eingänge, keine 2^n Zeilen der Tabelle, nur nötige Produktterme, und damit weitaus mehr Eingänge ohne exponentielle Chipgrössenzunahme. Deswegen sind die kleiner und billiger, und auch schneller. Die PAL PLDs brauchen nur 2*Eingänge * 8*Ausgange an Bits, z.B. das 14Ein/4Aus PAL14H4 ganze 14*2*8*4=896bits statt obigen 65536bits, also 73 mal weniger.

Die ersten 1970er Chips dieser Art, PLA (optimal klein) und PAL (etwas grösser aber schneller) waren relativ limitiert, und ersetzten so bis zu 10 herkömliche TTL Chips. Sie wurden zumeist dort benutzt wo man neben hochintegrierten Standardchips den "Resten" wie Adressdecoder damit machte (z.B. den 16Ein/8Aus PLA Chip im C64 oder die PALs auf vielen 1980er IBM PC Einsteckkarten). Die MyCPU hat übrigens keine PLDs, weil Denis die Anzahl Chipsorten reduzieren wollte, und EPROMs für Programme ohnehin unvermeidbar sind.

Spätere PLDs hatten dann eingebaute Flipflops zum separate Flipflop Chips einsparen. Ebenso kann man damit die Anzahl Verbindungsleitungen reduzieren (und damit Pins und Platz). Dazu haben sie noch breitere Produktterme und Logik, weil die internen Flipflops zusätzliche Eingänge sind. Diese sind insbsondere effizient für Sequenzgenerierung und Statemachines. Moderne PAL-V und GAL Chips ersetzen etwa 10-30 TTLs, und sind wie EEPROMs elektrisch löschbar.

Wiederum erweiterte grössere und komplexere Versionen, als CPLDs bekannt, können etwa 30-100 TTL Chips ersetzen. Diese sind eigentlich mehrere separate PALs auf einem Chip, mit noch mehr internen Verbindungsleitungen zum Pins sparen. Ein grosses PAL mit vielen Ausgängen, und die alle als interne Eingänge, ergäbe quadratische Grössenzunahme, weil lange Produktterme. Hier ist die Produkttermbreite konstant etwa 32-80 Eingänge. Dazu dann aber Verbindungsleitungen, mit wenigen Bits. Erlauben statt 8-32FFs bis zu 512FFs hinauf. Z.B. wurde ein 64FF Altera Mach210 CPLD für einen signal-kompatiblen Clone des ZX81 ULA Gate Arrays verwendet.

Neben PROM-Weiterentwicklungen erschienen auch Mitte 1980er die LCA, CAL und später FPGA Chips. Eigenständige nicht von grossen ROMs abgeleitete Entwicklungen, die dem Benutzer ein "Schachbrett" von anfangs 10x10 und heute bis 1000x1000 frei konfigurierbare Logikzellen anbieten. Jedes davon mit einem einem eigenen kleinen 16bit ROM (das eine beliebige 4 Eingang 1 Ausgang Logiktabelle beinhalten kann), sowie einem 1bit Speicher. Dazwischen besteht 90% des Chips aus konfigurierbaren Verbindungsleitungen (die quasi eine "Platine" ergeben). Erstaunlicherweise kommen alle diese mit RAM als Konfigurationsspeicher, sie müssen daher beim Einschalten aus einem PROM/EPROM/EEPROM/Flash gebootet werden, wozu man oft wiederum ein CPLD oder einen Mikrocontroller verwendet, was diese Lösungen grösser und teurer als nötig macht. Grund dafür ist dass die resultierenden Chips damit schneller werden, wegen dem einfacheren und aktuellerem ROM-losen Herstellungsprozess.

Eigentlich wären FPGAs technisch ideal für den "schnell einen einzelnen hochintegrierten Chip" Anwender, solange er dafür bereit ist, dafür je nach genauem Inhalt etwa 1-3% Platz und 10-30% Geschwindigkeit eines gleich grossen industriellen Chips zu akzeptiere. Das läuft heute auf etwa maximal den Stand eines Pentum II-III hinaus. FPGAs wurden z.B. im C-One und dem 1-Chip-MSX verwendet. In einer idealen Welt, wo nur Technologie entscheidet, wäre hier an dieser Stelle ein Vortrag über FPGAs programmieren, mit eigenem Design in einem der obigen Geräten.

Leider haben die Programmierbare Logik Hersteller sich entschieden, ab der CPLD Generation ihre Kunden mit Füssen zu treten, und ihnen jegliche Information zu verwehren, wie die Teile konfiguriert werden, also wie die zu ladenden Konfigurationsbits aussehen. Man stelle sich vor, die Mikroprozessor Hersteller hätten alle ab der 16bit Generation (8086, 68000, Z8000, 32016) keinen Maschinencode mehr dokumentiert, keinen Assembler mehr geliefert, nur noch deren eigenen Compiler, für ein paar wenige Sprachen, mit einer Einstellung der Sorte "Wozu wollt ihr denn auch eigene Compiler schreiben, benutzt einfach die Chips, wir haben Jahre in unsere Compiler investiert, und wir liefern alle Sprachen der Welt, Fortran und Cobol und sogar Algol!". Diese Compiler würden ausserdem nur als Cross-Compiler auf 2-3 wenigen ausgewählten Minicomputer Sorten laufen und nicht auf den Ziel-Mikroprossoren selber. Wir hätten heute keine PCs in so einer Welt.

Dazu haben sie dann auch noch miserabelste Compiler geliefert, die Laufzeiten in Stunden oder gar einen Tag haben (der Tag war für ein Xilinx XCV1000, 128x196 Logikzellen, auf einem Jahr 2000 1GHz Pentium III PC mit 4GB RAM). Dazu sind sie schwierigstens zu benutzen, dank fürchterlicher Programmiersprachen, weil Sprachdesign durch Kommitee und danach keinerlei Sprachevolution stattfand. Das mag besser sein als 3 Monate auf Chipfabrikation zu warten, und möglicherweise auch nicht unfreundlicher als die dort üblichen Tools und Sprachen, aber es ist meilenweit von dem entfernt, was man in den letzten Jahrzehnten als Mikroprozessor/Mikrocontroller Programmierer oder TTL Logik Erbauer gewohnt ist. Und "dank" absichtlich fehlender Doku ist es nicht möglich, bessere Tools zu machen, trotzdem dass Designansätze für weitaus brauchbarere Tools bekannt wären. Kurzum: Technisch hui aber kommerziell pfui.

Aus dieser Situation heraus frustriert hab ich Dezember 2003 mein Projekt begraben, den 1960-80er DEC PDP-10 36bit Grossrechner in einem einzelnen FPGA Chip zu clonen. Zu dem Zeitpunkt verbrauchte die implementierte Infrastruktur und halbe Befehlssatz etwa 2/7 eines mittelgrossen 96x64 Logikzellen FPGAs. Ebenso aufgegeben habe ich einen Versuch, den Virtex FPGA zu Reverse-Engineeren, zum eigene Tools herstellen. Das nachdem klar wurde, dass Reverse Engineeren + Tools schreiben + PDP-10 schreiben etwa 10 Jahre nehmen würden, und bis dann der Chip veraltet wäre.

Zudem wären bis dann die bereits existierenden PC-basierten Emulatoren automatisch schneller, selbst wenn auf billigen ARM Rechnerchen portiert. Schon während ich am Projekt dran war, kurz vor Aufgabe, hat bereits jemand einen solchen Emulator auf einem 200MHz StrongARM basierten Linux PDA (Sharp Zaurus) betrieben, mit Geschwindigkeit etwa wie dem historischen Original! Seine Bezeichnung dafür: Eine ARM Microengine mit KLH-10 Mikrocode (KLH-10 ist der Name vom Emulator). Das selbige würde auch für MIPS WLAN oder ARM NAS Geräte gelten, die beide um die Zeit aufkamen. Linux drauf, RS232 für serielle Konsole rausführen, USB Stick als Diskplatz, KLH-10 installieren, PDP-10 Systemsoftware dort drauf installieren, beim Booten automatisches login und KLH-10 starten. In wenigen Tagen getan. Damit war das Ziel den PC loszuwerden eigentlich bereits erledigt, solange man ein RS232 Terminal hat und einem das als Anzeige ausreicht. Und in 10 Jahren wird das mit modernen MIPS oder ARM so schnell sein wie ein Virtex-I basierter Clone.

Die Problematik doch eigene Rechner bauen zu wollen, ohne CPLDs oder FPGAs, aber auch ohne 100e von TTL Chips, und auch ohne einen PC mit Emulator, liess mich aber nicht los. Es muss doch einen anderen Weg geben. Die Lösung lief mir über den Weg, als jemand einen primitiven Videogenerator für Schwarzweiss NTSC Fernsehen vorstellte, der für Pong spielen ausreichte, also 40 Pixel pro Zeile lieferte. Das PIC Game System war auf der Basis eines nicht gerade leistungsfähigen PIC16 Mikrocontrollers. Ein weiteres Projekt hatte es danach bis zu 64x44 Pixel VGA Monitor geschafft, mit Farben, auf einem etwas besseren PIC18. Limite war bei beiden wie langsam der Controller die Pixel hinausschieben konnte. Das SX Game System hatte einen übertakteten Ubicom benutzt um sogar NTSC Farben zu erzeugen.

Eigentlich war das gar nicht überraschend. Mikroprozessoren wurden ja als Emulatoren entwickelt, und in Form von Mikrocontrollern lediglich mitsammt dem nötigen Speicher auf einen Chip reduziert worden. Und PCs als Homecomputer Emulatoren waren ja gang und gäbe, wenn auch erst nach etwa 300MHz auch so schnell wie die Originale, und das nur mit massiven Resourcenverbrauch, Stromfrass und Lüfterlärm zum die Wärme loswerden.

Mein Interesse war damit geweckt. Aber meine Anforderungen, eine volle Atari 800 oder C64 Niveau 40x25 Zeichen Anzeige (weil die Dragon 32 32x16 Anzeige mühsam wenig war) mit mindestens 4x8 Pixel Font in mindestens den 8 Primärfarben zu haben, sah nicht machbar aus, weil die Controller zu langsam für das schnelle VGA Timing waren. VGA ist nötig für dessen einfaches RGB Signalisierungsverfahren. PAL Fernsehen Verfahren tu ich mir nicht an, das ist kompliziert, und braucht so noch viel mehr Rechenleistung, trotz langsameren Signalen (und der Ubicom Chip ist grässlich, ein geklontes uralt PIC16F5x Modell, und wird ohnehin nicht mehr hergestellt).

Letztes VCFe erschien das AVR ChipBasic Projekt, das auf einem schnellen AVR Controller 30 Zeichen pro Zeile, mit 180 Pixel pro Zeile, in 8 Farben auf einem SCART Fernseher (die können teils auch RGB Verfahren) hinbrachte. Statt Faktor 10-30 nur noch Faktor 2-3 daneben. Es muss doch gehen! Ich hab das dann zuhause sofort genau nachgerechnet: Es sollte klappen! Das Resultat ist heute mein SoftVGA Projekt, und diesen Vortrag der das Projekt als Beispiel benutzt.

Man beachte, dass die Leistung eines AVRs nur gerade noch ausreicht zum einen Videogenerator machen. Dazu noch einen Prozessor machen, oder gar Sound dazu, liegen nicht mehr drin. Diese sind ja auch keine 100e MHz x86 PC Prozessoren. Das ist aber kein Problem, weil man dies mit wenigen weiteren AVRs machen kann, pro Funktion einen, mehrere Chips. Das war bis in die 1990ern hinein ja auch die normale Bauweise, dass pro Funktion ein eigener hochintegrierter Chip genommen wurde, das ist also sogar das passende Design. Und klein und billig und stromsparend genug dafür sind die AVRs ja, in letzteren beidem sogar besser als die original 1980er NMOS Chips.

Mikrocontroller

Intel hat, wie aus dem letzten Vortrag bekannt, 1971 mit dem 4004 den ersten frei erhältlichen 4bit Prozessor auf einem Chip geliefert, und 1972 mit dem 8008 den ersten 8bit nachgeliefert. Diese waren zwar beide für einen spezifischen Busicom Tischrechner und einen spezifischen CTC/Datapoint Terminal entwickelt worden, aber universell brauchbar. Der 4004 brauchte aber noch spezielle ROM (4001) und RAM (4002) Chips, daher gab es keine Variante mit PROM oder EPROM, also wieder ROM Fabrikation. Der 8008 dagegen lief mit standard ROM/PROM/EPROM und SRAM Chips, und war damit der erste für jedermann brauchbare Prozessor, und damit ein weitaus wichtigerer Durchbruch.

Wenig bekannt ist, dass Texas Instruments etwa gleichzeitig einen sehr minimalen 4bit Mikrocontroller (TMS-1000) geliefert hat, der unter anderem in einigen Spielzeugen verbaut wurde, aber auch die Basis von vielen ihrer 1970er Taschenrechnern war (TI war damals und ist bis heute ein bedeutender Taschenrechner Hersteller). Diese waren intern genauso emuliert wie die 4004 basierten Tischrechner. Nur eben alles auf einem Chip statt erweiterbar aus separaten Prozessor und 1-16 ROMs und 1-16 RAMs. Das ganze war auch nur mit ROM erhältlich, kein Wunder bei dem Platzproblem eines Einzelchips.

Sehr wenig bekannt ist, dass die Firma Fairchild in 1975 einen 8bit Controller annäherte, indem sie einen 2-Chip Controller namens F8 lieferte. Ein Chip ist ROM (wieder keine PROM/EPROM Auswahl, nur mit ROM Fabrikation) und die eine Hälfte des Prozessors (Programzähler und Sprunglogik), der andere Chip RAM und die andere Hälfte des Prozessors (ALU, Register)! Beide Hälften haben eine Kopie des Befehlsregisters und Teile der Ablaufsteuerung. Dieser wurde auch in einigen Spielen und Geräten eingebaut. Er soll der meistverkaufte Prozessor von 1977 gewesen sein. Sein grösster historischer Wert ist wohl dass er Intel zum 8048 inspirierte.

Etwas bekanner ist, auch vom letztjährigen Vortrag, dass Intel, der "alle 3 Jahre 4 mal soviele Transistoren" Logik folgend, in 1977 mit dem 8048 (und nachgezeichnetes Handbuch) den ersten 8bit Mikrocontroller lieferte. Das war wiederum ein einzelner Chip auf dem sich neben einem vollständigen 8bit Prozessor auch 1k ROM für Programcode, sowie 64 Bytes SRAM für Daten, sowie 3 8bit IO Ports und ein Timer sich befanden. Also ein kompleter kleiner 8bit Steuerungscomputer, ohne Abstriche, auf einem Chip. Nur ein paar wenige passive Bauteile (Stecker und Analog Krempel) anschliessen und man hat die ganze lauffähige Hardware eines recht brauchbaren Computers vor sich, nur noch Software dafür ist nötig. Leider typisch für die Intel 4004/4040 Gruppe, die das Teil machte, anfangs nur mit ROM eingebaut, kein PROM oder EPROM, also auf Chipfabrikation warten, wenn auch "nur" die billigere und verkürzte wie bei ROMs üblich. Später fand Intel zu seinen EPROM Wurzeln zurück und es wurde mit dem 8748 eine EPROM Version nachgeholt, und erstmals konnte jeder einen Mikrocontroller benutzen, wie zuvor den 8008 (und inzwischen den 8080, sowie bald den 8085 und die 8086/8088).

Natürlich war der 8048 (und die lediglich 2 bzw 4 mal grösseren 8049 und 8050) nur der Anfang. Intel lieferte 1980 bereits den Nachfolger 8051, einen gemischten "das Beste aus" Prozessor von 8048 und 8085. Der hatte anfangs 4k ROM für Program (spätere Modelle 8052..8058 mit 8k bis 64k), von Anfang an auch EPROM Varianten (875x), und 128 Bytes SRAM für Daten (aber leider auf max 256Bytes in allen späteren Modellen begrenzt, und auch die oberhalb von 128Bytes nur reduziert nutzbar). Dieser war trotz dieser SRAM Achilesferse ein Riesenerfolg, und wird heute von mehr als 30 Firmen lizenziert und von irgendwo 3-10 Firmen geklont, mit verschiedensten Erweiterungen, z.T. Flash Varianten (895x) statt ROM oder EPROM, und in verschiedensten Pinouts von 20-100 Pins angeboten. Der häufigste Computer der Weltgeschichte, selbst den Z80 hat er überholt. Hier am VCFe war der 8051 vor 4 Jahren Subjekt eines Vortrages, und landete als Folge davon auch im kbdbabel Projekt (eine Atmel 20Pin Flash Variante).

Daneben haben, analog zu den Mikroprozessoren, einige andere Firmen ihre eigenen Mikrocontroller Familien herausgebracht. Zwei davon sind heute sehr gross verbreitet geworden:

Heute haben die beiden ihre PIC und AVR auf alle 3 Märkte Billig/Mitte/Hochleistung ausgedehnt. Ebenso haben das die Intel Lizenzen und Clones das mit dem 8051 gemacht. Das ergibt heute über alle 3 Segmente hinweg ein 8051 + PIC + AVR Triumvirat, im Gegensatz zur PC 80x86 Einerlei. Und die PIC Fan vs AVR Fan Debatten errinnern stark an die 6502 Fan vs Z80 Fan Debatten von früher. Der Spass den mit den Teilen hat ebenso.

Der AVR Mikrocontroller

Hier vergleiche ich den im AVR verwendeten Prozessor mit den 8008/8080/8085/Z80/U880 Prozessoren vom letztjährigen Vortrag. Das ganze sollte aber auch ohne diesen gehört zu haben halbwegs verstehbar sein, auch wenn man weniger Details davon haben wird. Ich verlinke hier bei jedem Abschnitt auf das jeweilige Kapitel des letztjährigen Vortrages.

Wie nicht anders zu erwarten hat der AVR eine volle ALU drin. Genauso ist diese identisch verdrahtet, dass sie an Operationen genau alle 3 Logikfunktionen AND/OR/XOR, und beide Arithmetikfunktionen Addition und Subtraktion kann, und sonst keine weiteren.

Zusätzlich zur ALU hat der AVR auch noch eine Multiplikationseinheit für 8*8bit mit 16bit Resultat. Zumindest ist dies so bei den grösseren ATmega Serie von Chips, die Klein-/Billigserie ATtiny kann das nicht (das ist einer der Hauptunterschiede). Division kann keiner von ihnen. Diese Multiplikation hat der 8051 überigens auch, ebenso die 8086/8088 und der 6809. Und im Gegensatz zum AVR (und dem 6809) kann der 8051 auch dividieren, ebenso die 8086/8088.

Im Gegensatz zu allen Intel Chips, die alle Einadress Rechner sind (zumindest vor dem 8086) und dafür einen Akkumulator haben, zum damit die Rechnung V3 = V1 OP V2 in 3 Schritte zerlegt als A = V1; A = A OP V2; V3 = A rechnen, ist der AVR (wie der 8086) ein Zweiadress Rechner, und kann sie daher direkter ohne Akkumulator in 2 Schritte zerlegt als V3 = V1; V3 = V3 OP V2 rechnen. Dies reduziert die Anzahl Befehle, und damit Taktzyklen, und damit Programm Laufzeit. Intel hat beim 8086/8088 diesen Wechsel auch vollzogen. IBM hat dies ab der 360/370/390/Z-Serie auch so gemacht, ebenso DEC ab der PDP-11 Serie. Zweiadress ist also von Grossrechner über Minicomputer bis Mikroprozessor und Mikrocontroller uniform der Endpunkt der Entwicklung geworden!

Die Flags sind fast identisch. Die Carry/Übertrag, Sign/Vorzeichen und Zero/Null Flags sind sogar ganz identisch. Lediglich die Intel Eigenheit vom Parity Flag fehlt dem AVR (und allen nicht-Intel Prozessoren). Dieser vierte Flag ist fix immer Overflow/Überlauf, was bei Intel fehlte und bei Zilog im Z80 teilweise drin war. Addition und Subtraktion gibt es genauso beide ohne und mit Übertrag Flag. Auch die nicht abspeichernde nur Flags setzende "Vergleichs" Subtraktion ist da, und die hat es im AVR sogar auch ohne und mit Übertrag. Alle anderen haben das nur ohne.

Die Register des AVR sind eine Augenweide: Anstellen von den 6 Registern BCDEHL (und dazu noch A als siebentes) hat es volle 32 davon, schlicht mit R0 bis R31 durchnummeriert, keine Namen. Das ist ein massiver Registersatz, vergleichbar mit den grossen MIPS oder SPARC oder ARM 32bit RISC Prozessoren (die haben 16-32 32bit Register). Man kann damit viele Daten gleichzeitig im Prozessor halten und schnell benutzen, ohne von/zum Speicher Laden und Speichern, was ihn noch schneller macht. Das ist noch besser als Registerbänke wie beim Z80. Von den Registern sind allerdings nur 16 uneingeschränkt nutzbar, bei den anderen 16 kann man keine Befehle mit Konstante benutzen, also ist kein Rn = Rn OP Konstante möglich, also sind die mehr wie ein kleiner Register-schneller Speicher ohne Laden und Speichern anzuschauen, was aber auch sehr nützlich ist. Erstaunlich sind es R0..R15 mit der Limite und R16..R31 die vollwertig sind!

Da die Register einerseits grösstenteils universell sind, anderseits doch immer wieder Spezialitäten haben, empfiehlt es sich, eine Systematik zu entwickeln, welche man für was benutzen will. So eine, abgeleitet von der offiziellen für den MIPS Prozessor, habe ich für meine Projekte entwickelt.

Speicherzugriffe geschehen ebenfalls entweder via ein Registerpaar oder eine 16bit Konstante adressiert. Aber im Gegensatz zu nur einem HL Paar (M Pseudoregister Modus) und sehr eingeschränktem Gebrauch von BC oder DE hat es hier 3 vollwertige Registerpaare R26:R27 R28:R29 R30:R31 als Adressen. Und mit Adresskonstante ist nicht eine Erweiterung welche auf A und HL Laden/Speichern limitiert ist, sondern geht zu/von beliebigen Registern. All die 8008/8080/8085/Z80/U880 Probleme mit mehrere Adressvariablen, und die 8080/8085/Z80/U880 Basteieln/Limiten zum sie umgehen, kann man hier getrost vergessen.

Auf den Speicher gehen aber nur Rn = Speicher[] (laden) und Speicher[] = Rn (speichern)Befehle, keine gleichzeitige Arithmetik mit Speicher[] drin. Dazu braucht man einen separaten Arithmetik Befehl und ein temporäres Register dazwischen. Aber man hat ja genug Register, und man kann dafür auch ideal die 16 Konstante-losen Register benutzen. Und die Sachen die in den 16 Registern "Schnellspeicher" sind, sind von dieser laden-ohne-Arithmetik Limite auch nicht betroffen, da bereits geladen.

Wegen der 8+8=16bit Speicheradresse dieser Registerpaare ist das Speicher[Rn1:Rn+1] Array Rebenfalls auf maximal 64kBytes beschränkt. SRAM hat es auf dem Chip aber je nach Modell ohnehin nur 64Bytes bis 16kBytes. Genau 2 40Pin Modelle (ATmega8515 und ATmega162), sowie alle 64Pin und 100Pin Modelle, können aber auch externes SRAM anhängen, bis zu den max 64k (minus dem was intern schon benutzet ist). Der externe Speicher ist allerdings langsamer als der interne wegen der Signalisierung. AVR und 8048/8051 verwenden das selbige Signalisierungs Verfahren wie auch beim 8085 und 8086/8080, mit der Adresse und den Daten über die selbigen Pins, und einem externen 74373 Chip zum sie auftrennen. Die ATmega8515 und ATmega162 sind auch zu 8051 Pinout kompatibel).

All das gilt allerdings nur für den Datenspeicher, der Programmspeicher ist separat davon. Der SRAM Speicher (intern und extern) kann nur Daten aufnehmen, keinen Programmcode. Dieser kann nur im internen Flash Speicher drin sein, und gar nicht extern (und ist also damit nicht zu Laufzeit generierbar, auch nicht per externem Program RAM as Daten RAM beschrieben). Das ist die erste Eigenartigkeit und Limitation, bekannt als Harward Architektur. Dies im Gegensatz zur von Neuman Architektur der 8008/8080/8085/Z80/U880 oder 8086/8088 oder 6800 oder 6809 oder 6502 Mikroprozessoren. Die 8048/8051 und PIC Mikrocontroller sind auch Harward Architekturen, ebenso die 4004/4040 Mikroprozessoren. Nur kann man die 8048/8051 per externen Datenspeicher und externen Programmspeicher "überlagern" austricksen.

Dafür können bei allen Harward Architekturen die Programmspeicher und Datenspeicher dann auch gleichzeitig benutzt werden, zum den nächsten Befehl bereits holen während der aktuelle ausgeführt wird, was die ganzen Controller (noch) schneller macht.

Und damit kommt auch die zweite Harward Eigenart: Flash und SRAM sind nicht nur 2 separate Speicher Teilchips, mit festen Aufgaben, und gleichzeitig ablaufenden Zugriffen. Man muss auch als Folge davon separate Befehle benutzen zum auf sie zugreifen. Für Flash gibt es nur einige wenige und langsame Befehle, weil ausser Konstanten und Datentabellen man dort eh nichts auslesen muss. Ärgerlich ist dass dafür nur das letzte Registerpaar R30:R31 benutzt werden kann. Und dass die Adressen Zahlenkonvention dabei erst noch etwas unlogisch ist. Das trifft einem aber auch nur wenn man Tabellen von Konstanten aus dem Flash auslesen will. Meine Font Ausleserei wurde auf diese Art verlangsamt, wesshalb ich auf Font ins SRAM kopieren wechseln musste, und seither dort Platzprobleme habe, dafür aber auch Softfonts bekommen habe.

An Operationen gibt es einige. Viele davon kommen mit je 2 Operanden daher, als Rn1 = Rn1 OP Rn2, da dies ja ein Zweiadress Rechner ist. Wegen dazu 2 mal aus 32 Register auswählen braucht es dafür 2*5bit. Also ist nix mit 8bit Befehlen, es braucht pro Befehl 16bit, 2Bytes, auch 1Wort genannt. Heute haben wir Chipfläche und Speicherplatz, welche auf diese Art in Geschwindigkeit umgesetzt wird, weil es als Folge davon weniger Befehle braucht, was das ganze eben schneller macht. Die Programgrössenzuname wird auch durch die weniger Befehle teilweise kompensiert. Die dazu nötige grössere Menge Programbits pro Befehl können schnell transferiert werden, über 16 Leitungen, weil Prozessor und Flash auf dem gleichen Chip sind, und damit keine Pin Anzahl Limiten mehr im Weg sind.

Bei Operationen mit Konstanten statt Rn2 wird es problematisch, denn die 8bit Konstante muss in die 16bit mit rein, und lässt so nur noch 8bit frei. Daher können auch nur 16 Register (brauchen nur 4bit zum Auswählen) mit Konstanten umgehen, damit 4bit für die Operation auswählen übrig bleiben.

Auch die separaten Rn = Rn +oder- 1 Befehle sind da, trotz keinem Umweg über einen Akkumulator für beliebige Addition/Subtraktion einer Konstante zu einem Register. Diese erlauben aber, jedes der 32 Register damit zu benutzen, auch die 16 ohne Konstanten. Das gilt ebenso auch für Rn = 0 und auch Rn = 0 - Rn sowie Rn = Rn XOR -1 (alle Bits invertieren). Die beiden Rn = Rn *oder/ 2 sind ebenfalls da, auch ohne und mit Übertrag, auch für alle 32 Register. Dazu kommt eben noch bei ATmega eine volle Multiplikation, allerdings mit Limiten, es wird immer R1:R0 = Rn1 * Rn2 gerechnet, weil das 16bit Ergebnis nicht in Rn1 passen kann.

Zum 16bit Adressen rechnen ist aber nur sehr wenig vorhanden, weniger als bei den 8080 Erweiterungen. 16bit Konstante laden muss man mit 2 mal 8bit Konstante laden machen. Es gibt 16bit Registerpaar Kopieren für beliebige Register, aber nur im Prozessor drin, nix von/zu Speicher. Ebenso gibt es Registerpaar +oder- 6bit Konstante, aber nur für die Adressregisterpaare R26:R27 R28:R29 R30:R31 sowie noch für R24:R25 welche damit zum universellen 16bit Zähler werden. Anderseits gibt es für den häufigen Fall von Adressregisterpaar +oder- 1 die Möglichkeit, dies direkt während dem Speicherzugriff "nebenbei" rechnen zu lassen. Kein separater Befehl ist nötig, und Null Zeitverbrauch, also noch schneller, sehr gediegen.

Der Programmzähler ist ganz normal, er fängt nach Reset mit PC = 0 am, macht aber wegen den 16bit/2Byte/1Wort Befehlen und 16bit breitem Programmspeicher nur +1 nach 1 Wort, was mit 16bit Adressen bis zu 64kWort=128kByte Flash erlaubt. Fast alle Befehle sind nur 1 Wort gross (daher sind Konstanten auch im 16bit Wort drin, nicht in einem zweiten Wort danach!), ausser genau 4 Befehlen die alle 2Wort sind (2 davon sind das Laden und Speichern mit 16bit Adresskonstante). Zusammen mit nur 1 Taktzyklus pro Speicherzugriff, und Datenzugriffe während der nächste Befehl bereits geholt wird, werden etwa 80% aller Befehle in 1 Taktzyklus ausgeführt, was zusammen mit hoher Taktfrequenz die sehr hohe Leistung ergibt. Etwa 14MIPS bei der alten 16MHz Serie und 17MIPS bei der neuen 20MHz Serie. Vergleiche: Ein 4MHz Z80 hat etwa 1MHz Speicherzugriffe und davon 2..3 pro Befehl, also 0.33..0.5MIPS, also etwa 1/40 an Leistung. Ein 1MHz 6502 (im C64) hat 1MHz Speicher und davon etwa 3..4 pro Befehl, also 0.25..0.33MIPS, also etwa 1/50 an Leistung. Ein 24MHz 8051 (normal, es gibt die in 12..60MHz) hat 4MHz Speicher (also 2..10 möglich), und davon 2..4 pro Befehl, also etwa 1..2MIPS, also etwa 1/10 an Leistung. Dazu kommt dass der AVR oft mehrere Z80 oder 6502 oder 8051 Befehle in einem einzelnen zusammenfasst (z.B. die automatische Adressregisterpaar +oder- 1), also ist er je nach Program und Vergleich etwa 10..100 mal schneller.

Wenn man nun bedenkt, dass ein 3.58MHz Z80 mit etwas Hilfsschaltung es geschafft hat im ZX80 32 Zeichen pro Zeile (genau 1 Zeichen pro 4-Takte Befehl!) in Schwarzweiss auf einen Fernseher zu schicken, zeigt sich dass der AVR der ideale schnelle Chip ist zum ohne Hilfsschaltungen Videogenerierung versuchen, wie es auch beim ChipBasic (selbiger Chip) demonstriert wurde. Die alten viel zu gering aufgelösten Versuche waren alle mit langsameren PIC Chips gemacht worden.

Die Programmsprung Befehle sind normaler Standard. Unbedingte und bedingte Sprünge, wenn auch letztere mit 16 Bedingungen, darunter auch mit Kombinationen von Flags. Alle gibt es in PC = PC + Konstante Ausführung, bedingte mit nur 7bit Konstante (aber das sind ja +63/+64 Worte!), unbedingte mit 12bit (+2047/-2048 Worte). Unbedingte gibt es auch mit PC = 22bit Konstante (das und Unterprogram sind die beiden anderen 2Wort Befehle), was den AVR auf 22bit PC limitiert, also 4MWort=8MByte Programmspeicher, was gigantisch ist. Momentan gibt es Chips mit 1-256kByte davon. Ebenso gibt es für berechnete Sprünge ein PC = R30:R31 (auch wieder nur das eine Paar möglich, wie beim Datentabellen auslesen), wobei in Chips grösser als 128k Flash daraus ein PC = 0:R30:R31 wird, und ein separater PC = EIND:R30:R31 Befehl addiert wurde (mit EIND von einem Hilfsregister). Leider sind die Adress Zahlen in R30:R31 für Datentabelle lesen (will Byteadressen) und für berechneten Sprung (will Wortadressen) nicht konsistent, Datentabelle braucht EIND bereits ab grösser als 64k!

Es gibt kein kombiniertes Rn = Rn - 1 gefolgt von bedingtem Sprung falls Rn != 0 für Herunterzählschleifen. Da müssen 2 Befehle hinein, wie zur vor-Z80 Zeit (8048 und 8051 können das wie der Z80). Und erst recht gibt es keine Z80 Block Kopiererei. Darin ist der AVR auch folglich "nur" 10 mal so schnell wie ein Z80/U880, oder 20 mal ein 8080/8085. Zum Vergleich, nur den Schleifen Teil ohne Register vorbesetzen:

Für Unterprogramm Aufrufe gibt es alle 3 identischen Adressmethoden wie bei unbedingten Sprüngen, also relativ 12bit, konstant 22bit und berechnet mit Register R30:R31 (bzw 0:R30:R31 oder EIND:R30:R31). Adresse abspeichern für Rücksprung geht mit einem normalen nach unten wachsenden Stack im SRAM. Dieser hat soviel Platz wie man dem gibt (8048 ist auf 16Bytes limitiert, 8051 unlimieriert aber nur 256Bytes RAM). Dessen Adresse steht in 2 Hilfsregister SPH:SPL, und muss wie gehabt beim Aufstarten einmal gesetzt werden. Daten zu/von Speicher[SPH:SPL] geht auch, aber nur 1 Byte aufs mal, keine Registerpaare, dazu sind 2 Befehle nötig.

Programme in den Rechner Laden

Damit sind wir die Befehle (bis auf die wieder ausgelassenen Ein-/Ausgabe Befehle) durch, und kommen zu dem was total anderst ist: Wie bekommen wir unser Program da in den Chip hinein! Der Programmspeicher ist ja kein RAM wie bei einem Homecomputer oder PC, sondern Flash. Und damit ist er nicht per Software modifizierbar (ausser mit gewissen Klimmzügen), und damit man kann auch nicht per Monitor oder Betriebsystem Programme laden. Und Monitor oder BIOS ist da auch keiner/keines drin, also ein Henne-Ei Problem. Und Disk zum etwas davon laden hat es ohnehin keine in einem 1-Chip Rechner. Also ist nix mit PC-artig von Floppy oder CD oder USB booten und dann auf interne HD installieren.

Und da das Flash ja im Chip drin ist, kann man es auch nicht ausstecken und in einem externen Programmiergerät beschreiben, analog zu PC Harddisk ausstecken und in anderen PC einbauen.

Das ist eine Problematik die alle Mikrocontroller haben, aus selbigem Grund, alles auf 1 Chip. Also haben alle Mikrocontroller einen speziellen Flashing Modus eingebaut, quasi die selbige Logik wie bei einem Front Pannel. Dieser wird aber nicht mit Schaltern und Lämpchen von Hand betrieben, sondern mit Signalen die man via einem am PC anhängbaren Adaptor automatisch erzeugen kann. Manche Controller benutzen dazu eigene spezialisierte Signalisierungen (z.B. 8748), manche benutzen 3-Draht RS232 (z.B. die 8751/89C51), manche andere standardisierte Schnittstellen (z.B. die 89S51 und AVR das SPI Seriellbus System).

Verschiedene für AVRs programmieren taugliche SPI Adaptoren gibt es in Varianten für Parallelport (Offizielles Entwicklungssystem STK200 (Seite 10-2) und nur-Programmieradaptor Nachbau STK200) oder für Seriellport (Offizielles Entwicklungssystem STK500 und Programmieradaptor Teil davon Beschreibung AVR910 (Seite 10)) oder für USB (USBasp). Damit wird der Chip angehalten (Reset Leitung aktiv), das Flash mit dem Inhalt eines speziell formatierten PC Files beschrieben/geladen, und der Chip losgelassen (Reset inaktiv).

Angesteuert wird das Ganze mit einem einfachen kleinen PC Program, welches das File in das Flash kopiert. Für Windows liefert der AVR Hersteller Atmel eines kostenlos, für Linux gibt es 3 davon (avrdude, avrp und uisp).

Bei jedem AVR basierten Rechner muss man dafür einen "Programmieranschluss" bereitstellen, einen 2x5pin oder 2x3pin Pfostenleistenstecker, an dem alle programmierrelevanten SPI Pins verdrahtet sind, plus eventuell debuggingrelevante Pins dazu:

  Blick von oben auf den (erweiterterten) STK200-kompatiblen Stecker
  10pol Bandkabel, mit farbig markiertem Draht am 1-Ende des Steckers

                              1   2
         MOSI, Daten PC->AVR   o o   +5V oder (+3.3V), AVR->Adaptor versorgen
  *** Test LED, AVR->Adaptor   o o   RxD, PC->AVR für USB Debug ***
              RESET, PC->AVR   o o   TxD, AVR->PC für USB Debug ***
    SCK, Takt für Daten   o o   GND / 0V
         MISO, Daten AVR->PC   o o   GND / 0V
                              9   10

  *** = fakultativ, Test LED fehlt oft am Adapter
                    Debug RxD+TxD sind Erweiterung, sonst auch GND / 0V

  Alle ausser TxD sind direkt verbinden, TxD muss einen 1kOhm Widerstand haben.
  Ebenso hat RxD auf dem Adaptor (dessen TxD) einen 1kOhm Widerstand. Beide
  davon um Kurzschluss zu vermeiden, bei anstecken an nicht erweiterten
  Adaptern oder Geräten (mit dort GND / 0V drauf).


  Blick von oben auf den (kleineren) STK500/AVR910-kompatiblen Stecker
  6pol Bandkabel, mit farbig markiertem Draht am 1-Ende des Steckers
  Signalumfang ist STK200, ohne LED, ohne mehrere GND, ohne Debugerweiterung

                             1   2
        MISO, Daten AVR->PC   o o   +5V oder +3.3V AVR->Adaptor versorgen
   SCK, Takt für Daten   o o   MOSI, Daten PC->AVR
              Reset PC->AVR   o o   GND / 0V
                             5   6

  Alle Leitungen direkt verbinden, keine Widerstände da kein TxD oder RxD.
    

Am Schluss sieht das ganze bei meiner Ausrüstung so aus: Links Laptop, dann 40pin AVR Experimentierboard (mit ATmega32 drin) mit oben das VGA Interface und Kabel, dann separate Debug Erweiterung mit darüber RS232 LED Tester und Nullmodem, rechts STK200 Adaptor Nachbau mit darüber Parallelport LED Tester.

Das Zielprogramm schreiben und assemblieren (oder compilieren) und das speziell formatierte File zum kopieren generieren muss man logischerweise auch auf dem PC. Der Assembler ist, da auf dem PC laufend, ein Batch Assembler, ein Zeilenassembler macht da ja keinen Sinn. Offiziell ist ein Mnemonic basierter Assembler, kein Algorithmischer, mit den üblichen Labels, Konstanten, etc. Ein völlig normales Standard Durchschnittsteil also. Für Windows liefert wiederum Atmel einen kostenlos, für Linux gibt es einen kompatiblen Nachbau (avra). Dazu gibt es mehrere kommerzielle und freie C Compiler, inklusive unter Linux einer gcc Portierung, mitsammt teilweiser C++ Fähigkeit.

Daten Ein- und Ausgabe

Bisher habe ich alles was mit Ein- und Ausgabe zu tun hat weggelassen, sowohl im Hardware Vortrag vor 3 Jahren, wie auch im Maschinencode und Assembler Vortrag letztes Jahr, wie auch in diesem. Grund war, wie damals angegeben, dass Ein- und Ausgabe sehr vielfältig ist, und damit sehr viel Material zum beschreiben wäre, mehr als den ganzen Rest der Rechnerei! Ein Z80 ist eben immer ein Z80, ebenso ein 6502 ein 6502, egal ob in einem Homecomputer, oder einem PC, oder einer Steuerung, oder einem Automaten. Ein Hersteller macht einen universellen Chip, genau das macht Prozessoren auch massenproduziert und günstig. Auch Speicher sind immer das selbige, nur Menge und Adressanordnung der Sorten varieren. Ein-/Ausgabe dagegen macht den Unterschied vom Homecomputer zum Automaten aus, und beschäftigt 1000e verschiedener spezifischer spezialisierter Firmen. Das hätte viel mehr Platz gebraucht, und die Vorträge waren ohnehin bereits zu lang.

Für diesen Vortrag werden nun ein paar Kenntnisse von Ein-/Ausgabe benötigt, daher muss ich diese hier nachholen. Allerdings werde ich das nur für genau eine sehr simple Sorte davon machen, dem Parallel Input/Output (PIO) Verfahren. Der AVR kann viele mehr, aber SoftVGA verwendet, zumindest soweit es diesen Vortrag anbegeht, nur das.

Ein-/Ausgabe besteht wiederum aus 2 Teilen, dem digitalen der mit dem Prozessor verbunden ist, und dem analogen der mit der Aussenwelt verbunden ist. Diese sind direkt an einander gekoppelt. Dieser Abschnitt beschreibt die Details des generischen digitalen PIO Teil, sowie macht generelle Aussagen zum schaltungsspezifischen analogen Teil, welcher später im SoftVGA Kapitel präzisiert wird.

Jeder Rechner kann Speicher beschreiben und danach wieder auslesen. Technisch tut er beim Schreiben nur einem von den vielen Speicherworten per Speicheradresse auswählen und die dortigen Flipflops mit einer Kopie von den 0 oder 1 in einem Register beschreiben. Beim Lesen tut er wieder per Speicheradresse eines der Speicherworte auswählen und ein Register im Prozessor mit einer Kopie beschrieben. PIO verwendet nun nichts anderes als einen Seiteneffekt davon, nämlich dass die 0 und 1 in dem Speicher drin elektrischen Spannungen entsprechen, traditionell 0V und 5V.

Parallele Ausgabe verwendet Chips mit einigen wenigen speziell präparierten Speicherzellen, deren 0V/5V Zustand per herausgeführte Leitungen die Aussenwelt beeinflussen kann, z.B. eine Leuchtdiode mit Strom versorgen damit sie leuchtet, oder einen Transistor oder Relais auslösen für grössere Lampen oder Motoren schalten, oder ein Servo anpulsen zum etwas verschieben. Oder beliebiges anderes. Ein normaler Satz von Flipflops (z.B. 74374, 1Adresse a 8bit) reicht bereits für normale PIO Ausgabe. Normal gilt Bit 0 = 0V = Stromfluss = ein und Bit 1 = 5V = kein Stromfluss = aus, was in Software vorauskorrigiert werden muss, aber wenn Transistorverstärker danach geschaltet sind, wird dies durch deren Umkehrung ohnehin nachkorrigiert und damit kompensiert. Generell ist man nur durch die Möglichkeiten der nachgeschalteten Analogtechnik und/oder Leistungselektronik und Mechanik limitiert, sowie durch die Anzahl Bits, und die Geschwindigkeit (und Präzision) mit denen diese vom Prozessor schaltbar sind. Letzteres umgehen ist der Hauptgrund für speziellere Ausgabe Schaltungen neben PIO, die wir hier alle ignorieren.

Parallele Eingabe ist auch analog. Dazu werden einfach statt Speicherzellen ihre Daten (also Spannungen) auswählen beliebige Signale ihre Spannungen ausgewählt, per hineingeführte Leitungen von der Aussenwelt genommen, auch üblich 0V/5V (Testgrenze darf im Bereich 0.8-2.4V liegen), und das als 0 oder 1 in den Prozessor kopiert. Dazu kann wiederum externe Analogtechnik ein beliebiges Signal, von einem beliebgen Sensor auf diese Spannungen aufbereiten. Ein normaler Satz von Tristate Gattern (z.B. 74244, 2 mal 1Adresse a 4bit) reicht dazu. Der einfachste Sensor, direkt ohne Analogtechnik, ist ein Umschalter der 0V/5V liefert, oder gar ein Winderstand nach 5V und ein simpler Schalter der zu 0V kurzschliesst, womit dann ein = zu = 0V = 0 ist, und folglich aus = offen = 5V = 1, was wiederum in Software nachkorrigiert werden muss. Man kann auch als Eingabe das Signal nehmen, das von einer obigen Parallel Ausgabe her kommt, damit das wieder einlesbar ist. Generell ist man wieder nur durch die Möglichkeiten der vorgeschalteten Analogtechnik und/oder Sensoren limitiert, sowie die Anzahl Bits welche diese produziert, und die Geschwindigkeit (und Präzision) mit denen diese vom Prozessor lesbar und verarbeitbar sind. Letzteres umgehen ist wiederum der Hauptgrund für speziellere Eingabe Schaltungen neben PIO, die wir hier auch alle ignorieren.

Diese speziellen präperierten Speicherstellen werden Ports genannt. Bei einem 8bit Prozessor können beim Speicher 8bit aufs Mal geschrieben oder gelesen werden, und folglich auch maximal 8bit auf einem Port ausgegeben oder von einem Port eingelesen werden. "Maximal" deshalb, weil man auch einen teilweisen Port machen kann, bei dem nur ein Teil der Bits gespeichert und ausgegeben werden (der Rest wird vergessen und damit fortgeworfen), oder nur ein Teil der Bits geliefert werden (der Rest bekommt Zufallswerte welche die Software dann ignorieren muss).

Da (Wieder-)Eingabe als Ergänzung bei Ausgabe erwünschenswert ist (und man dafür mehrere Chips bräuchte), und man oft teilweise Ports Ausgabe und Rest nur Eingabe haben will (und man dafür sonst separate Ports braucht), oder gar umschaltbare Ein- oder Ausgabe (und man damit Umschalteinrichtung braucht), und man oft mehrere Ports braucht (und dafür alles obigr mehrfach), gibt es Spezialchips mit mehreren konfigurierbaren Ports, mit fester Eingabe und ein-/ausschaltbarer Ausgabe. Dazu hat es neben einem Satz Flipflops für potenzielle Ausgabedaten auch einen zweiten Satz von Flipflops zum die Ausgabe freigeben bzw verhinden zum Eingabe sehen und damit die Richtung vorgeben, oft mit Bit 0 = Eingabe (weil nach Reset 0 und Eingabe keinen Schaden anrichten kann) und 1 = Ausgabe. Letztlich tut nur ein 1 (5V) ein weiteres Tristate Gatter zwischen dem Datenausgabe Flipflop und dem Anschlusspin aufmachen.

Diese beliebig nutzbaren Spezialchips werden wiederum PIO (Parallel Input Output) oder seltener PIA (Parallel Interface Adaptor) genannt. Jeder Prozessor Hersteller hat seit Mitte 1970ern welche im Angebot. Intel liefert den 8255 zum 8080 und den 8355 zum 8085, Zilog den Z80PIO zur Z80CPU (die DDR Variante ist der U855 zum U880), Motorola den 6820 zum 6800 (und 6809), MOS Technology die 6520 und 6522 und 6530 und 6532 zum 6502 (strikte war der 6530 ein 1kByteROM+64ByteSRAM+PIO Chip, der zusammen mit einem normalen 6502 wieder einen 2-Chip Controller ergab. Dem 6532 fehlte das ROM, dafür hat er 128ByteSRAM). Für 8086/8088 wurden normale 8080/8085 Teile benutzt, ebenso für 68000 normale 6800/6809 Teile.

Mikrocontroller haben nun stets neben Prozessor und Speicher auch PIOs im Chip eingebaut, da diese auch beliebig nutzbar sind. Beim AVR hat es sogar zuschaltbare Widerstände nach 5V, damit man simple Schalter nutzen kann ohne externe Widerstände. Die PIO Ports machen den grossen Teil der Mikrocontroller ihrer Pins aus. Neben Speichermenge ist die Anzahl PIO Pins das Unterscheidungskriterium der einzelnen Modelle in einer Familie. AVR gibt es mit 6 PIO Pins (mit 8 Pin Gehäuse) bis 86 PIO Pins (mit 100 Pin Gehäuse). Der ATmega32 den ich hier benutze hat 32 PIO Pins (mit 40 Pin Gehäuse), organisiert als 4 8bit Ports.

Auf der von mir verwendeten generischen Prototypenplatine sind diese 4 Ports je auf einer von Atmel im STK200 und STK500 standardisierten 10pin Pfostenleiste herausgeführt, an der man den spezifischen analogen Teil aufsteckt:

       Standard AVR PIO Port Stecker wie auf STK200 und STK500

                            1   2
                Port Bit 0   o o   Port Bit 1
                Port Bit 2   o o   Port Bit 3
                Port Bit 4   o o   Port Bit 5
                Port Bit 6   o o   Port Bit 7
                  GND / 0V   o o   +5V (oder +3.3V)
                            9   10
    

Ein Problem ist wo in den Speicherbereich man die Ports hinstellt. Es sind ja Pseuso-Speicherstellen, die auch Adressen brauchen. Man muss ohnehin den Adressbereich des Prozessors in ROM und RAM aufteilen, je nach den benötigten Mengen, und nun eben auch Ein-/Ausgabe daraus nehmen. Ports passen nun aber schlecht hinein, weil sie viel kleinere Mengen haben, ein paar wenige Adressen statt mehrere/einige k Adressen der Speicher. Der C64 tut seinem 6502 seine 64k in 16*4k aufteilen und davon dann 8+8k ROM und 4k Ports und 40+4k RAM verteilen (die 40k minus je 1k Status und Videospeicher gibt die berühmten 38k Basic Bytes Free), trotzdem dass von den 4k Ports nur 47 (VIC-II) + 29 (SID) + 2*16 (2 6526er) genutzt werden! Auch der Apple 1 hat 16*4k gemacht und sogar nur 4Bytes von 4k Ports (1 6820 Chip) genutzt. Der Apple 2 tut aufwendiger nur 128 Ports reservieren, aber davon auch nur 8 nutzen. Der Atari 800 tut sogar 6k Ports belegen. Bei 6502 und 6800 und 6809 hat man keine andere Wahl, also das so zu machen.

Manche Prozessoren offerieren dafür aber Spezialbefehle (Einlesen/IN und Ausgeben/OUT), zum eine geringe Menge an zusätzlichen unabhängigen Adressen anbieten, neben dem Speicher (Laden und Speichern), mit separaten sogenannten IO Adressen. Zumeist sind diese nur als kurze Adresskonstanten spezifizierbar). Der AVR hat 64 solcher IO Adressen. Seltsamerweise erscheinen diese Ports aber ebenfalls zusätzlich als Speicherstellen an den Adressen 32..95 (in den Adressen 0..31 erscheinen auch die Register nochmals). Die IN und OUT Spezialbefehle sind hier nur für schnellere kurze Adresskonstanten da (1Wort Befehle statt den 2Wort Befehlen mit 16bit Konstanten). Als Vergleich: Der 8008 offerierte 8 IN und 24 OUT Befehle (das sind 32 der fehlenden 40 Befehle, im letzten Vortrag in der Opcode Tabelle mit xxx markiert). Die 8080/8085/Z80/U880 haben sogar deren 256 mit je IN und OUT, nur 2 Befehle beide mit nachfolgender 8bit Konstante 1 Byte. Der 8048 hat ganze 7 mit IN und 7 OUT (14 Befehlen). Der 8051 hat wiederum 128 IN und OUT, mit 8bit(!) Adresskonstante nach dem Befehl, wobei 0..127 die ersten 128 Bytes SRAM adressieren, und 128..255 die 128 Ports, wesshalb SRAM 128..255 nur via Register adressierbar ist und nicht via Adresskonstanten.

Video, Fernsehen, Computer und VGA

Jetzt wo die Mikrocontroller Technologie und Ein-Ausgabe bekannt sind, wollen wir sehen was wir eigentlich damit anstellen wollen. Als Beispiel für eine Chip Emulation nehme ich hier meine SoftVGA Implementierung eines Videobildgenerators. Also zuerst mal eine Einführung in Video, und was daran eigentlich so schwierig ist.

Audio ist relativ einfach, es ist nur eine Schallwelle. Man braucht dazu nur ein Analogsignal, das über die Zeit hinweg variert, und so der Schallwelle folgt. Standard ist 0..1V für 0..100%. Einziges Problem ist dies genau zu machen (sonst wird es verzerrt), und schnell genug um auch hohen Tönen und Details zu folgen (sonst wird es dumpf). Für Sprache und Telephon reichen 4khz, für normale Musik 10kHz, für HiFi Musik 20kHz. Digital muss man für die Genauigkeit genug Bits pro Messung vorsehen (sonst leidet die Dynamik, leise Passagen verschwinden), und die doppelte Frequenz davon (als Shannon Limite bekannt) messen, um beide Hälften einer Schwingung zu erfassen (sonst sinkt die oberste Frequenz und es wird wieder dumpf), was zu 8kHz*8bit=64kbit/s bei Telephon und 44.1kHz*2*16bit=1411.2kbit/s bei CDs führte (MP3 mit 128 192 oder 256kbit/s sind also Kompression von 10.76 7.174 oder 5.3833).

Für Stereo muss man 2 Schallwellen L und R übertragen. Sehr oft wird, aus Kompatibilität mit Mono Geräten, eine L+R=Mono und L-R=Differenz Übertragung benutzt, z.B. bei UKW Radio. Beide Signale bei Stereo muss man so übertragen, dass man sie im Radio wieder trennen kann. Das ist mit Analogtechnik recht aufwendig (und das Verfahren digital zu simulieren noch viel schlimmer). Pur Digital ist Stereo ist schlicht die doppelte Bitrate und für je einen Bitsatz hin und her schalten. Eine CD ist grossteils schlicht eine in Polykarbonat eingestanzte Spiralrille mit 44100*2*16bit/s, plus noch etwas Verwaltungsbits zum es in Päckchen aufzuteilen und Kaputtbits (Stanzfehler oder Schäden) zu erkennen und korrigieren und Anfang identifizieren zum einzelne Stücke anspringen. Da die L-R=Differenz oft nahe 0 ist, weil L und R oft ähnlich sind, und damit sehr gut komprimiert, wird bei MP3 unter 128kbit ebenfalls das Mono+Differenz Verfahren benutzt.

Wenn man statt aufzeichnen und Wiedergabe nur Audio generieren will, reicht einiges weniger. Selbst 0.5-1.0kHz 1bit Mono ist für PC "Beep" generieren genug, es reicht ein Rechtecksignal, mit 2 mal pro Welle Ausgabe (abwechselnd 0 und 1). Die normale C-Dur Tonleiter hat als "unteres" C (C4 genannt) 261.63Hz und "oberes" C (C5) 523.25Hz (alles verdoppelt sich pro Oktave), und ist "festgenagelt" bei A (englisch) bzw H (deutsch) = 440Hz (strikte 439.96Hz). Etwas mehr muss es sein zum detailiertere Soundformen als nur Rechteck zu generieren, etwa 8 mal höchste Frequenz reicht für erkennbare Wellenformen. Aber das ist immer noch harmlos, beherrschbar ab etwas 1980 mit dem Pokey Chip im Atari 800, dem SID im C64, oder dem AY-3-8910 im MSX, die alle etwa 10-30kHz 8bit Mono machen. Aber auch halbwegs dazwischen geht es, z.B. mit nur einem 6bit PIO Ausgang, mit einem 6bit Digital-Analog Wandler dahinter (nur 6 Widerstände), und mit 15.75kHz Takt (der TV Zeilenfrequenz) per Software beschreiben, wie es z.B. im Dragon 32 verwendet wird.

Video ist weitaus schwieriger. Weil ein Bild neben der Helligkeit auch eine Fläche hat, über die hinweg die Helligkeit unregelmässig und scharf varieren kann, daraus entsteht erst das Bild. Dazu wird die Fläche wie bei einem Mosaik in genügend kleine Stücke fixer Helligkeit zerlegt, die Pixel. Für jedes einzelne davon muss nun die Helligkeit übertragen werden. Dazu wird das Bild Zeile für Zeile nacheinander, und in jeder Zeile Pixel für Pixel nacheinander, die Helligkeitswerte übertragen, was dann pro Bild eine Serie von "Helligkeitswellen" (eine pro Zeile) ergibt. Nach allen Zeilen wird wieder oben angefangen, das ganze genug oft, damit das Bild nicht ruckelt. Signal ist wieder 0..1V, aber davon 0.3..1V für 0..100% Schwarz..Weiss, und 0..0.3V "dunkler als schwarz" zum Zeilen und Bildenden anzeigen. Nach jeder Zeile wird noch 1/4 der Zeit gewartet, ebenso nach jedem Bild 1/8 der Zeit Leerzeilen gezeichnet, damit der Monitor Zeit hat zum an den Zeilen oder Bild Anfang zurückkehren.

Bilder und Auflösung braucht es:

Das sind 7.5 bzw 60 bzw 240 bzw 325 bzw 275 mal die HiFi Audio 20kHz. Man sollte ersteres eher als 37.5 mal die Telephon Audio 4kHz anschauen, weil ausser für Bildtelephon ist es wirklich unbrauchbar. Man sieht dass dies Datenmenge kostet, Fernsehen ist etwa 300 mal schwieriger als HiFi Audio! Und Frequenzreduktion gibt statt dumpfen Klang (ohne Höhen) eine "verschmierte" Darstellung (ohne Details), horizontal unscharfe Übergänge an Kanten, die weniger akzeptabel sind. Digital muss man wieder genug Genauigkeit haben für die Werte, es reichen dafür aber (3*)8bit, statt (2*)16bit.

Typische 2. Hälfte 1970er und 1. Hälfte 1980er Rechner haben Fernseher oder Videomonitore als Ausgabe benutzt, also TV Signale generieren müssen. Dabei wurde die damalige Speicher und Signalgenerator Chip Technologie bis an den Rand ausgenutzt. Nimmt man die PAL 64us/Zeile (bzw NTSC 63.5us/Zeile), was nach Abzug von 1/4 Zeit Rücklauf etwa 51us für das Bild gibt, und nach Abzug des Randes noch etwa 40us davon nutzbar, muss das Gezeichnete in diese 40us rein passen. Das erlaubt maximal 40 Zeichen a je 1us (bei 1MHz Speicher üblich), oder (etwas schmaler) 32 Zeichen a je 1.12us (beim recht beliebten 3.58MHz/4=0.895MHz Speicher üblich). Folglich liefen die Pixelerzeuger für die häufigen 8 Pixel/Zeichen mit genau der 8fachen Taktfrequenz des Speichers (8MHz oder 7.16MHz), was bei 8bit/Speicherzelle auch gerade noch für 1bit/Pixel und damit 2 Helligkeiten oder Farben reichte. Das ergab die damals üblichen 40x8=320 Pixel (Atari 800, C64) bzw 32x8=256 Pixel (TI-99, MSX, Dragon 32). Mehr Helligkeiten oder Farben gab es nur mit reduzierter Auflösung, halbierte 160 bzw 128 Pixel mit 2bit/Pixel für 4 Helligkeiten oder Farben, und geviertelte 80 bzw 64 Pixel mit 4bit/Pixel für 16 Helligkeiten oder Farben (was letzteres selten machte, im Atari 800 und Dragon 32 drin, aber nicht in C64 oder TI-99 oder MSX).

Damit, und mit den TV Halbbild Zeilen, war auch der maximale übliche Bitmap/Pixelmap Modus Videospeicher von 320/8(=40)*200=8000=fast8kByte (Atari 800, C64) bzw 256/8(=32)*192=6144=genau6kByte (TI-99, MSX, Dragon) festgelegt. Dieser wurde zumeist in einem Teil des damals üblichen 64k Adressraum gelegt, ebenfalls zumeist physikalisch in den Hauptspeicher RAM Chips gespeichert, kein separates Videokarten RAM wie oft beim PC (nur TI-99 und MSX hatten separate Video RAM Chips (16k), und eigenen Adressraum dafür, und die hatten beide den gleichen TMS9918 Videochip der beides machte).

Damit erscheint jedes Pixel in einer Speicheradresse, und darin als einen Ausschnitt an 1 2 oder 4 Bits (gehörend zu 8 4 oder 2 Pixeln in der Adresse). Für die Pixel im Byte gab es zwei Anordnungen:

Für Text zeichnen wurden üblicherweise Fonts mit 8 Pixel/Zeichen (im 1bit/Pixel Modus ist das genau 1 Byte) und 8 Zeilen/Zeichen benutzt. Das ergab dann 320/8(=40) x 200/8(=25) = 1000Zeichen (Atari 800, C64) bzw 256/8(=32) x 192/8(=24) = 768Zeichen (TI-99, MSX). Aber es gab bei letzterer Auflösung auch ein Verfahren mit 12 Zeilen/Zeichen Font, mit nur noch 256/8(=32) x 192/12(=16) = 512Zeichen (TRS-80, Dragon 32). Letzteres war sehr wenig und unübersichtlich. Da man bei Text zeichnen immer alle 8 Bits einer Speicherstelle setzt, kann man einfach ein Block Pixelmuster Bytes aus dem Font kopieren (ein Muster pro Zeichen). Es gab aber auch eine seltenere 6 Pixel/Zeichen Darstellung, zum trotz eines nur 256 breiten Bildschirmes doch 40 Zeichen haben, in 40*6=240 Pixeln drin. Das artete dann in einer grösseren Bitschieberei aus, von den Font Byte zu Video Byte Bit Positionen.

Die Speicheradressen eines Pixels selber berechnete sich aus dem Bildanfang (eine Konstante) und der Y Koordiante und der X Koordinate. Hierfür X geteilt durch 8 4 oder 2, was trotz variabler X Pixelzahl, durch die reziproke variable Anzahl Bits/Pixel, dann zu einem einen konstanten Bereich von 0..39 bzw 0..31 führte, während Y immer konstant 0..199 bzw 0..191 war. Es gibt für die Umrechnung 3 Anordnungen und Formeln:

Beim Text Modus wird ausgenutzt, dass für Textanzeige eigentlich nur eine von wenigen festen 8x8 (oder gar 8x12) Pixelmusterm pro Zeichenplatz benötigt wird. Es wurden daher nicht mehr alle die eigentlichen Pixel im kleineren Speicher (kein Platz mehr!) gespeichert, sondern nur noch 6-8bit/Zeichen an Indizes zu einem separaten Fontspeicher. Dies benötigt folglich nur noch 1/8 (oder gar 1/12) soviel Bildspeicher, also 1000=fast1k bzw 0.75k (oder gar 0.5k). Neben Speicher sparen erlaubt dies auch schneller scrollen weil dazu weniger Daten umzukopiert werden müssen.

Adressen sind hier stets Bereich Anfang .. Anfang+(1000bzw768bzw512)-1, in linearer Anordnung, Anfang + Y * (40bzw32) + X, für Y = 0..25bzw24bzw16 und X = 0..39bzw31.

Es war ziemlich verbreitet, dass Index 0 im Font ein Leerzeichen beinhaltet, damit wie beim Bitmap Modus der Bildschirm löschen daraus besteht, überall 0 hineinzuschreiben. Index 1..63oder127oder255 haben nur eine Bedeutung wenn man den Fontspeicher Pixelmuster Inhalt kennt, der bei jedem Hersteller anderst war. Mit 6bit Index und 64 Zeichen war ASCII 32..95 der Standard. Mit 7oder8bit Index und 128oder256 Zeichen waren beliebige Erweiterungen möglich, wenn auch ASCII 96..126 naheliegend war, aber oft nicht der Fall!

Der zusätzlich nötige Fontspeicher (dafür sind aber keine Fontdaten im Programmspeicher mehr nötig) besitzt dann pro Zeichen die 8 Bytes (oder gar 12 Bytes) an Pixeln, aber das nur für 64-256 Zeichen, je ein mal. Ein minimaler 64Zeichen*8Bytes Font braucht 512=0.5kBytes, ein voller 256Zeichen*8Bytes Font 2048=2kBytes. Zusammen mit den 0.5k-1k Indizes ist das immer noch weniger als die 6k-8k an Bitmap Pixeln. Eine spezielle Hardware Variante in den 1970ern war noch max 7bit/Zeichen Index (und damit max 128 Zeichen Font und halbierte ROM Grösse) und das achte Bit als ein "alle Pixel invertieren" Signal genutzt (Commodure PET, Dragon 32), was wiederum oft bei 8bit Index im Standardfont simuliert wurde (VC-20 oder C64, Atari 800).

Der Fontspeicher kann ein ROM im Videochip drinnen sein (Dragon 32 64*12Byte im 6847 Chip), ein separates ROM in multi-Chip Hardware (TRS-80 64*12Byte, PC CGA 256*8Byte), ein Teil des Programm ROMs (ZX-81 64*8Byte), schaltbar ROM oder RAM (VC-20 und C64 2Fonts * 256*8Byte = 4k ROM oder 2k RAM, PC EGA 256*14Byte und VGA 256*16Byte ROM oder 4k RAM), nur RAM und vom BIOS ROM her gefüllt zum Umschalter sparen (glaubs bei VT220 und VT320), oder total abwesend für nur Bitmap Modus (ZX Spectrum, KC 85/2 und KC 85/4, glaubs auch VT330+VT340).

RAM als Fontspeicher erlaubt Softfonts, und damit eigene graphische Objekte laden und pixelgenaue Animation zur Laufezeit generieren, ohne einen vollen Bitmap Videomodus. Extremfalls kann man bis zur Hälfte der Zeichen je 1 mal als "Kacheln" missbrauchen, zum ein Teilbild Bitmap simulieren. Das gibt Textschnelles Scrollen und Bitmapflexibles Zeichnen in einem. Die meisten guten Games haben dies ausgenutzt. Softfonts war das zentrale Feature aller guten Homecomputer. Deren fehlen typisch für primitive 1970er Rechner.

Aber auch ohne Bitmap Modus (nur Text Modus) und ohne Font RAM und Softfonts kann man etwas Graphik machen, zumindest mit niederer Auflösung. Dazu kann man jede Zeichenposition in 2x2 oder 2x3 Blöecke unterteilen, und diese als grosse Blockpixel anschauen. Das läuft auf eine 2*2=4bit/Position (Atari 800, C64, Dragon) oder 3*2=6bit/Position (TRS-80) Blockmap hinaus. Dazu muss das Font ROM dann aber 2^4=16 oder 2^6=64 Blockgraphik Zeichen beinhalten, letztlich einfach alle möglichen Blockkombinationen. Bei invertierendem Fontindex Bit 8 reichen die Hälfte, da der Rest durch invertieren erzeugt kann. Das SoftVGA Logo besteht aus einer derartigen 2x2 Blockgraphik.

Fakultativ konnte man zusätzlich zu obigem Bildspeicher einen weiteren Attributspeicher haben zum "Einfärbebits" (und/oder blinken oder Formänderung) liefern, zum einen Teil der Farben aus mehreren Auswählen. VC20 und C64 haben neben 8bit Speicher weitere 4bit pro Zeichen (8x8 Pixel) zum 1 Farbe (Vordergrund) aus 16 wählen, auch im Bitmap Modus gilt dies nur pro ganue Zeichenposition! TI-99 oder MSX oder Spectrum oder PC CGA/EGA/VGA (nur im Text Modus) oder KC 85 haben neben 8bit Speicher 4+4bit zum 2 Farben aus 16 wählen), auch da Spectrum und PC nur pro Zeichenposition, KC 85/2 pro 8x4 halbhohes Zeichen, TI-99 und MSX und KC 85/4 wenigstens pro 8x1 Pixel Streifen. Beides gab Ärger mit mehrfarbigen Vektorgraphiken, sogenannte Attributkollision. Oder man konnte sogar 2 separate Videospeicher auslesen (KC 85/4 2 mal 8bit Speicher für 2bit/Pixel 4 Farben bei Vollauflösung). Das von den Millionen Farben (oder 100en Helligkeiten) die der Fernseher eigentlich darstellen könnte.

Für Farben werden, analog zu bei Stereo, mehrere Helligkeiten übertragen, die 3 Grundfarben Rot und Grün und Blau. Diese werden auch sehr oft, aus Kompatibilität zu Schwarzweiss Geräten, als R+G+B=Helligkeit und G-R=Differenz1 und G-B=Differenz2 übertragen. Daneben erlaubt dies auch, die beiden Differenzen mit geringerer Auflösung und Datenmenge zu übertragen, da wir Farbschattierungen weitaus weniger aufgelöster sehen als Helligkeit, wegen der Sehzellen Verteilung. Fernsehen macht das bereits in analog, PAL horizontal Faktor 6.5/1.3=4, NTSC horizontal 5.5/1=5, SECAM horizontal wie PAL und vertikal 2. Wir haben damit aber 3 statt 2 Signale, und Schwarzweiss ist weniger akzeptabel als Mono. Die drei Helligkeiten so zu übertragen dass sie wieder trennbar sind, ist mit Analogtechnitk sehr aufwendig (und digital simulieren extrem schwierig). NTSC schickt immer alle 3 Signale und ist durch das verfahren anfällig auf Farbverfälschung durch Signalstörungen, PAL korrigiert das mit mehr Verpackungsaufwand, SECAM korrigiert das mit nur einer der Differenzen pro Zeile abwechselnd übertragen (und das andere von der letzten Zeile aus einem Speicher nehmen) für weniger Aufwand und robust, aber total inkompatibel. Pur Digital tut man einfach wieder mehr Bits vorsehen und abwechslungsweise schicken, Differenzen seltener als Helligkeiten.

Weil Fernseher oder Videomonitore benutzt wurden, mussten damalige Rechner entweder Schwarzweiss benutzen (z.B. Apple 1, ZX80 und ZX81), was aber nur geringen Ansprüchen genügt, oder für Farben die ganze NTSC oder PAL Analog Verpackerei simuliert werden, was aufwendig war. Letzteres geschah mit speziellen analogen Schaltungen. Entweder mit vielen Analog Bauteilen (wie in einer Videokamera), oder missbrauchter TTL Logik (Apple 2) oder in hochintegrierten (Teil-)Analog Chips (Atari 2600 und alle guten Homecomputer).

Da im AVR nix derartiges drin ist (und überhaupt nix für Video erzeugen, oder überhaupt für Analog erzeugen), und ich hier keine externen aufwendigen Hilfsschaltungen (analog oder digital) haben will, anderseits aber Farben haben will, und auch die hohe Rechenleistung des AVR für Analog Verpacken in Software simulieren nicht reicht (im Gegensatz zum Ubicom), scheiden Fernseher oder Video Monitore aus als Anzeige. Aber es gibt ja auch andere Monitore, von der PC Welt.

Auch der IBM PC hatte anfangs das selbige wie Homecomputer, mit der CGA (Color Graphics Adaptor) Karte. Das allerdings mit doppelter horizontaler Auflösung, weil doppelter Speichertakt, 1/2us statt 1us. Das war möglich mit separatem RAM auf der Videokarte, das nicht mit dem Prozessor geteilt war (was ihn ausbremsen würde). Das erlaubte im Bitmap Modus 640x200 Pixel mit 1bit/Pixel und 2 Farben bzw 320x200 Pixel mit 2bit/Pixel und 4 Farben (letzteres identisch mit dem KC 85/4 seinen 2 Videospeichern). Der Text Modus war auch doppelt breit mit 80x25 Zeichen (reduzierbar auf 40x25), mit je 2 Bytes/Zeichen (8bit Index gefolgt von 2*(1+3)=8bit Attribut), in 4k von 16k des gemeinsamen Speichers, der Adressen 0xB8000 .. 0xBBFFF hat. Dieser wurde für den Bitmap Modus komplett übernommen, alle 16k, für 200 Zeilen zu je 80 Bytes = 16000Bytes. Daher hatte es im Bitmapmodus keine Attribute mehr, und damit nur fixe 2 oder 4 Farben! Addiert man dazu den nur-ROM Fontspeicher (nix Softfonts) wie in einem primitiven 1970er Rechner, und dort drin nur 1x2 Blockgraphik Zeichen (was nur für miese 80x50 reicht), und Games mussten daher Bitmap benutzen. Das war aber mühsam dank nicht linearem Y (wegem 6845 Chip seinen max 128), langsam bei 16k Bildspeicher scrollen, und gab ohne Attribute maximal 4 Farben (bei 320x200), und dazu noch 3 feste Auswahlen von hässlichen Schwarz/Cyan/Magenta/Weiss oder weiss-losen Schwarz/Grün/Rot/Gelb oder gemischtes Cyan/Rot/Weiss (strikte war Schwarz beliebig ersetzbar, aber wer will schon das verlieren?). Sprites zum etwas aufbessern hatte es auch keine. Die CGA war alles andere als beeindruckend, selbst im Vergleich zu 1/3 so teuren Homecomputern.

Weil die NTSC oder PAL Signale für die 640 Pixel oder 80 Zeichen zu langsam waren, gab es mit Videomonitor nur die auf 320 Pixel oder 40 Zeichen halbierte Auflösung. Für volle 640 Pixel oder 80 Zeichen brauchte es einen CGA Spezialmonitor. Der hatte eine nicht kombinierte digitale RGB Übermittlung. Genauer hatte dieser 4 Drähte, mit je nur digital 0V/5V binär, die ersten 3 für RGB genau 8 die Primärfarben wählen, den vierten für 2 Helligkeitsstufen davon (Intensität). Das nannte man dann RGBI Verfahren, was 2*8=16 Farben (strikte 2*7+1=15, 0 und 8 sind beide Schwarz) gab. Dazu kamen noch 2 weitere digitale 0V/5V Drähte HV zum Zeilen- und Bildwiederholung synchronisieren. Die 2*(1+3) Attributbits sind nichts anderes als I+RGB für Hintergrund (Bit7+6..3) und Vordergrund (Bit 3+2..0). Bit 7 kann zudem für den ganzen Bildschirm zum Blinkbit umgeschaltet werden, was dann aber nur noch 8 Hintergrund Farben erlaubt, die 8 ohne Intensität. Der CGA Monitor wäre mit rein 4+2=6bit digital und 14.318MPixel/s ein gutes Teil für AVR Video, und es wären erst noch frühe 1980er Originalmonitore, wenn die heute bloss noch verbreitet wären!

Alternativ zu CGA gab es aber auch die MDA (Mono Display Adaptor) Karte und Monitor. Diese konnten nur Schwarzweiss und nur Text Modus (ebenfalls mit nur ROM Fontspeicher, ohne Softfonts, und mit nur 1x2 Blockgraphik Zeichen). Dafür konnten sie einiges höherere Font Auflösung von 9x14, und liefen immer mit dem MDA Spezialmonitor (ohne das wären diese reinstes 1975). Dies reichte für 720x350 Pixel und 80x25 Zeichen (kein 40x25 sinnvoll oder möglich), wieder in 4k Videospeicher, diesmal an den Adressen 0xB0000 .. 0xB0FFF (und daher konnten sie neben CGA ko-existieren für Dual-Head). Attribute sind wieder 2*(1+3), mit nur Farben 0,7,15 gültig und Vordergrund "Farben" 1,9 geben 7,15 aber unterstrichen. Ebenso kann Bit 7 zum Blinkbit umgeschaltet werden, wieder auf Kosten von Hintergrund 15. Man konnte mit dem selbigen Monitor auch 720x348 (nicht 350!) Bitmap machen, mit der Signal- und Frequenz kompatiblem HGA/MGA (Herkules Graphics Adaptor / Mono Graphics Adaptor) Karte, mit 32oder64k Videospeicher, der Adressen 0xB0000 .. 0xB7FFFoder0xBFFFF hatte (letzteres nicht mehr mit CGA Dual-Head fähig). MDA und HGA/MGA sind heute nur noch relevant als Auflösungs und Font Vorläufer der EGA.

Diese Auflösung von 720x350 und Font von 9x14 wurde auch in den Text Modus der EGA (Enhanced Graphics Adaptor) Karte und Monitor übernommen, die das aber alles auch noch farbig und mit vollfarbiger Bitmap Graphik konnten. Der Text Modus hatte identischen Speicherinhalt wie die CGA, nur mit MDA Auflösung+Font. Der Bitmap Modus konnte immerhin 640x350 mit 4bit/Pixel und damit volle 16 Farben/Pixel ohne reduzierte Auflösung. Das brauchte dann auch 4 64k grosse Videospeicher (und nur 4 mal 28000Byte davon genutzt!), normal an Adressen 0xA0000 .. 0xAFFFF (und damit mit MDA Dual-Head fähig, aber nicht mit CGA!). Für CGA oder MDA Emulation war einer von diesen zu 0xB0000 oder 0xB8000 verschiebbar. Und einer weiterer davor wurde auch noch als 4k Softfont benutzt. Dazu hatte EGA noch 6 Drähte RRGGBB (und 2 Drähte HV), zum für jede der 3 Grundfarben unabhängig 4 Helligkeiten zeigen zu können (und somit 4*4*4=64 Farbtöne darstellen), mit einer Tabelle zum jeden der 16 Farben beliebige einer dieser 64 Farbtöne zuzuordnen. Dank 16-farb 640x350 Bitmap und 80x25 Zeichen Textmode mit 9x14 Softfonts, war EGA auch ganz anständig brauchbar, auch ohne Sprites. Von den Farben und Auflösung her der erste halbwegs moderne PC Monitor, aber heute auch nur noch relevant als Vorläufer der VGA. Mit rein 6+2=8bit digital, und mit 16.257MPixel/s nur 13.54% schneller als CGA, wäre dieser noch besser für AVR Video geeignet, aber heute auch selten zu finden. Damalige frühe Multisync Monitore konnten umschaltbar CGA oder EGA Signale, mit Frequenz von CGA bis über EGA hinaus (reichte bis inoffizielle 800x600 S-EGA aus 4 mal 60000Bytes). Diese Monitore wären absolut ideal für AVR, aber heute auch selten.

Später wurde das für die VGA (Video Graphics Array, das A nicht Adaptor sondern benamst nach dem erstmaligen verwenden eines Gate Array Chips) Karte und Monitor sogar leicht ausgebaut. Das ergab Text Modus mit 720x400 für 80x25 Zeichen in 9x16 mit Softfont, wieder Speicher CGA oder MDA kompatibel möglich. Der Bitmap Modus konnte nun 640x480 Pixel, erweitertes EGA kompatibel (4 mal 38400Byte genutzt). Dazu kam noch ein 320x200 Pixel Bitmap Modus mit 1Byte/Pixel für 256 Farben (nur 1 mal 64000Byte genutzt). Und all das erst noch in 16 oder 256 Farben von 64*64*64=262144 Farbtönen. Damit blieb VGA lange der PC Graphik Standard, bis SVGA nur mehr Bitmap Pixel brachte (16 Farben mit 800x600, 4 mal 60000Byte, sowie 256 Farben mit 640x400, 4 mal 64000Byte, womit endlich der ganze 256kByte EGA Speicher ausgenutzt wurde, 2 Generationen später!).

VGA verwendet für seine vielen Farben 3-Draht RGB Übertragung mit analog Signalen, wie beim Fernsehen, und kann damit beliebig viele Farben verlangen, heute üblich 256*256*256=16Mio. Dies aber leicht abweichend mit nur 0..0.7V, ohne die 0.3V "unter Schwarz" für Zeilen/Bildwechsel. Für diese sind weiterhin die 2 digitalen HV da, wie bereits bei den nur-digitalen CGA und MDA/HGA/MGA und EGA Karten und Monitoren. Diese Signale und Stecker bleiben bis zum wieder rein digitalen DVI unverändert. Die 3 analog Signale aus digital des AVR generieren ist harmlos, genau die Schaltung die im EGA Monitor drin war, ganze 6 Widerstände werden benötigt.

VGA hat als Folge der Auflösung genau die halbe Zeit pro Zeile als NTSC Fernsehen (70Hz 400 Nutzzeilen oder 60Hz 480 Nutzzeilen statt 60Hz 240 Nutzzeilen bzw 30Hz 480 Nutzzeilen). Lediglich die Pixelfrequenz ist nur auf 8/5 statt 8/4, weil nicht in den Rand hinaus gezeichnet wird. Das ergibt 25.4us nutzbares Bild bei VGA statt 40us bei NTSC (oder PAL). 640 Pixel (und 80 Zeichen a je 8 Pixel) brauchen dann 25.18MPixel/s bzw 720 Pixel (und 80 Zeichen a je 9 Pixel) sogar 28.32MPixel/s. Und Multisync Monitore mit VGA Signalen funktionieren erst ab VGA Frequenzen, keine EGA oder gar CGA. Ziemlich saftig das. Ich hab mich entschieden für 1/4 vom VGA 640 Pixel/Zeile Bitmap, mit 25.18/4=6.29MHz, was mit 160 Pixel/Zeile für 40 Zeichen zu je 4 Pixel reicht, und auf dem AVR gerade noch machbar ist.

Später (lange nach dem Entscheid für VGA) hab ich beim ChipBasic gesehen, dass auch Fernseher mit SCART Anschluss zum Teil RGB können, mit nur Fernseh Auflösung, also Zeiten wie bei CGA, aber mit analog Signalen und allen Farben wie bei VGA. Das wäre ideal gewesen. Nur habe ich kein solches Teil (und diese Eigenschaft deswegen nicht gekannt), und die "VGA geht doch" Rechnung war da schon gemacht, und ein Monitor dafür ist vorhanden.

SoftVGA

Zum auf einem VGA Monitor ein Bild erzeugen, müssen wir die VGA Signale generieren. Dazu brauchen wir ein passendes spezifisches PIO digital zu VGA analog Schaltungsteil, zum auf die Prototypenplatine aufstecken. Das sind einerseits 3 mal analoge 0..0.7V (R+G+B) und anderseits 2 mal digitale 0V/5V (H+V) Signale zum generieren, sowie ein HD-15 Stecker danach. Letztere 2 erzeugen ist einfach, es reichen je 1 PIO Ausgabe Pin ohne etwas dazwischen direkt durchgeschlauft, es sind ja TTL Logik Signale die der Monitor braucht (strikte ist der analog Teil schon im Monitor drin), und langsame dazu. Für erstere 3 braucht es je 1..n PIO Ausgabe Pins (1..n je nach wieviele Farbabstufungen man will) mit je einem nbit Digital-Analog Wandler dahinter.

Zum so schnell wie möglich Pixel zeichnen können, und alle Grundfarben synchron schalten, können wir nur 1 Ausgabebefehl pro Pixel haben, also maximal 1 Port von 8bit PIO Ausgabebits aufs mal. Also ist eine 2R+2G+2B+1H+1V=8bit Anordnung sinnvoll, und erlaubt damit 2bit/Grundfarbe (4 Helligkeitsstufen). Damit liegen wie bei EGA 4*4*4=64 Farben drin, was für einen 1980er-artigen Homecomputer völlig ausreicht (die konnten so 4..256). Dafür braucht es pro Signal einen 2bit Digital-Analog Wandler. Diese bestehen aus je 2 Widerständen sowie dem 75ohm Eingangswiderstand des Monitors.

Im nachhinein habe ich auch entdeckt, dass alle 8bit für Farben ausnutzen möglich ist, indem 1H+1V von einem separaten PIO kommen (die müssen ja nicht pixel-synchron sein!) und 3R+3G+3B von den 8 PIO bits (mit dem LSB/Bit0 von G+B identisch). Das erlaubt volle 256 Farben, und braucht pro Signal einen 3bit Digital-Analog Wandler (je 3 Widerstände und die 75ohm).

Also müssen wir pro Pixel einen Ausgabebefehl/OUT ausführen, was auf einem AVR 1 Taktzyklus kostet. Wir können aber nicht zur Laufzeit Code für alle Pixel generieren, da das Flash ja nicht einfach so beschreibbar ist für jede Bildänderung. Also müssen die Videodaten im SRAM abgelegt werden. Anderseits kann SRAM kein Programmcode beinhalten. Also müssen wir im Flash eine Reihe Programschnipseln für generische "Pixelfolgen" unterbringen, und die von SRAM Daten gesteuert ausführen. Zwischen den Pixeln einer Folge zeichnen müssen wir also die nächste Folge ihren Schnipsel ermitteln, und diesen anspringen. Dazu wird auf einem AVR zumindest ein PC = R30:R31 Befehl ablaufen müssen, welcher 2 Taktzyklen braucht. Also muss ein Pixel minimal 1+2=3 Taktzyklen lang sein, also max Takt/3 Pixelfrequenz. Andere Controller können hier nur noch (weit) schlechter abschneiden.

Offensichtlich nimmt man für ein Textdisplay als "Pixelfolgenlänge" die Breite eines Zeichens, also mindestens 4 Pixel (weniger geht fontmässig nicht). Ein 40 Zeichen/Zeile Bild in 25.4us zeichnen ergibt damit 0.635us/Zeichen, was bei 4 Pixel breiten Zeichen in 0.158us/Pixel resutiert, was eben die 6.29MPixel/s ergibt. Das ist das Minimum das man erreichen muss. Wenn man nun den AVR so programmiert, dass man alle 3 Takte ein Pixel ausgibt, reichen dann 3*6.29=18.87MHz. Das ist unter den 20MHz der neuen AVRs und 18% übertaktet bei den alten 16MHz, was diese problemlos aushalten, da die 16MHz selbst bei 4.5V (langsamste Elektronen) und 85grad (ungenaueste Elektronen) garantiert werden. Ein min 5V Netzteil erlaubt 27% übertakten, ein min 5.25V Netzteil sogar 41%, max 30grad Raumtemperatur erlauben nochmals dazu 18% übertakten, das alles ohne fragwürdiges Chiptoleranzen ausnutzen wie beim PC übertakten üblich (die sind eh auf 0.1V genau festgelegt und dabei gerade noch erträglich heiss).

Also muss es lediglich möglich sein, dem nächste Zeichen seine Pixelfolge in dem 4*2 Taktzyklen Pausen zwischen den 4 Pixeln zu ermitteln und aufrufen. Nachdem ich nach dem VCFe 2008 genau den Code dafür zusammengestellt hatte, war es klar, dass das Projekt realistisch machbar ist. Hiermit war der ganze "Erfinder" Teil der Entwicklung erledigt.

Der Rest war "nur" noch eine "kleine" Sache der Hardwarelöterei und Programmiererei. Genauer ein Program schreiben, welches 40 mal die passende obige 4*(1+2)=12 Taktzyklus Zeichenroutine aufruft (gibt 40*12=480 Zyklen), dann etwas wartet (1/4*480=120 Zyklen) und darin den Zeilenwechsel auslöst, das Ganze dann für 400 Zeilen wiederholen, gefolgt von 50 Leerzeilen und während denen den Bildwechsel auslösen. Dieses hat meine ganze für Hobby vorige Zeit von letztem Herbst bis heute aufgebraucht. Das waren gemäss Logfile zwischen 2008.09.13 und 2009.03.04 etwa 23 volle und 13 halbe Tage reiner Programmierzeit, also etwa 1.5 Mannmonate. Designen und Planen ist da nicht eingerechnet, da diese zumeist vorzu geschahen, oder "irgendwann" und "irgendwo", oft im Zug unterwegs oder während dem Sport Training, und z.T. vor Jahren (den Namen SoftVGA hab ich erstmals Mitte 2005 notiert). Ebenso sind da AVR Doku einarbeiten (auch z.T. vor Jahren, jetzt nur auffrischen und erweitern) und Website bauen nicht eingerechnet. Insgesammt war das wohl eher ein 2.5-3 Mannmonat Projekt.

Die Details vom Programmiercode, und den Techniken dies alles zeitgenau hinzubekommen, passen nicht an einen Einführungsvortrag. Sie werden morgen am Workshop durchgearbeitet werden. Hier nur ein paar Höhepunkte zusammengefasst.

Es reichen 6+2=8 (bzw 8+2=10) PIO Pins für die Videoausgabe, sowie ein paar wenige PIOs zum mit dem Hauptprozessor kommunizieren. Also würde ein 28pin AVR mit 20 freien PIOs ausreichen, oder sogar ein 20pin mit 15 freien PIOs. In der Grösse waren aber vor dem neuen 28pin ATmega328 nur Chips mit unzureichenden 1k oder noch weniger SRAM vorhanden. Die 40x25 Zeichen für Atari 800 oder C64 Darstellung sind bereits 1000Bytes, plus noch Verwaltungsdaten dazu, damit werden 1k überschritten. Also habe ich einen 40pin ATmega32 genommen, für seine 2k SRAM. Für eine 32x24 Anzeige würden 1k SRAM locker ausreichen, ebenso bereits die 8k Flash eines ATmega8, das wäre dann die 28pin Minimalausgabe. Die 20pin haben max 1/2k SRAM und scheiden definitiv aus.

Wegen (Font-)Speicherplatzmangel werden von den 400/25=16 Zeilen pro Zeichen nur 8 definiert. Die anderen 8 sind entweder leer (ergibt die historische "streifige" Homecomputer und CGA Bild Darstellung) oder Wiederholung des Vorgängers (ergibt die CGA auf VGA Karte "Doublescan" Emulationsmodus Darstellung). Diese können zur Laufzeit per Schalter ausgewählt werden.

Der Font wird mit einem normalen ASCII Texteditor "gezeichnet", als 8 Textzeilen pro Zeichen, mit je 4 Pixel darin (gezeichnet als 4 mal 4 ASCII Zeichen, damit es die passende quadratische Form hat), und in einem speziell formatierten File abgelegt. Dieses wird dann von einem kleinen Script automatisch in AVR Code umgewandelt, v.a. in .db Befehle, die Daten im Code ablegen. Dieses so generierte Sourcefile wird dann im restlichen Code mit .include eingefügt.

Im Laufe der Zeit hat es 3 Zeichenmethodiken gegeben, nach und nach Verbesserungen einbringend, bzw andere Kompromisse:

Mit dem veränderbaren RAM Font kann SoftVGA heute auch weitaus mehr als ich am Anfang des Projektes je zu träumen gewagt hätte!

Strikte haben wir hardwaremässig 480 Takte/Zeile und nicht 160 Pixel/Zeile, es wird einfach nur jeder dritte Takt für einen Pixel genutzt, und für die beiden nächsten gleich gelassen. Theoretisch könnte man da etwas machen, mit differenzierteren Zeichenroutinen, statt 16 mit genauem 3 Takt Timing. Hans wollte damit expermentieren zum schönere Fonts machen, aber ich hab da bisher keine ernsthaft bessere Möglichkeiten ausmachen können.

Neben dem Bild ausgeben muss der AVR auch den Bildinhalt zuerst mal in den Bildspeicher schreiben. Direkt von aussen auf den Speicher zugreifen kann man ja nicht, weil der im Chip drinnen ist. Anfangs wurde dieser zuerst beschrieben und dann erst ausgegeben, was nur ein statisches Bild ergab. Zum während der Darstellung etwas verändern/hineinzeichnen muss der AVR dauernd zwischen Ausgabe und modifizieren wechseln, und das zumindest ein mal pro Bildausgabe. Das läuft auf Multithreading hinaus, wozu der extrem zeitkritische und damit hochpriorisierte Zeichenthread ab und zu Pausen einlegen muss, zum dem Bildbearbeitungsthread eine Chance geben. Während den möglichen 200 Leerzeilen im Bild, und den sicheren 50 beim Bildwechsel hat der AVR je Zeile 480 von den 600 Takte/Zeile Zeit, wo die Ausgabe sich nicht ändert. Davon können etwa 400 nutzbar gemacht werden, zum etwas in den Bildspeicher hineinzuschreiben. Es wird dazu die Ausgabe abgebrochen und ein Timer verwendet, zum zeitgenau mit dem Weiterzeichnen anzufangen. Diesen genug schnell hinzubekommen hätte theoretisch auch das Projekt beerdigen können, aber die Chance dass das passiert war gering. Und die erwarteten Reserven dafür waren verfügbar. Die Umstellung war genügend einfach dass sie in 1.5 Tagen Programmieren lief.

Was dem SoftVGA momentan noch fehlt ist jeglicher externer Anschluss für Daten. Im Videospeicher und Font steht und passiert nur das, was auf dem AVR laufende Demos von sich aus zeichnen, also was zur Assemblierzeit im SoftVGA Code eingebaut war. Es ist aber rein Sache einer (recht geringen Menge) Programmierung, anstelle von Demos dort einen Terminalemulator laufen zu lassen. Also genau das wofür der 8008 entwickelt wurde, und wozu der AVR Faktor 100-300 überdimensioniert ist, also auch nach Abzug der Zeichenzeit ausreichend schnell sein wird.

Als Schnittstelle wäre dazu am besten die auf dem AVR vorhandene USART Ein-/Ausgabe Schaltung zu benutzen (eine der gegenüber PIO erweiterten die ich hier nicht näher beschreibe), zum RS232 (eventuell nur 3-Draht 5V RS232) implementieren. Oder da wir ohnehin vorige Pins haben, schlicht eine PIO Schnittstelle machen.

Benutzen ist so einfach wie ein Fernschreiber oder Terminal, es reicht der gewöhnliche PRINT Befehl eines Basicrechners, eventuell mit etwas CHR$() drin zum Farben oder andere spezielle Sachen steuern.

Wegen der präzisen Zeitanforderungen der Zeichnerei ist diese nicht unterbrechbar. Also muss dieser Emulator ohne Interrupts arbeiten, also die USART oder PIO pollen, was wiederum nur während Leerzeilen möglich ist. Diese sind nur nach jedem Bild garantiert, also muss man mit 400/450=8/9 bzw 480/525=8/9 Bild langen Aufnahmepauses rechnen, und kann folglich Zeichen nicht schneller als max eines pro Bild schicken. Dies ist auch die Geschwindigkeit eines Apple 1 (der nur ein Zeichen pro Bild in seinen seriellen Videospeicher einschreiben konnte).

Obige Geschwindigkeitslimite kann man umgehen indem man ein Handshaking Verfahren verwendet (explizite Rückmeldung nachdem ein Zeichen "verdaut" ist, und nächstes geschickt werden kann) statt einfach warten. Damit könnte man mehrere Zeichen nach jedem Bild ausgeben, schneller wenn auch stossweise. Und sogar Leerzeilen im Bild ausnutzen, Halbschnell statt Stillstand. Handshake ist bei PIO Chips als Standard dabei und ist bei USART per RTC/CTS Missbrauch addierbar.

Man könnte auch das unregelmässige Verhalten ohne Handschaking ausgleichen/verstecken, mit einem externen FIFO Speicher (First-In First-Out, quasi in Schlange anstehen), z.B. mit einen zweiten kleinen AVR. An dessen Eingang ist halbschnelles RS232 mit konstantem Zeichenfluss, am Ausgang schnelles RS232 oder PIO mit Pausen und Handshaking. Hierzu reichen bereits Speicher und Anschlüsse und Geschwindigkeit eines minimalen 16MHz 28pin AVR oder gar ein 20pin oder 14pin ATtiny Modell.

All das was noch fehlt, alle Varianten davon, sind aber standard Programmiertechniken, keine offenen Fragen, nur Arbeitszeit.

SoftCPU

Mit SoftVGA haben wir nun einen auf circa 1980 Homecomputer Standard laufenden VGA Videogenerator in einem einzelnen Chip, für Eur 10. Damit kann man nun beliebigen Eigenbauprojekten billig eine kleine aber feine Videoausgabe geben. Einfach dem SoftVGA AVR die Daten die er in den Speicher schreiben soll als Bytestrom zuscheiben.

Neben dies kann man aber auch mit weiteren AVRs jede Menge andere Chips ähnlicher Leistung emulieren, obiger FIFO zweit-AVR ist nur der Anfang davon. Dieser kleine AVR könnte auch nebenbei die Ctrl-G aussieben und Beep generieren (oder gleich varierendes Audio generieren), oder gar mit einem PS/2 Anschluss (und Wandlung zu ASCII) und einem bidirektionalem RS232 (auch 3-Draht 5V pseudo-RS232 reicht) am Eingang ein vollständiges 2-Chip Terminal ergeben, für etwa 15Eur.

Das kann aber noch einiges weiter gehen. Für Leute die CPU Architekturen vergleichen, und dabei Ideen bekommen wie sie eine CPU gerne gehabt hätten, und damit experimentieren wollen, dürften da CPU Chips zum emulieren an erster Stelle stehen. Genau für solches ist mein nächstes Projekt SoftCPU da, die Techniken dafür auszuarbeiten. Dieses Projekt ist weitaus einfacher, da keine VGA Timing Probleme zu erwarten sind. Es muss lediglich die CPU brauchbar schnell sein (ausser man geht auf historisch kompatibles CPU Bustiming los).

Ich sehe keinerlei Probleme etwa einer 4-8MHz 8080/8085/Z80 bzw 1-2MHz 6502 folgen zu können (man hat 8-16 16MHz AVR Takte bzw 10-20 20MHz AVR Takte pro 6502 oder 8080 1MHz oder 2MHz Speicherzugriff). Das reicht also für beliebige Homecomputer Leistungsklasse CPUs emulieren. Selbst in C programmieren müsste drin liegen, für barbarische Assembler-Muffel, wenn eine langsamere CPU akzeptiert wird!

Ich habe an den Chemnitzer LinuxTagen SoftVGA vorgezeigt und bin dabei auf einen Professor unter den Besuchern gestossen, der auf AVR Basis eine CPU gemacht hat (als Studentenprojekt), und gerade vor hat VGA zu machen, was zu einem regen Gedankenaustausch führte. Er hat es immerhin geschafft, eine bustaktzyklengenaue Emulation einer 1MHz 6502 zu machen. Ich hatte bis anhin mit unpräzisem 1-2MHz gerechnet, variabel je nach Program und Befehlsmix. Es liegt also wieder mal mehr drin als ich vor hatte.

Was man nun mit einer SoftCPU alles machen kann? Nun eigentlich alles. Wer die heutigen expandierten Ataris, C64er, Schneiders, KC 85er, etc anschaut, weiss dass deren 1980er CPUs, auch heute für vieles ausreichen. Selbst mit ihren 64k Adressraum, einfach mit MBytes an RAM und EPROM Modulen aufgerüstet, für beides den Adressraum erweitert per Bankswitching Mechanismen (mit oft 2 verschiedenen Verfahren für RAM und EPROM!), und gar mit HDs oder Flashdisks angehängt, z.T. mit Floppyimages und Switching. Multitasking ist seit längerem möglich, mit einem laufenden Programm pro RAM Speicherbank. MP3s abspielen geht, solange die Decodierung in einem externen Chip passiert. Lediglich visuelle Multimedia (Photos und Videos) scheitert an Datenvolumen und Anzeigelimiten. Selbst Internet, und gar Webbrowser und Webserver liegen darin, Mail oder IRC ist gar kein Problem, remote Login ist sogar trivial.

Was für CPUs kann man nun auf die Art machen:

Sprachspezifische Prozessoren waren kommerziell immer ein Fiasko, weil wenige Benutzer Geld ausgeben wollten für ein 1-Sprachen System, trotz schnell und effizient/billig für die Leistung. Aber für Hobbyisten ist Kundenanzahl kein Thema, und der SoftCPU Konstruktion sind keine Fabrikationkosten (und damit Verkaufszahl) Limiten mehr gesetzt. Nicht einmal mehr (Um-)Lötzeit ist nötig, nur einer SoftCPU AVR den Mikrocode neu flashen (oder gar per Bootloader auswählen). Ist einmal die SoftCPU Hardware da, ist der Rest 100% reine Software, nur Schreiben Assembliern und Flashen, nur ein AVR Program, der Mikrocode für die neue emulierte CPU. So vielfältig wie eben das Homecomputer oder PC Emulator Angebot, aber es ergibt am Schluss emulierte CPU "Hardware".

Die Details von möglichen Programmiercodes, und den Techniken dies möglichst schnell oder aber zeitgenau hinzubekommen, werden auch morgen am Workshop durchgearbeitet werden. Die Workshop Zeitaufteilung zwischen SoftVGA und SoftCPU geschieht je nach Interessentenlage der Teilnehmer. Hier wieder nur ein paar Höhepunkte, wie ich mir Teile davon vorstelle.

Das SoftCPU Projekt ist momentan erst in Planung, also keine Praxiserfahrung, oder aus solcher entstandene Code Erfahrungen. Das ist aber kein grosses Problem. In SoftVGA waren die entscheidenen Teile auch lange genau der Code den ich eine Woche nach dem letztem VCFe finalisiert, und Jahre davor skizziert hatte, bis sie durch die neue Zeichenmethodiken ersetzt wurden.

Als Prozessor dient wieder ein AVR. Dessen 32 Register können dazu gebraucht werden, die Registerinhalte der emulierten CPU zu halten. Gerade auch die 16 Register ohne Konstantenbefehle werden so genutzt, weil sie nur Userdaten abbekommen, nur vom Speicher her (auch wenn es dort Konstanten oder Immediatewerte im Programmcode sind!), keine Konstanten aus dem AVR Mikrocode. Seltenere CPU Register kommen ins SRAM, z.B. der 2. Registersatz einer Z80 (der wird bei EXAF und EXX umkopiert). Aber SRAM wird auch benutzt z.B. für CPU interne Stacks (z.B. bei einer Forth CPU) oder für Caches (z.B. Adressen von Zeilen oder Variablen bei einer Basic CPU). Die Ablaufsteuerung des Emulators verteilt sich über beides, in Register (die mit Konstantenbefehlen) und SRAM. Im Flash des AVR ist der Microcode drin.

Die Befehle werden von einem Befehlsinterpreter im AVR Flash decodiert, was auf indexierte Sprungtabellen oder berechneten Sprüngen zu Routinen für jeden Befehl hinausläuft, bzw in C ein switch Konstruct. Da dabei oft gleiche Codesequenzen vorkommen wird man vieles mit Makros lösen wollen, oder gar mit einem Codegenerator. Aber das ist nur Optimierung, nicht notwendig.

Da das ganze ein emulierter CPU Chip sein soll, und kein ganzer emulierter Rechner (dazu würde der interne RAM Speicher ohnehin nicht ausreichen), bekommt dieser extern angehängte Speicherchips, wie jede normale CPU. Deren Adress-, Daten- und Steuerleitungen kommen an ganz normale PIO Pins des AVR, die damit den Prozessorbus bilden. Mit einen 40pin AVR seinen 4*8bit Ports erlaubt dies 2*8bit Adresse, 8bit Daten, nbit Steuerung, und ein paar freie Pins für Ein-/Ausgabe (z.B. RS232 mit den 2 UART Pins). Der emulierte Prozessor holt, wie die Originale, seinen Code und Daten vom externen Speicher, durch Sequenzen geeigneter Signale, generiert durch PIO Ausgabe und Eingabe Befehle. Andere AVR Ein-/Ausgabe wie Timer oder noch komplexeres muss dazu nicht benutzt werden, auch keine Interrupts (ausser man nimmt einen solchen als "Reset" der SoftCPU). Damit ist man mit der PIO Pin Auswahl relativ frei. Ebenso entsteht ausschliesslich einfacher geradeaus Programmcode, den jeder schreiben kann, notfalls sogar in C.

Verschiedenste moderne Retro Rechner Nachbauten (6502 basierte wie A-One oder Replica-1, oder 1802 basierter wie Cosmac Elf 2000) haben, als Folge der heutigen Speicherchip Auswahl, oft die "halb-halb" Kombination von einem 62256 32k SRAM und einem 28C256 32k EEPROM (oder 29C256 32k Flash) zum quasi-Standard gemacht. Das selbst für Mitte-1975er Systeme, die original viel weniger Speicher hatten, aber darauf mit vielen Chips ausbaubar gewesen wären. Das ist daher auch hier eine muss möglich sein Vorgabe.

Problem ist nur, dass 8080/Z80-artige Rechner ihr ROM ab Adresse 0 haben müssen (wo 6800/6502-artige ihr Zeropage RAM haben müssen), und dass 6800/6502-artige Rechner ihr ROM bis zur Adresse 0xFFFF haben müssen (wo 8080/Z80-artige üblicherweise ihren Stack erwarten). Die Hardware (genauer der RAM vs ROM Sockel Adressdecoder) bei jedem Prozessorwechsel umsteckbar/umschaltbar machen ist aufwendig und mühsam und Fehleranfällig. Einfach die RAM und ROM Chips austauschen verlangt nach identischen Sockeln (und verhindert damit die Nutzung der häufigeren schmalen 300mil Gehäuse 32k SRAM Chips) und resultiert früher oder später in abgebrochenen Pins. Verschiedene EPROM/EEPROM/Flash Chips mit Code für die verschiedenen Prozessoren umstecken beim wechseln ist auch mühsam, und man erwischt ab und zu den falschen. Und erst recht mühsam ist oft ausstecken, jedesmal wenn man das EPROM/EEPROM/Flash neu laden will, und dazu braucht man dann auch noch ein Programmiergerät zum diese laden.

Es gibt aber eine einfache Lösung für all das. Einfach zwei 32k SRAMs nehmen. Das ergibt durchgehend 64k RAM, kein ROM, keine adressspezifische RAM/ROM Anordnung (oder 50:50 Aufteilung), kein ROM zum laden, auch kein Programmiergerät dafür. Einziges neues Problem: Man hat auch keinen bei Stromverlust bleibenden ROM Inhalt mehr. Das ist aber einfach lösbar, denn der AVR hat ja bereits Flash drin, weitaus mehr als wir für den Mikrocode brauchen, welches bereits CPU-spezifisch geladen werden muss, per bereits vorhandenem SPI Adaptor. Man kann nun gleichzeitig den ROM Inhalt in einen Teil davon laden, und diesen beim Aufstarten vom AVR Flash ins externe RAM kopieren lassen, an den korrekten ROM Ort und Menge, bevor die SoftCPU auch nur einen Befehl vom resultierenden "ROM" holt. Bei etwa 2MByte/s (= 2kByte/ms) Kopiergeschwindigkeit sind selbst 32k "ROM" in 16ms kopiert, weit unter den wahrnehmbaren 100ms Verzögerung. Dazu wird der gewünschte ROM Inhalt in AVR Assembler Source .db Befehle "verpackt" in ein File abgelegt, und dieses dann per .include Befehl eingebunden.

Danach muss nur noch der AVR Microcode wissen welche Speicherbereiche nicht von Programmen der emulierten CPU beschrieben werden können (weil sie ROM sind, oder gar kein Speicher). Das geht mit einem einfachen und schnellen Sprungtabellen basierten Algorithmus, in 256 256Byte Blöcken festlegbar. Tabelle in Flash fix und langsam, in SRAM schneller und modifizierbar, aber eventuelle Platzprobleme. ROM direkt aus dem Flash auslesen, statt ins RAM kopieren, ist übrigens langsamer, da ein Test und Sprung bei jedem Lesen (inklusive Opcodes holen) nötig wäre, statt nur beim Schreiben (und auch da nicht immer, z.B. nicht beim Stack oder bei 6502 Zeropage).

Diese pseudo-ROM Technik kann aber auch noch viel mehr:

Die Ein-/Augabe von der emulierten CPU aus ansteuern wird dann abhängig von der emulierten CPU Sorte. CPUs die spezielle IN/OUT Befehle haben sind einfach zu handhaben. Einfach diese als normale Befehle decodieren und wie Speicher lesen oder schreiben ausführen, nur mit speziellem PIO Steuersignal Pins für IO statt Speicher Zugriffe bewegen.

Bei CPUs ohne IN/OUT Befehle hat man ein Problem, dass überall Speicher ist, und IO Geräte nicht dorthin können, weil dort nirgendswo Adressen frei sind. Und der Ort könnte je nach Prozessor oder gar System ohnehin verschieden sein, und damit müsste der Adressdecoder wieder variabel sein, wie bei der RAM/ROM Unterscheidung, nur noch variabler und aufwendiger. Anderseits muss man für Prozessoren mit IN/OUT Befehlen ohnehin die IO Hardware separat signalisierbar anhängen. Also kann man gleich den IO Adressdecoder in den Mikrocode nehmen. Dazu tut man hier wieder Speicherzugriffe auf 256Byte Blöcke testen, und dann die relevanten in pseudo-IN/OUT-Befehle umwandeln, diesmal nicht nur beim Schreiben sondern auch beim Daten Lesen (aber auch da vermutlich nicht immer, z.B. wieder nicht beim Stack oder bei 6502 Zeropage). Lediglich beim häufigeren Code Lesen kann den Test immer entfallen lassen, da man nie die Eingabe Ports ihre Inhalte als Code ausführt. Danach kann man die derart "abgezweigten" Adressen weiter behandeln wie oben.

Auch Interrupt basierte Ein-/Ausgabe kann man emulieren, indem ein PIO Pin zur Interrupt Leitung deklariert wird, und man diesen nach jedem emulierten Befehl abtestet, und falls der aktiv ist das geeignete Interruptverhalten nachstellt.

Damit kann man dann auf beliebige ganz traditionell gebaute externe Ein-Ausgabe Hardware zugreifen, wie mit einer richtigen CPU:

SoftIO

Nachteil all dieser Varianten ist, dass die Ein-/Ausgabe (In/Out, IO) dann durch die externe PIO oder USART Chipwahl und Verdrahtung fest vorgegeben ist, auch wenn obige Beispiels-Chips sehr universell sind. Das stört wenn es neben einer beliebigen emulierten CPU und Speicherkonfiguration und Ein-/Ausgabe Adressblock auftaucht.

Alternativ dazu kann man aber auch Ein-/Ausgabe Chip Interfaces emulieren: Man hängt die beiden SoftVGA und PS/2 AVRs (oder die AVRs des 2-Chip Terminals), direkt an die TxD und RxD Pins der eingebauten USART in dem SoftCPU AVR (plus 2 PIO Pins für alfälliges RTS/CTS Handschaking). Danach werden zur Ein-/Ausgabe nicht mehr Chip-spezifische Befehle als Speicher-artige Signalisierung über den Bus nach aussen geschickt. Statt dessen werden einzelne Portzugriffe auf eine PIO oder USART oder sonstwas als Schnittstelle emuliert (bis hin zu obigem Videoram abfangen!). Diese werden dabei über das auf sehr schnell plus Handshaking eingestellte AVR USART verschickt, und die Details im anderen AVR emuliert. Wenig Hardwareaufwand und dank Ports emuliert total flexibel, nichts ist bei solcher SoftIO mehr durch die Hardware festgelegt.

Mit z.B. einer 6502 SoftCPU und mit Dxxx als Ein-/Ausgabe abgezweigt im emulierten Adressdecoder und dahinter einem emulierten 6820 hat man ein A-One oder Replica-1 Äquivalent, aber mit einer Soft6502 im Haupt-AVR (statt Hardware 6502), Soft6820 im Neben-AVR (statt Hardware 6820), ohne TTL Decoder (im Original und Replica) bzw GAL Decoder (im A-One), mit dem Soft6820+SoftVGA AVR (statt selbigem AVR im A-One, bzw 2 AVRs + 2 TTL Chips im Replica-1, und das für nur 40x24 schwarzweiss TV Video!), und mit 2 RAMs statt 1 RAM und 1 EEPROM. Dafür aber mit wählbarer RAM/ROM Grenze, VGA Monitor (statt schwarzweiss Videomonitor), farbigem Video (fehlt allen anderen), und dazu noch per Microcode total andere CPU und Portchip und EEPROM Inhalt und Systemarchitektur ladbar. Mit leichter Änderung an den SoftVGA (anderes Video Interface) zum schwarzweiss Videomonitor Signale generieren (und geeigneter Software) sollte bei 18MHz und 6MPixel/s und 6 Pixel breitem Font sogar eine genaue pixelkompatible Replika der Apple 1 Ausgabe drin liegen (was die A-One sein ATmega32 wohl auch genau so macht).

Auch der SPI Anschluss der SoftCPU (und was an SEEPROM/SerialFlash/MMC/SD daran angesteckt ist) kann nicht nur für ROM Module benutzt werden, sondern mit genug Grösse (bis in die MBytes sind erhältlich) auch für emulierten Diskspace. Auf diesen wäre dann via einem in der SoftCPU AVR emulierten blockweisen Diskcontroller Interface zugreifbar, mit Filesystem von "Disk" geladen, analog zu Atari 800 oder PDP-8 oder CP/M oder IBM PC, oder gar ein ganzes Filesystem hinter einem Interface emuliert, analog zu Commodore ihren Floppylaufwerken (die eigentlich kleine Fileserver sind). Dazu wird man einen Teil der IN/OUT Befehle ihrer Adressen für das Interface "abzweigen" müssen. Die Tests dafür verlangsamen aber nur die IN/OUT Befehle oder Zugriffe, nicht den Speicher und den restlichen Programcode.

So ein emulierter SoftFDC Disk Controller, zusammen mit emuliertem IO, in emuliertem Adressspace, von einer emulierten SoftCPU, gibt dann ein vollständiges "komplett-softes" Rechner System. Das schönste dabei: Alle 3 AVRs dieses Systems, und ihre ganze externe Beschaltung, und ihre Verdrahtung untereinander, mit UART und SPI, ist 100% generisch. Man kann eine einzelne fertige Platine designen, klein, mit wenigen Teilen, schnell gelötet. Und kann dann auf dieser beliebige Microcodes betreiben, entweder Standardmikrocodes oder eigene spezifische, und das erst noch getrennt entschieden nach CPU und/oder VGA und/oder PS/2 drauf laden. Damit können nach einer Weile eine grosse Auswahl an Mikrocodes erhältlich werden, je nach was für Featuresatz und/oder Maschinencode jemand haben will. Resultat ist der universale formbare Mikrocomputer/Kleincomputer/Homecomputer.

Damit wäre dieser genauso flexibel wie ein C-One oder ein 1-Chip-MSX, aber weitaus freundlicher als mit deren FPGAs. Und der resultierende Rechner hat genug Leistung zum den eigenen Mikrocode auch auf dem System drauf zu erstellen (oder modifizieren) und (neu-)assemblieren/compilieren (was mit FPGAs nicht geht). Der SPI Anschluss der SoftCPU kann neben für ROM Modulen oder Diskspace sogar benutzt werden, zum einem weiteren AVR (und damit auch alle AVRs eines weiteren Systemes) ihren Mikrocode einzuflashen. Alles wird voll autonom von irgendwelchen PCs (was mit FPGAs wieder unmöglich ist, mangels Doku und folglich mangels Möglichkeit eines eigenen Compilers auf dem eigenen System).

Das geht alles, solange man im Leistungsbereich der 3 AVRs bleiben kann. Und der ist ja in etwa 1980er Homecomputer, was bekanntlich für vieles völlig ausreicht. Ebenso muss man auf bitgenaue Emulation/Kompatibilität verzichten, es gibt nur funktionale Äquivalente, aber das waren alle Homecomputer Originale untereinander auch, und das reichte damals auch.

Mit diesen 3 AVRs sind natürlich nur Prozessor+Video/Tastatur(+Modul/Disk) Rechner möglich. Will man weitere Funktionen eines Homecomputer-artigen Gerätes, wie Sound oder separates Floppy Laufwerk oder Kommunikation, muss man noch weitere AVRs addieren, zum deren Chips emulieren. Damit ist aber eine nur Tasten-RxD-CPU-TxD-Video 3-Draht 5V RS232 Architektur nicht mehr ausreichend. Auch wenn mit CPU-SPI-SEEPROM aufgerüStet.

Beim Wechsel von traditionell gebauter externer Ein-/Ausgabe Chips auf einem Bus, zu Interface Emulation mit nur USART und SPI dahinter, ging uns hier die Möglichkeit verloren beliebig viele externe Interfaces anzuhängen. Zum die AVRs eines derartigen Multi-Controller Rechners mit einander zu verbinden braucht es universellere Kommunikation. Da aber überall ein voller Mikrocontroller drin ist, läuft dies auf ein Multi-Rechner Kommunikationsnetzwerk hinaus, analog zu SCSI oder Ethernet oder USB.

Das ist aber nicht nur für uns ein Problem, sondern auch für viele andere "normalere" Mikrocontroller Anwendungen, die auch Erweiterung wollen, auf spezialisierte Features die nicht on-Chip sind. Netterweise stecken genau für diese Fälle bereits in jedem AVR spezialisierte Ein-/Ausgabe Schaltungen drin, die für beliebige Multirechner/Multicontroller Kommunikation geeignete Busse ergeben. Es hat sogar 3 verschiedene standardisierte Sorten davon:

Diese sind alles serielle Bus Systeme, zum Pins sparen. Sie können aber alle bis etwa Taktfrequenz/10 bit/s erlauben, also selbst bei einem langsamen 16MHz AVR noch etwa 16/10=1.6MBit/s und bei etwa 10 Byte/Zugriff Protikoll damit etwa 1.6/10=0.16MByte/s. Das ist mehr als ein typischer 1980er Prozessor Speicherbus seine Daten Kopier/Transferrate, welches ja nach Abzug von Opcodes holen und Byte rein und raus kopieren etwa 0.1MByte/s ist. Und es ist damit mehr als die IO Rate typischer 1980er 8bit Homecomputer. Und hinter dem Bus steht immer ein eigenständiger AVR Prozessor, der mit Eigenintelligenz und komplexen Funktionen den Busverkehr minimieren kann (z.B. einen Scrollbefehl statt Video RAM umkopieren). Und damit ist das wieder weit mehr als nur ausreichend.

Damit wird die SoftCPU zum Bus Master (alle 3 Bussysteme brauchen so einen, zum ihre Funktionsweise einfacher machen), analog zu einer echten CPU, und alle IO AVRs werden zu Bus Slaves, analog zu echten Peripheriechips. Dies entspricht dann dem Systembus der damaligen Rechner. Damit ist die Datenübertragung gegeben, und der CPU Emulator muss lediglich einen Satz von IN/OUT Befehlen (oder einen Speicherbereich) erkennen und dahinter ein Portsystem nachbilden, das dann Bytes auf diese Art verschickt oder erwartet. Neben dem Bus kann noch ein Interrupt System ausgearbeitet werden (keines der Busse hat eines fixfertig), so dass dann Peripheriechip AVRs Aufmerksamkeit erlangen können, und die Auslöser schnell erkannt und behandelt werden können.

Für einen erweiterbaren modularen kartenbasierten Aufbau kann ein kleiner "Slot" Stecker standardisiert werden für die wenigen Signale, mit etwa 10-16 Pins, z.B. ein schmales Bandkabel. Da dort nur Ein-/Ausgabe darüber geht, und keine Speicherzugriffe, beschränkt er auch nicht die Speicher und Prozessor Geschwindigkeit.

Für ein Basis-/Minimalsystem reichen wieder bereits die 3 bestehenden AVRs am Bus, der CPU/Master/Motherboard und 2 Peripheriechips/Karten:

Weitere fakultative AVR basierte Peripheriechips/Karten können dann sein:


Home | Artikel | VCFe Softe Hardware

Diese Seite ist von Neil Franklin, letzte Änderung 2009.05.30