Home | Informative Texts | Apple 1

Apple 1 - Hardware und Software Analyse


Inhalt

Einführung

Hintergrund für die Entstehung dieses Textes waren Disukussionen zwischen mir (Elektro Ingenieur und Lowlevel Programmierer sowie Retrocomputer Aktivist) und zwei Sportkollegen (beide Informatiker und Applikation Programmierer). Dabei waren auch Diskussionen zu moderner Bloatware, sowie als Gegenargument dazu wie die Rechner früher mit weit wenig Programm auskamen. Dabei waren auch kompakte Betriebssysteme im 2-stellig oder gar 1-stellig kByte Bereich ein Thema. Irgendwann habe ich den superkompakten Monitor vom Apple 1 entdeckt, der es schafft mit nur 256 Bytes an Betriebssystem zu laufen. Nein, das sind keine 256 kBytes, nur 1/4 kByte!

Nachdem ich dieses gegenüber einem der Kollegen beschrieb konnte er es kaum glauben. Ich habe ihm damals versprochen, die Funktion dieses Systemes zu erklären. Daraus entstand dieser Text. Ziel davon ist, den Apple 1 im Detail anzuschauen, sowohl von aussen was der Benutzer sieht, wie auch von innen was ein Programmierer davon sieht, die Hardware und Software davon. Dabei ist die zweite Hälfte vom Text zugleich ein Fall von Softwarearchäologie, was man ziemlich selten zu sehen bekommt.

Historische Situation

Die Geschichte des Apple 1 ist weitherum bekannt. Ich werde sie daher hier nur kurz zusammenfassen, plus noch ein paar unbekanntere Sachen addieren. Dem Namen nach ist es offensichtlich der erste Rechner von Apple, aber das ist das am wenigsten interessante daran.

Schon interessanter ist, dass er nicht von Apple entwickelt wurde. Das ganz einfach, weil Apple zu der Zeit noch gar nicht existierte! Vielmehr war es ein Hobbyprojekt von Steven Wozniak gewesen, der damit seine Kollegen beeindruckte, darunter auch Steve Jobs. Die Firma Apple wurde erst danach von den beiden gegründet, um diesen in Serie herzustellen und an Interessierte zu vertreiben.

Daraus entstand eine erste Serie von 200 Geräten, plus allenfalls ein paar 100e mehr später, bevor er durch den revidierten und erweiterten Apple II abgelöst wurde. Dementsprechend ist er selten, trotz im April 1976 eingeführt, und dem Apple II erst im April 1977 ein Jahr darauf erschienen. Davon sollen heute nur noch etwa 50 existieren, welche mit den vielen Apple Fans in der Welt demensprechend gesucht und teuer sind.

Weit interessanter ist daher, dass es als Folge davon diverse Formen von Nachbauten gibt. Manche davon sind Chip-für-Chip genaue Replikate, trotz dass manche der Teile fast nicht mehr erhältlich sind, bei Restpostenhändlern oder gar Elektronikausschlachtern erjagdt werden müssen. Für extreme Replikate werden sogar Chips aus dem genauen Jahr zusammengesucht, und selbst diese sind trotzdem billiger als die seltenen Originale!

Viel häufiger als Nachbauten sind daher nur funktionale Clones, mit den relativ einfach zu beschaffenden Teilen vom eigentlichen Rechner genau gleich und somit softwarekompatibel, aber die weit selteneren Terminal Logik Bauteile und die ebenso recht seltene Tastatursorte durch neueres vergleichbar wirkendes ersetzt. Selbst im eigentlichen Rechner werden die alten seltenen kleinen Speicherchips durch moderne grosse ersetzt. Mir bekannt die Replica 1 und A-One. (Und logischerweise gibt es auch Emulatoren, als reine Software auf PCs. Mir bekannt der POM-1.)

Als Folge der Apple Fans und dem Preis davon, wird der Apple 1 heute massiv überschätzt. Dabei wird er oft als den "ersten Homecomputer" ausgegeben. Was er aber nicht ist, weil er technisch gar kein Homecomputer ist, sondern ein Zwischenschritt von Mikrocomputer zu Homecomputer, wie weiter unten erklärt wird, was genau ihn interessant macht. Erst der Apple II war ein echter Homecomputer.

(Parallel zum Apple II kamen dann auch Commodore PET 2001 in Juni 1977 und Tandy Radio Shack TRS-80 Model I in August 1977, beide auch echte Homecomputer. Dazwischen kam der Processor Technology Sol-20 aber schon in Juni 1976, und war damit der erste echte Homecomputer. Dazu mit schnellerem Prozessor, und komfortablerer Software. Aber mit $2000 auch weit teurer, wenn auch dafür vollständig betriebsbereit. Während der Apple 1 zwar nur $666 kostete, aber auch nur als nackte Platine ohne Tastatur und Transformator und Gehäuse daherkam. Wobei man den Sol-20 auch als nackte Platine haben konnte, oder gar als Bausatz zum selber löten. Ebenso den Apple 1 sogar als blanke Platine ohne Bauteile.)

Technische Position

Das ist die historische Situation. Aber die technische Position macht den Apple 1 erst richtig interessant, weil er eben ein Zwischenschritt ist, und damit praktisch alleine da steht. Die 1970er/1980er Mikroprozessor basierten Rechner kann man in drei Kategorien einteilen:

Mikrocomputer mit Terminals

Diese sind von Minicomputern her inspirierte Rechner, aber auf Mikroprozessoren basiert. Angefangen als Kisten mit Lampen und Schalter Frontpannels. Wie bei Altair 8800 und Imsai 8080. Direkt kopiert von PDP-8 oder PDP-11 sowie vergleichbaren Rechnern. Darin als Boden ein passiver Bus und dahinter/daneben ein Netzteil. Darauf gesteckt eine Prozessorkarte und Speicherkarten und IO Karten. Generell sind hier alle S-100 oder ECB Bus Rechner. Wieder direkt kopiert von PDP-8 Omnibus bzw PDP-11 Unibus sowie vergleichbarem. Daneben kamen Rechner mit 7-Segment Hexcode. Wie beim KIM-1 oder Mikroprofessor 1. Auch inspiriert von PDP-8/A und PDP-11/34 sowie vergleichbaren. Wenn auch hier als einzelne Platine statt Kiste, mit nur einem Erweiterungsstecker statt einem Bus. Ausgelegt auf Lernsysteme statt Produktionssysteme.

Dann kamen Rechner mit seriellen RS232 Karten und Terminals welche ASCII plus Steuerzeichen brauchten. Dazu noch Floppydisks und passende Disk Betriebssysteme. Wie die meisten CP/M Rechner. Angelehnt an praktisch alle Minicomputer welche wegen mehrerne Benutzern Terminals brauchten, und auf Harddisks basierte Software hatten. Nur hier zumeist auf ein Benutzer und ein Terminal sowie kleinere billigere Floppys reduziert. Diese Terminals waren anfangs reine TTL Logik, wie bei der VT05 (um 1970), dann mit einem TTL Prozessorchen, wie bei der VT52 (um 1975), aber bald mit einem eigenem Mikroprozessor, ab VT100 (um 1980) und vergleichbaren.

Dann wurde wegen nur ein Benutzer und ein Terminal die Terminal Logik direkt im Rechner eingebaut, mit extern nur einem Videomonitor. Die einzige bei Minicomputern seltene Bauweise. Diese Logik zumeist als Terminalkarte auf dem Bus vom Rechner, weiterhin seriell angehängt, aber wegen kurzer Distanz auch teilweise parallel für direkten (Rechner-)Prozessor zu (Terminal-)Prozessor Datenaustausch.

Später wurde, weil nur ein Terminal, der Rechner nicht mehr als separate Kiste gebaut, sondern gleich in ein Terminal eingebaut. Auch das an die PDT Minis-in-Terminals angelehnt. Diese teils noch mit einem Bus voller Karten nebem dem Bildschirm, wie es die VT100 hatte, teils aber einfach eine grosse Platine unten drin, mitsammt Terminal Logik dort drauf.

Als Massenspeicher waren anfangs teils Lochstreifen, zumeist Floppys, selten Harddisk. System wird von diesen geladen, im ROM ist bestenfalls ein Monitor, aber oft nur ein Bootloader. Später auch gleich mit 5 1/4" Floppys im Terminal eingebaut, neben dem Bildschirm, während 8" immer externe Laufwerke hatten. Was letzteres wieder an die PDTs angelehnt war.

Homecomputer mit Videospeicher

Die logische Folge davon, dass es in neueren Terminals drinnen zumeist Mikroprozessoren hatte, und der 8008 als erster 8bit sogar als solcher Terminalprozessor entwickelt wurde. Ein Prozessor wird direkt für Rechner und Terminal geteilt, kein zweiter, kein Datenaustausch mehr, weder seriell noch parallel. Strikte eine Form von Mikrocomputer, da auf Mikroprozessoren basiert, aber wegen anderem Erscheinen kam ein neuer Begriff auf, der den alten verdrängte.

Es hat daher einen direkt vom gemeinsamen Prozessor beschreibbaren Videospeicher. Entweder zumeist im Hauptspeicher (Apple II, VC-20 C64 und C16,C116,Plus/4, Atari 800, Acorn BBC, alle Sinclair, Amstrad/Schneider CPC), oder seltener ein separater Videospeicher (Sol-20, PET/CBM, TRS-80, Texas Instruments 99/4, alle MSX Rechner). Den der Prozessor aber stets selber adressierten und byteweise beschreiben und auch auslesen kann. Wenn auch bei manchen mit separatem Videospeicher nur indirekt adressiert durch Adressregister in der GPU setzen (99/4 und MSX).

Es sind damit auch keine ASCII plus Steuerzeichen mehr nötig, um vom Rechnerprozessor zum Terminalprozessor zu kommunizieren. Ebenso hat es keinen Datenaustausch, weder seriellen noch parallelen. Allerdings wurde oft in der Systemsoftware auf dem gemeinsamen Prozessor ein ASCII plus Steuerzeichen benutzender Treiber eingebaut, um einfache gradlinige Textausgabe zu vereinfachen, sowie portieren von auf Minis aufgekommenen Programmiersprachen und damit geschriebener Software. Diese war aber nur für Basisfunktionen wie Kommandozeile zuständig, und stets umgehbar um ausgefalleneres wie Games selber direkt zu machen.

Als entscheidender Unterschied wird hier nicht vom Terminal gescrollt, nachdem in einer Zeile kein Platz mehr ist, oder ein Zeilenvorschub geschickt wird, oder bestenfalls eine Escapesequenz. Mit solches nur nach oben, oder mit Escapesequenz auch unten. Mit neue Zeichen nur zeilenweise unten ansetzen, oder mit Escapesequenz auch oben. Vielmehr kann hier in beliebige Richtungen auf/ab/links/rechts gescrollt werden, sogar teilweise auf Videozeilen bzw Pixelspalten genau statt nur Textzeilen. Sowie neue Zeichen zeilenweise oder spaltenweise angesetzt werden, unten/oben/links/rechts. Was gerade Games brauchen. Dazu kommen gamespezifische Fonts, oder aber Bitmapgraphik, oder beides schaltbar, was alles bei Terminals selten war, aber hier bald zum Standard wurde.

Als Massenspeicher anfangs Kassettenband und später Floppys. Weil diese langsam oder gar sehr langsam sind, wird das System in ROM geliefert. Anfangs nur mit Monitor wie im Sol-20. Aber sehr schnell mit Basic, ab Apple II und PET 2001 und TRS-80. Und später mit ROM Modulen erweiterbar, gerade auch für Spiele.

Personalcomputer als Kombination

Die Kreuzung von beiden obigen. Einerseits wie beim Homecomputer einen direkt vom gemeinsamen Prozessor beschreibbaren Videospeicher. Anfangs zumeist separater Speicher auf einer Graphikkarte, später auch direkt im Hauptspeicher, aber stets vom Prozessor direkt adressiert (wie in Sol-20 und PET/CBM und TRS-80), ohne GPU Register (wie in 99/4 und MSX). Wieder mit einem ASCII plus Steuerzeichen Treiber, bzw bei IBM dem Video BIOS, aber ebenfalls umgehbar. Strikte die letzte Evolutionsstufe vom Mikrocomputer, der die Vorteile vom Homecomputer in sich aufnahm, und dabei ebenfalls den alten Begriff fallenlies. Anderseits wie beim Mikrocomputer mit Floppys oder gar Harddisk. Mit System von diesen geladen, zumeist in ROM nur ein Bootloader, wie bei IBM das Disk BIOS, selten mit einem vollen Monitor.

Apple 1 als Zwischenschritt

Der Apple 1 schafft es dagegen, aus diesen Kategorien komplett herauszufallen, bzw eine umgekehrte Kombination zu sein. Einerseits indem er analog zu Mikrocomputern für Video ein Terminal hat. Was keinen ASCII plus Steuerzeichen benutzender Treiber braucht, und erst die so kleine Systemsoftware erlaubt. Dies aber wie bei späteren solchen mit Terminal Logik auf der einen Platine eingebaut, ohne Bus und Karten, und dazu noch parallel angehängt. Aber mit externem Videomonitor, nicht Rechner in einem Terminal eingebaut. Und auch keine Kiste, nur eine Platine wie bei Hexcode Rechner. Aber auch ohne eigenen Prozessor im Terminal, wie bei frühen Terminals wie dem VT05. Anderseits aber wie ein Homecomputer nur Kassettenband benutzt. Mit daher System im ROM. Allerdings das wiederum nur ein Monitor, Basic musste von Band geladen werden.

Damit ist er ein Zwischenschritt, wirkt von aussen wie ein Homecomputer, und wird daher oft mit solchen verwechselt, ist aber intern fundamental immer noch ein Mikrocomputer, wenn auch dort ein eher eigenartiger, mit sehr alt und sehr neu bunt gemischt. Der Apple II ist dagegen ein echter Homecomputer, aber der kommt erst nach dem Sol-20, ist somit nicht mehr der erste.

Hardware Aufbau

Diese ist sehr minimal. Alles passt auf nur eine einzelne Platine. Siehe Photos der Bauteileseite und der Lötseite. Des weiterem ist die Hardware im Apple I Handbuch beschrieben, als Schaltplan, auf 2 Seiten ohne Nummern, ganz am Schluss davon.

Lieferzustand war als nackte Platine, wie im Bild. Kein Transformator um die Stromaufbereitung zu versorgen (braucht 8..10V AC 3A sowie 25..28V AC 1A mit Mittelabgriff), ebenso keine Tastatur (muss fertige 7bit ASCII Codes liefern mit Bit7=1), und kein Gehäuse. Der Benutzer musste erstere beiden selber passende auftreiben, und letzteres selber herstellen. (Es wurden sogar manche als blanke Platine verkauft, ohne Bauteile drauf. Der Benutzer musste dann sogar diese auftreiben und auflöten.)

Auf dem ersten Platinenphoto sind oben Buchstaben A bis D und links Zahlen 1 bis 18 zu sehen, welche als Koordinatensystem einzelne Chips identifizieren. Diese finden sich wieder, im Schaltplan auf allen Chips, oberhalb deren Typenangaben. Sie werden hier im Text in Klammern referenziert, als "(an XX)".

Rechner

Als Prozessor (im Bild an Koordinaten A6..8, und im Schaltplan letzte Seite an Koordinate A7) läuft ein MOS Technology 6502 (der im Bild ist vom Zweithersteller Synertek). Dieser ist ein reiner 8bit Prozessor, ohne jegliche 16bit Operationen, ausser dass sie 16bit Adressen generiert, und daher einen 64kByte Adressraum hat, als 256 Pages (0..255) zu je 256 Bytes (0..255) organisiert. Dieser wird weiter unten in einem eigenen Kapitel detailiert beschrieben. (Clone benutzen den selbigen immer noch produzierten 6502 NMOS Chip, von 1975! Oder teils noch die 65C02 CMOS Variante davon.)

Der auf 1MHz ausgelegte Prozessor ist mit 1.0227MHz leicht übertaktet, weil das 1/14 des verwendeten sehr billigen NTSC Farbfernseher 14.31818MHz Quarzes ist. Das Taktsignal "CL" kommt von der Terminal Logik her, nach dort drin es durch 14 teilen. Erstaunlicherweise hat es keinerlei Power-On Reset Logik, nur die Reset Taste auf der Tastatur. Da die 6502 keine interne solche Reset Logik hat, und die Platine keine solche addiert, stürzt sie nach einschalten immer ab, wird erst durch Benutzer die Reset Taste drücken gestartet! Wozniak sieht dies nicht als Mangel, sondern als Feature, weil es hat ja schon die Reset Taste, wozu mehr?

Strikte kann die Platine auch mit einer Motorola 6800 laufen, aber diese Variante wurde nie verkauft, und war wohl nur als Notlösung gedacht, falls die neu erschienene 6502 scheitert. Das Handbuch weist im Schaltplan darauf noch darauf hin, aber auch dass man dazu all die fehlenden Bauteile innerhalb das gestrichelt umrandeten Teiles vom Schaltplan (unten links) dazu nachrüsten muss, sowie 2 Lötpunkte "6502" auftrennen muss.

An Speicher gibt es 2 Bänke aus je 8 Stück Mostek 4096 DRAM Chips (an B11..18 Bank X, bzw an A11..18 Bank W), welche jeweils 4k Adressen zu 1bit Breite haben, was pro 8-er Bank 4kBytes ergibt. Die 8 Stück 8T97 (an A9 und A10) hinter den DO Ausgängen der DRAMs sind reine Signalverstärker. Die 7410 (an B2) schaltet diese ein, falls Takt plus DRAMs selektioniert plus Lesezugriff.

Die DRAMs brauchen einen Adressmultiplexer, welcher Adressleitungen A0..5 bzw A6..11 anliefert, bestehend aus 2 mal 74S257 (an B5 und B6). Diese werden von einem weiteren Signal "CLA" aus der Terminal Logik gesteuert, nach mit einer 74123 (an B3) um 480ns verzögert werden. Für die eigentliche DRAM Steuerung wird Signal "RAS" aus dem Prozessortakt plus DRAMs selektioniert erzeugt, und Signal "CAS" aus RAS durch die beiden 74S257 mitschicken, so dass es nach umschalten der Adressen von der ersten 74S257 (an B5) auch durchgelassen wird, statt einer festen 1=inaktiv, aber durch die zweite 74S257 (an B6) noch etwas verzögert wird, um den geschalteten Adressen Zeit zu geben. (Diese sind nebenbei auch die Signalverstärker für A6..11.)

Ebenso brauchen DRAMs Refreshadressen, ebenfalls von der Terminal Logik her genommen, welche anstelle von A0..5 eingespiesen werden, via weiteren 2 mal 74S257 (an B7 und B8). Diese werden von der Kombination von zwei Signalen aus der Terminal Logik gesteuert, Signal "H6" wird während Zeichen anzeigen aktiv und Signal "H10" (bzw in der Terminal Logik heisst es "10H") wird jeweils bei Zeichen 09,19,29,39 aktiv (aber zudem auch 3 mal wenn keine Zeichen am anzeigen, daher wird es hier mit H6 kombiniert). Die eine 74S257 (an B8) schaltet zudem R/W auf festes 1=read, um den Speicher nicht zu verfälschen, und die andere 74S257 (an B7) hält nebenbei auch noch den Prozessortakt während der Refreshzeit auf 0=inaktiv an, um so einen Speicherzyklus "auszuleihen". Damit gehen aber 4/65 aller Speicherzyklen verloren, was den Prozessor von den realen 1.0227MHz auf 61/65 bremst auf effektive 0.960MHz, wie auch vorne im Handbuch angegeben. (Diese sind nebenbei auch die Signalverstärker für A0..5. Womit nur noch A12..15 weitere 4 Stück 8T97 (an A9 und A10) brauchen.)

(Clone nehmen hier üblicherweise einen einzelnen 62256 SRAM Chip von 32kBytes. Das sind 8 mal die 4k von einem 8-er Satz hier, also 64 mal soviele Bits im Chip. Und das trotz dass SRAM 4 mal so viel Chip Platz braucht wie gleich viel Bits DRAM, diese also mit 256 mal DRAM vergleichbar sind. Dafür laufen SRAM ohne Adressmultiplexer und Refreshadressen, und somit auch ohne die 4/65 Bremse. Diese *256 sind aber auch nur +4 Chipgenerationen zu je *4 grösser, mit Generationen in je 3 Jahren erscheinend, also 1977 +4*3 Jahren, auf Stand 1989. Noch 3 Jahre davor wären 6264 SRAM Chips von 8kByte machbar gewesen.)

Weiter gibt es eine Bank aus 2 Stück MMI 6301 PROM Chips (an A1..2), welche je 256 Adressen und 4bit Breite haben, welche somit 256 Bytes an Platz bieten. In diesen sitzt die ganze Systemsoftware, im Handbuch einfach als "6502 Hex Monitor" betitelt. Dieser wird weiter unten detailiert beschrieben, sein Interface und seinen Programmcode, mit letzterem alleine etwa die Hälfte vom Text, weil er mehr als alles andere diesen Rechner charakterisiert, neben noch dessen Terminal Logik. (Clone nehmen hier einen einzelnen 2864 oder 28256 EEPROM Chip von 8kBytes bzw 32kBytes.)

An Ein-/Ausgabe hat es eingebaut nur einen einzelnen Parallelport Chip (Bild an A3..5, Schaltplan an A4), ein Motorola 6820 oder 6821 (oder wie im Bild auch ein MOS Technology 6520). Welcher einerseits an Port A eine externe ASCII Tastatur erwartet, welche an einem 16pin IC Sockel (an B4) als Steckbuchse angeschlossen werden muss. Und anderseits an Port B die eingebaute ASCII Terminal Logik anspricht, mit Signale "RD1..7" (Ausgabedaten) sowie "DA" ("Zeichen wartet") und "RDA" ("Zeichen verarbeitet"). Wobei RDA noch mit einer 74123 (an B3) um 3.5µs verzögert wird. Fakultativ kann man mit 2 Lötpunkten die IRQA und IRQB Pins der 6802 an die IRQ bzw NMI Pins der 6502 legen, aber die Monitor Software in den PROMs kann damit nicht umgehen. (Clone benutzen auch hier den selbigen immer noch produzierten Chip, in einer der 6820 6821 oder 6520 Varianten.)

Weiter gibt es einen einzelnen Slotstecker (im Bild unten links), sowie gleich daneben (bzw im Bild darunter) einen Erweiterungsanschluss, an dem eine kleine Platine mit weiteren Slotsteckern angehängt werden kann. Letztere wurde selten genutzt, weil Apple nur eine einzelne Slotkarte anbot, das Kassettenband Interface. Dieses war nicht im Rechner eingebaut, sondern eine eigene Platine, mitsammt eigenen 2 Stück MMI 6301 PROM Chips drauf, welche in weiteren 256 Bytes dessen eigenen Treiber plus Utilities mitbrachten. Siehe Photos der Bauteileseite und Lötseite.

Abgesehen von diesem hat der Rechnerteil der Platine noch einen 74154 Decoder (an B9..10), der den 64kByte Adressraum in 16 * 4kByte Schnitte aufteilt, und damit 16 Lötpunkte ansteuert gleich daneben (im Bild rechts davon), welche mit 0..9 und A..F angeschrieben sind, passend zu den Hexadressen Blöcken 0xxx ... Fxxx.

Diese 4k Schnitte passen genau zu den 4k DRAM Bänken. Von denen ist die erste X im Lieferzustand per Lötpunkt "X" mit 0xxx verbunden. Die 6502 braucht in 0000..00FF (Page 0, Zeropage genannt) und 0100..01FF (Page 1, Stackpage genannt) stets RAM, sonst versagen manche Funktionen. Die zweite 1/W kann per Lötpunkt "W" wahlfrei an 1xxx (für erweitertes 8k RAM, ist Lieferzustand) oder per Draht an Exxx (für Basic, damit dieses auch in PROMs sein kann, was Apple aber nie angeboten hat) verdrahtet werden. Der Adressmultiplexer wird nur angesteuert, wenn eine der beiden "X" oder "W" von der 74154 aktiviert wird, aber auch stets direkt bei Refresh, von einer 7410 (an B2) gesammelt. Dies neben dass der Refresh die 74154 abschaltet, mit einer 7400 (an B1). Bei einem Apple I mit zweiter RAM Bank, aber ohne Drahtbrücke dort, wurde diese nie ausgenutzt, und es ist vermutlich ein "blankes" Replikat rein zu Ausstellungszwecken. (Im Bild ist eine zweite Speicherbank drin, und an Exxx gelegt für Basic.) (Clone legen ihre 32k SRAM an 0000...7FFF, ohne 74154 Decoder.)

Die 256 Bytes PROM kommen ebenfalls im Lieferzustand per Lötpunkt "Y" mit Fxxx verbunden. Darin erscheinen wegen 4k=4096Bytes Schnitte die 256er PROMs 4096/256 = 16 mal wiederholt. Die 6502 braucht in FFFC und FFFD ROM, sonst stürzt sie nach Reset ab! (Clone legen ihre 8k oder 32k EEPROM an E000..FFFF bzw 8000..FFFF. Mit entweder Fxxx 16 Kopien vom Monitor und Exxx 1 Kopie Basic. Oder statt Fxxx nur FFxx 1 Kopie Monitor und F000..FEFF für anderes frei. Wie etwa dem Krusader Assembler von Ken Wessen, der bei den Replica 1 und A-One Clonen vorinstalliert ist.)

Die 6820 kommt ebenso im Lieferzustand per Lötpunkt "Z" mit Dxxx verdrahtet. Das System braucht diese, sonst kann es weder Anzeigen noch Eingaben sehen. Ein Apple I auf dem dort keine Drahtbrücke ist, kann als unbenutzbar und somit nie benutzt angeschaut werden, und ist sehr sicher ein Replikat, entweder gezielt wegen "schöner" oder unwissend wegen "Draht = abgeändert" annehmen, im Blankzustand statt Lieferzustand und Gebrauchszustand nachgebaut. (Im Bild ist diese Drahtbrücke der Fall.) (Clone legen diese an Dxxx bei 8k EEPROM, oder schneiden diesen Bereich bei 32k heraus.)

Weiter vorhanden sind Lötpunkte "R" "S" und "T", alles Slotstecker Signale, von denen das Kassettenband Interface "R" an Cxxx braucht. Ein Apple I ohne Drahtbrücke dort wurde nie mit Kassetten benutzt. (Im Bild ist diese Drahtbrücke auch der Fall.) (Clone lassen dies zumeist weg, weil Kassetten eh mühsam sind. Sie verlassen sich rein auf EEPROM. Bei 32k sind nach Fxxx und Exxx benutzt sowie Dxxx weg immerhin noch 20k verbleibend. Oder sie speichern gar nichts ab.)

Terminal Logik

Neben 50% Rechner (an A1..18 und B1..18) und 10% Stromaufbereitung (an C16..18 und D16..18) hat die Platine noch 40% Terminal Logik um ein Bild zu generieren, welche dahinter nur noch einen Schwarzweiss NTSC Videomonitor braucht (im Bild Anschluss oben rechts). Dieses ist reines Schwarzweiss ohne Graustufen. Trotz kleiner zu sein als der Rechner ist sie weitaus aufwendiger zu verstehen.

Ein Videosignal ist 1V, aus 0.7V Differenz von dunkel nach hell, plus 0.3V weglassen als "superdunkel" für Synchronisationspulse. Es entsteht im Potentiometer R12 100Ohm (im Schaltplan zweitletzte Seite mitte links), getrieben vom Transistor Q5, mit dort Addition und Verstärkung der Stromstärken, von den Chips 74166 (an D1) Pin 15 und 74175 (an C3) Pin 6 durch die beiden Widerstände R1 1500Ohm bzw R2 3000Ohm. Das ist der ganze Anteil an Analogelektronik, alles andere ist digital, um für Pixel 1=hell=0.7V bzw 0=dunkel=0V und Synchronisationspulse 1=ohne=0.3V bzw 0=mit=0V anzusteuern.

Eine Videozeile besteht aus 40 Zeichen, zu je 7 Pixel (davon 5 das eigentliche Zeichen und 2 Abstand dazwischen), also 40*7 = 280 Pixel horizontal. Dazu wird der 14.31818MHz Quarz (an D13), mit einem Oszillator aus einem 7404 (an D12) betrieben, im ersten Viertel von einem 74175 (an C13) auf halbe Frequenz geteilt für die Pixelrate, von 7.159MHz, am Signal "DOT RATE". Dann mit 7 Takte davon abgezählt von einem 74161 (an D11) als 10,11,12,13,14,15,0 load 10,11,12,13,14,15,0 load ... unendlich. Die 7 Pixel werden ausgegeben mit einem 74166 (an D1), der beim 15 zu 0 Wechsel ein neues Zeichen lädt und dessen erstes Pixel ausgibt, bei allen anderen 6 Takten die weiteren Pixel, und ohne weiteres laden Leerpixel. Was zusammen 1/14 der Frequenz an Zeichen ergibt, mit 1.0227MHz. Deren 280 Pixel passen so mit 39µs Signaldauer in etwa 4/5 der sichtbaren Zeile von 51µs, was einen schwarzen Rand links und rechts ergibt.

Selbige 1.0227MHz bekommt auch der Prozessor als Takt gegeben, vom Bit Q2 der 74161 her, als Signal "CL", mit einem Wertverlauf von 0,0,1,1,1,1,0 0,0,1,1,1,1,0 ..., zu 4:3 asymmetrisch, um weitere Chips zu sparen. Des weiteren wird Bit Q3=0 benutzt um von 0 auf 10 zu springen. (Was ich hier nicht verstehe ist, warum dieses Q3 neben an PE, auch an CEP und CET geht. Was bei Q3=0 den Zähler anhält, aber da gleichzeitig das PE aktiv ist und Vorrang hat, wird ein ansonsten erzeugtes 0+1=1 ohnehin sofort mit der 10 überschrieben, was dann mit Q3=1 gleich wieder den Zähler aktiviert. Am ehesten könnte es sein, dass die CEP und CET Pins nahe bei Q3 und PE sind, und nicht bei 5V=1. Aber man könnte sie auch einfach leer lassen, was default 1 ergibt, und bei der nachfolgenden 74160 auch gemacht wird. Im Apple II werden auch diverse Zähler und Schieber ihre unbenutzten Steuerleitungen an "SOFT 5" gehängt, einem stets 1 liefernden Ausgang einer 74LS00 mit Eingänge = 0. Scheint den selbigen Grund zu haben, aber ebenso keinen ersichtlichen Vorteil gegen direkt an 5V für 1.)

Zudem geht Bit Q3 mit Signal "CLA" nach verzögern an den Adressmultiplexer, und als Signal "CHAR RATE" als Takt an eine Zählerkette von einer 74160 (an D6) und 3 weiteren 74161 (an D7 bis D9) um diese zu takten. Die 74160 zählt zumeist 0..9=10 Zeichen, und schickt Signal "10H" an die erste 74161 (an D7). Selbiges geht als Signal "H10" an den Refreshmultiplexer. Die 74161 zählt 9..15=7 Zeichengruppen, und kürzt bei der ersten davon die 74160 auf 5..9=5, für insgesammt 65 Zeichen. Was bei 1.0227MHz dann 63.5µs Zeilenzeit ergibt. (Was ich hier nicht verstehe ist, warum ein 0 zu 5 Anfangswert Schalter der 74160 und ein 0 zu 9 Anfangwert Schalter der 74161 vom Bit Q3 der 74161 her kommen, es nicht einfach feste 5 und 9 sind. Zumal der "LAST H" Ladeimpuls vom TC Pin nur bei 74160=9 und 74161=15 ausgelöst werden kann, womit letztere ihr Q3 stets 1 ist, und der Anfang so stets 5 bzw 9 wird. Ausser es ist auch obige "SOFT 5" Logik am Werk. Klar ist dagegen, dass eine 0 als Anfangswert der 74160 nur intern entsteht, nach einem Überlauf ohne Ladeimpuls von der 74161.)

Dabei wird Bit Q2 dieser 74161 zu 0,0,0,1,1,1,1, was genau Zeichen ausgeben oder nicht steuert, als Signal "HBL". Dieses steuert mit Q2=1 ob obige 74166 Zeichen laden darf, oder auf Leerpixel für den horizontalen Strahlrücklauf zurückfällt. Selbiges geht als Signal "H6" an den Refreshmultiplexer, um mit obigem Signal "H10" 4 mal pro Zeile aktiv zu werden, bei Zeichen 09,19,29,39. Zudem werden Q0 und Q1 als Signale "H4" und "H5" zu den Bits A0..1 der Refreshadresse mit Werte 0,1,2,3. Dabei wird zudem Bit Q0 zu 1,0,1,0,1,0,1, was mit Q2 bei beiden = 0 in einem 7432 (an C9) den Horizontalsync Impuls erzeugen, Signal "HSYNC". Insgesammt entstehen so 5+2*10=25 "Zeichen" Rücklauf plus 4*10=40 ausgegebene Zeichen in jeder Zeile, mit erstere 5 ohne + 10 mit + 10 ohne Horizontalsync Impuls, und letztere 4*10 mit auf jedem zehnten Refresh machen.

Das Videobild besteht weiter aus 24 Zeichenzeilen, zu je 8 Videozeilen (davon 7 das eigentliche Zeichen und 1 Abstand dazwischen), also 24*8 = 192 Videozeilen vertikal. Das ergibt zusammen 40x24 Zeichen, mit 5x7 Font in 7x8 Platz, und somit insgesammt 280x192 Pixel. Die Zeilen passen ebenfalls alle in etwa 4/5 der 240 sichtbaren Zeilen des Monitors, was auch einen schwarzen Rand oben und unten ergibt, und zusammen mit Rand links und rechts den genutzten Textausschnitt vom Bildschirm begrenzt.

Die obigen 63.5µs Zeilenzeit werden, mit dem "LAST H" Puls am Ende des letzten gezeichneten Zeichens, dem selbigem der auch die 74160 auf 5 setzt, an die verbleibenden beiden 74161 (an D8 und D9) weitergegeben. Diese zählen zusammen zumeist 0..255=256 Zeilen, mit 0..191=192 davon als Ausgabe plus 192..255=64 als vertikalen Strahlrücklauf, mit in letzteren dem Signal "VBL" aktiviert. Die Zeile 255 aktiviert zudem das Signal "LAST". Die 4 Bits der ersten 74161 gehen auch als Signale "V0..3" zu den Bits A2..5 der Refreshadresse. Damit dauert ein ganzer Refreshdurchlauf 16*63.5µs, und somit nicht ganz 1ms, was die DRAMs problemlos mitmachen.

Selbiger "LAST H" Puls geht parallel dazu, auch an eine weitere einzelne 74161 (an D15), welche bei nicht Strahlrücklauf oder in diesem bei Zeilennummern mit Bit V5=0 oder Bit V4=1 oder Bit V3=1 auf 10 gehalten wird. Sobald obiges nicht mehr gegeben ist, was nur bei Zeilen 224 bis 231 sein kann, zählt dieser los. Was 8 Schritte 11,12,13,14,15,0,1,2 gibt bevor er wieder auf 10 gehalten wird. Bei jeder Zahl mit Bit1=1 (11,13,15,1) werden mit dem Signal "VINH" die obigen beiden 74161 angehalten, was die Zeilenzahl von 256 auf 260 anhebt, näher zu den eigentlich vom Videomonitor verlangten 262. Bei jeder Zahl mit Bit3=0 (0,1,2) wird der Vertikalsync Impuls erzeugt.

Bedingt dadurch wie Videomonitore funktionieren, sind es real 2*192=384 genutzte Zeilen, von bei NTSC bis zu 2*240=480 sichtbaren, aus insgesammt 2*262.5=525, von denen aber abwechselnd (interlaced) pro Bilddurchlauf nur die gerade bzw ungerade nummerierten gezeichnet werden (was offiziell 480i genannt wird). Von denen werden hier aber nur die geraden benutzt, mit dafür in jedem Bild diese gezeichnet werden (was offiziell 240p genannt wird). Ebenso sind es strikte 280 Pixelpaare und so 560 Pixel (von den bei 14.31818MHz in den 51µs insgesammt möglichen etwa 730), was zu "breiten" Pixeln führt, und zusammen mit nur den geraden Zeilen benutzen zu einem streifigen Bild.

(Letzteres ist bei allen 1970er/1980er Videomonitor basierten Terminals und Homecomputern und Konsolen typisch. Es sollte bei gut gemachten Emulatoren auch so erscheinen, mit jede zweite Zeile schwarz gelassen. Zeilen statt dessen doppelt zeichnen (double scan) sollte nur ein Spezialfall sein.)

Die 5 von 7 Pixel und 7 von 8 Zeilen an Zeichen kommen aus einem Signetics 2513 (64*8)x5bit Zeichensatz ROM (an D2..3). Dieses kann für ganze 64 Zeichen je 8 Videozeilen liefern (wobei die achte Zeile immer 0 ist). Das reicht nur gerade für teil ASCII 32..95 darstellen, also gibt es keine 96..127 und somit auch keine Kleinbuchstaben. Genauer werden ASCII 96..127 einfach zu 64..95 umgewandelt, durch ASCII Bit5 fallenlassen, womit diese zu Duplikaten der Grossbuchstaben werden. Bzw strikte werden beide zu den ROM Zeichen 0..31, nur die 32..63 sind an ihrem ASCIII Platz im ROM. Dies geschieht durch ASCII Bit6 invertiert zum ROM Bit5 machen. Erst recht hat es keine Graphik, nicht einmal Blockgraphik, bestenfalls geht teilweise ASCII Art (es fehlen aber manche Sonderzeichen welche mit den Kleinbuchstaben und Delete zusammen in 96..127 sind). Das resultiert in genau diese Zeichen nutzbar sein:

  ASCII   im Bild    am ROM    Zeichen

 32..47     0..15    32..47      ! " # $ % & ' ( ) * + , - . /
 48..63    16..31    48..63    0 1 2 3 4 5 6 7 8 9 : ; < = > ?

 64..79    32..47     0..15    @ A B C D E F G H I J K L M N O
 80..95    48..63    16..31    P Q R S T U V W X Y Z [ \ ] ^ _

 96..111   32..47    fehlen    ` a b c d e f g h i j k l m n o
112..127   48..63    fehlen    p q r s t u v w x y z { | } ~
    

Um ein Bild auszugeben muss es einen Bildspeicher haben, um die 24 Zeichenzeilen zu 40 Zeichen/Zeile = 960 Zeichen abzuspeichen. Wozu aber keine RAM Chips verwendet wurden, sondern 6 Stück Signetics 2504 Schieberegister vorhanden sind (je 2 an D4 und D5 und D14). RAM steht für Random Access Memory, welches wahlfreien Zugriff auf beliebige Bits erlaubt, wozu RAM Chips Adressen brauchen. Schieberegister haben dagegen neben Stromversorgung und je eine Daten Ein und Aus Leitung nur noch einen Taktanschluss, aber keine Adressleitungen! Daher werden Bits von nur Ein genommen, und nach und nach intern durchgereicht, und erst an Aus ausgegeben nachdem alle anderen davor eingegangenen dort raus kamen. Was als Sequential Access Memory bekannt ist. Diese hier sind 1024bit lang, mit davon 960 benutzt und 1024-960=64bit unbenutzt.

(Womit diese Logik also intern ein 6bit Terminal ist. Wie die VT05 übrigens auch, mit genau selbigen nur 64 Zeichen. Aber mit 72x20=1440 Zeichen, wege 1970 in 6 Sätzen von je 3 Stück 512bit = 1536bit an Schieberegistern, mit 1536-1440=76bit unbenutzt. Auch Fernschreiber hatten oft nur selbige 64, wie beim ASR33. Weshalb die VT05 ebenfalls genau diese hat, und auch 72 Zeichen breit ist, weil als Fernschreiberersatz designt. Weshalb die 2513 ebenfalls diese hat, und somit auch der Apple 1.)

Der DS0025 Chip (an C11) dient dazu diese ihren Schiebetakt zu erzeugen. Getrieben vom Q0 der 74160, welche einen Taktzyklus pro 2 Pixel macht, und gesteuert durch Signal "MEM 0" 0=aus/1=ein. Die 7427 (an C5) Logik davor schiebt nur während den 40 Zeichen ausgeben, wenn Signal HBL=1, und nur im ersten Pixel von jedem Zeichen. (Das Signal "LINE 0" ist massiv missbenamst, da es die erste Spalte und nicht erste Zeile des Zeichens anzeigt!)

Schieberegister können ihre Bits aber nur in einer Richtung schieben, diese pro Bild darstellen alle einmal durchgehend. Sie können dabei keine Wiederholungen liefern, aber 8 Videozeilen/Zeichen verlangen nach jeweils 8-facher Wiederholung der Zeichencodes. Daher ist nach den 2504ern noch ein Signetics 2519 40x6bit Hilfsschieberegister vorhanden (an C3), seine Bits einmal pro Videozeile durchgehend. Genauer mit Signal "LINE 7" (dieses ist richtig benamst) in der letzten Zeile von einem 8er Satz die von den 2504ern kommenden Zeichen aufnehmen, und danach im folgenden 8er Satz 8 mal wieder von sich geben (und die ersten 7 mal wieder aufnehmen). Die Logik vor dem DS0025 dient auch dazu, die 2504er nur in der letzten Zeile der Zeichen zu schieben, wenn die 2519 aufnimmt. Die 2519 selber wird vom Signal "LINE 0" geschoben, für einmal pro Zeichen der Zeile.

Neben die 24*40=960 jeweils 8 mal wiederholen, hat es noch die 64 unbenutzten Bits der 2504er auszulassen. Diese werden nach dem Bild ausgeben im vertikalen Strahlrücklauf hindurchgetaktet. Bei genau 256-192=64 Zeilen davon könnte man hierzu etwas nehmen was 1 mal pro Zeile stattfindet, wie das Zeilenende. Aber die bestehende Logik schiebt die 2504er nur alle 8 Zeilen, weshalb man auf 8 mal pro Zeile kommen muss. Die bestehende Logik tut aber 40 mal pro Zeile schieben, also ist 40-8=32 davon eliminieren angesagt. Die einzige weitere auf das Signal "MEM 0" einwirkende Logik vom 7402 (an C10) wird bei Signal "VBL" im Rücklauf aktiv, und testet das Q3 der 17160, welches wegen 0..9 zählen 8 mal 0 und 2 mal 1 ist. Damit werden 2/10 und somit 1/5 der 40 bestimmt, was bei den 8 Zeichen 08,09,18,19,28,29,38,39 schiftet, und zusammen mit 64/8=8 Zeilen genau auf 8*8=64 Schifts kommt! Dies so einfach zu machen ist wohl der Hauptgrund, warum es nur 24*40=960 und nicht 25*40=1000 Zeichen sind, trotz dass letztere noch in die 1024bit 2504er passen würden.

Genau diese Signetics 2513 und 2504 und 2519 Chips sind heute sehr schwierig zu bekommen, weil sie nur kurze Zeit hergestellt wurden. Die ganze Schieberegister Technik wurde erst anfangs 1970er eingeführt, als 512bit und dann 1kBit davon genug gross und schnell waren, aber 1kbit DRAMs noch zu langsam (keine 1MHz Zugriffe) und 256bit SRAMs noch zu klein (32 Chips für 1kByte) waren. Womit diese sehr schnell veraltet waren, sobald nur eine Chipgeneration später mitte 1970er die weit flexiblere RAM Technik genug schnell (DRAMs mit 1MHz) und gross (SRAMs mit 1kbit) wurde. (Wozniak hat übrigens den Schieberegister Ansatz vom Don Lancaster TV Typewriter von 1973 übernommen, aber von 32x16 auf 40x24 Zeichen erweitert. Das trotz dass es 1976 inzwischen mit RAM machbar war, was Wozniak entweder ihm unbekannt war oder er hat es wegen aufwendiger sein abgelehnt.) (Weshalb Clone genau diese Terminal Logik komplett ersetzen. Ebenso die seltenen ASCII Tastaturen, ausser es werden dazu einfach die sehr ähnlichen Apple II Tastaturen benutzt.)

Der erstaunlichste Nebeneffekt der Schieberegister ist aber, dass sie nur beim Auslesen beschreibbar sind, indem an der aktuellen Anzeigeposition statt einer Kopie des alten Inhaltes ein neuer eingespeichert wird, mit zwei 74157 (an C4 und C14) als "alt/neu" Schalter. Daher kann die Terminal Logik nur einmal pro Bild ausgeben ein Zeichen einfügen. Womit es unmöglich ist, bei NTSC 60Hz (= 60 Bilder/Sekunde) mehr als 60 Zeichen/Sekunde auszugeben. Die ganzen max 960 Zeichen ausgeben dauert bis zu 960/60 = 16 Sekunden!

(Eine zweite 2519 vor den 2504ern könnte dies bis zu Faktor 40 beschleunigen, bzw genauer um soviele Zeichen wie die ausgegebenen Zeilen durchschnittlich darin haben. Dies weil mit bis zu 15750 Zeichen/Sekunde aufnehmen, und dann mit bis zu 60 ganze Zeilen/Sekunde weitergeben. Dieser wurde aber eingespart, weil eben ein Minimalrechner. AFAIK hat die VT05 so etwas drin.)

Die Zeichen selber kommen von der 6820 her, als Signale "RD1..7" welche die ASCII Bits 0..6 darauf haben. Die Signale "DA" und "RDA" zeigen "Zeichen wartet" bzw "Zeichen verarbeitet" an. Eine 74174 (an C7) synchronisiert die beiden, mit D1 zu Q1 bzw D2 zu Q2. Diese ist mit dem Signal "MEM 0" getacktet, und damit nur bei Zeichen anzeigen und kopieren bzw ersetzen aktiv. Die 7410 (an C6) mit Signal "CURS" wartet bis die 2504 bereit sind, in der richtigen Position geschoben um dies zu machen. Die 7427 (an C5) erkennt mit RD6=1 oder RD7=1 ob es ein druckbares ASCII 32..127 Zeichen ist. Die 7432 (an C9) schaltet mit Signal "WRITE" die beiden 74157, von "alt" (= behalten) zu "neu" (= einfügen).

Ausnahme gilt nur für das "neue Zeile" Steuerzeichen, ASCII Carriage Return, welches einfach die restliche aktuelle Zeile mit Leerzeichen auffüllt, in einem Zug, mit danach automatisch am Anfang der nächsten Zeile landen. Dieses wird von der restlichen Logik rechts von der 74174 erkannt, und zusammen mit der 74174 gesteuert. Die Logik aus den Signalen "RD1,3,4,2,5", plus obiges "druckbares Zeichen" nicht der Fall sein, erkennt den Anfang vom Carriage Return. Die D3 zu Q3 Speicherung hällt dieses aufrecht, um Leerzeichen zu wiederholen. Das Signal "LAST H" via D4 zu Q4 unterdrückt D5 zu Q5, und beendet weiter wiederholen. Das Signal "WC2" korrigiert die Cursorposition, welche sonst bei Signal "WRITE" einfach +1 macht.

Obiges reicht wenn ein Carriage Return am Ende der meisten Bildzeilen ausgegeben wird. Aber falls der Cursor auf der untersten ist, würde er am Anfang der nicht vorhandenen nächsten Zeile zum Bild herausfallen. Mit der 74174 vom Signal "MEM 0" getacktet würde er somit nach vertikalem Strahlrücklauf abwarten einfach am Anfang der ersten Zeile wiedererscheinen, so das Bild zyklisch überschreibend. Statt dessen ist hier aber scrollen vom Bild erwünscht. Dies kann man wegen der Shiftregister nur durch weitere 40 Shifts erzeugen machen, die erste Zeile ihre 40 Zeichen verlierend und die neue Zeile ihre 40 zu Leerzeichen machend. (Der TV Typewriter hat noch zyklisch überschrieben. Scrollen ist damit eine Erweiterung durch Wozniak.)

Aber es wird bereits in allen Zeilen geschiftet, 40 mal beim zeichnen, bzw nur 8 mal im vertikalen Rücklauf. Also kann man weitere 40 Shifts nur bekommen, indem man eine Zeile mehr zeichnet. Dazu wird, wenn das Signal "VBL" aktiv wird, nach dem Schritt von Zeile 191 zu 192, und falls Carriage Return am füllen ist, was per Signal "WC1" angezeigt wird, die Zeilennummer auf 191 zurückgesetzt. Womit erneut die letzte Zeile der Ausgabe ist, und somit nochmals die 2519 mit 40 Zeichen eingelesen wird für die nächste Zeile, womit die bereits geholte mit nochmals holen überschriebn und somit fallen gelassen wird. Dazu wird ausgenutzt, dass die beiden 74161 sonst 0..255 laufen, ohne mit PE laden, was nun für das 191 laden benutzt wird. (Was ich hier nicht verstehe ist, warum die 191 auch auf 0 schaltbar ist, aber das nur wenn nicht im vertikalen Strahlrücklauf oder wenn die 74160 Q3=1 hat, also auf 8 oder 9 ist. Wobei ersteres aber Bedingung ist um die 191 zu laden, ausser dies ist nur ein Seiteneffekt von der 7402 (an C10) als reinen Inverter von Q3 doppelt nutzen. Aber zweiteres macht auch keinen Sinn, warum es überhaupt dann 0 statt 191 laden soll, zumal bei 192 werden die 74160 von Signal "LAST H" neu 5 hat, und bis sie bei 8 ankommt die 74161 bereits wieder bei 191 sind.)

Selbiges füllen für längere Zeit machen ist auch die Bildlösch Logik, welche so lange wirkt wie die Bildlösch Taste dazu auf der Tastatur gedrückt wird. Dabei wird einfach alles mit Leerzeichen überschrieben. Dabei wird ebenfalls die Zeilenzahl, sobald vertikaler Strahlrücklauf erreicht ist, mit dem Signal "WC1" auf 191 gehalten bis losgelassen, gefolgt von mit Signal "WC2" den Cursor setzen. Dazu wird Signal "LAST" statt "LAST H" benutzt, welches garantiert dass bis zu einem Bildende gelöscht wird. Daher wird der Cursor auch auf die neue Zeile nach der letzten gelöschten gesetzt, womit dieser stets auf der untersten zu stehen kommt, die erste Ausgabe und Eingabe zuunterst im Bild geschieht, nicht von oben nach unten bis Bild voll, mit ab dann auf der untersten bleibend. Womit dies auch praktisch ein voller Reset der Terminal Logik ist. (Wer an einem Clone eine Apple II Tastatur benutzt hat keine Bildlösch Taste auf dieser. Das ist genau der Unterschied welcher diese zu "sehr ähnlich" aber nicht ganz identisch macht.)

Die eigentlichen Leerzeichen dazu werden von den beiden 74157 nebenbei "erzeugt", indem einfach ihre Ausgänge per Signal "CLR" auf 0 gezogen werden. Diese kommen sowohl in die 2504er wie auch direkt in den 2519. Daher wird auch das ASCII Bit6 erst beim kopieren von den 2504 zum 2519 invertiert fürs 2513 ROM, mit dem 7402 (an C10). In den 2504 ist es noch direkt drin, damit dort eben 0 = Leerzeichen gilt.

Zudem können gleichzeitig mit einer 7408 (an C12) alle angezeigt werdenden Zeichen mit Bit6=0 (also Leerzeichen und Sonderzeichen) ohne die 2504 zu ändern mit Bit6=1 (zu @ bzw Buchstaben) modifiziert werden, falls sie an der Cursorposition sind und die 555 (an D13) 1 abgibt. Damit entsteht vom 555 gepulst an der Cursorposition, welche stets ein Leerzeichen hat, ein blinkender Leer/@/Leer/@/... Cursor. Es kann kein reversblinkender Cursor dargestellt werden, weil die 2519 kein siebentes Bit speichern kann, um die "zeige Cursor" Position separat von der 6bit Zeichennummer zu halten.

Da einfügen alles weit langsamer ist als der Prozessor arbeiten kann, muss dieser bei jeder Ausgabe nachprüfen ob die Terminal Logik das letzte Zeichen bereits verdaut hat, und ein neues annehmen kann, oder der Prozessor warten muss. Die 6820 verwaltet diesen Status nebenbei, setzt via Pin CB2 das Signal "DA" wenn sie vom Prozessor ein Zeichen bekommt, und meldet diesem "erledigt" wenn sie das Signal "RDA" vom 74174 auf Pin CB1 bekommt. Selbiges macht sie auch für die Tastatur, Status ob bereits eine Taste vorliegt, oder der Prozessor warten muss, mit Signal "STB" von der Tastatur auf Pin CA1.

Die Cursorposition wird, um Bauteile zu sparen, mit einem wandernden Bit in einem siebenten 2504 (an C11) gespeichert. Dieses verwaltet von zwei Viertel vom 74175 (an C13) welche es synchronisieren, und mit einem Teil vom einten 74157 (an C14) welche es an der alten Position löscht. Ein weiterer Nebeneffekt davon, dass Schieberegister nur in einer Richtung schieben können, ist dass diese Cursorposition nicht reversiert werden kann, die Terminal Logik daher eine reine Fernschreiber-artige Ausgabe hat. Dies ist eindeutig das eigenartigste Stück Hardware im ganzen Rechner! (Der TV Typewriter verwendete eine total andere Cursor Schaltung, welche mit seinen 32x16 simpel war, aber bei 40x24 aufwendiger geworden wäre. Dieser Ansatz ist somit auch eine Umkonstruktion durch Wozniak.)

Womit es auch kein überschreiben oder gar korrigieren ausgegebener Zeichen geben kann. Bei Backspace kann der Kommandozeileneditor zwar im RAM ein Zeichen löschen, aber nicht auf dem Bildschirm! Wer jetzt das Bild ganz löschen und neu ausgeben will, stellt dazu noch fest, dass es dafür gar kein Steuerzeichen dafür gibt, oder überhaupt irgendwelche Steuerzeichen ausser Carriage Return! Was drausen ist bleibt draussen, bis es weggescrollt wird. Was nur durch durch 24 Carriage Return schicken geschehen kann, und 24/60 = 2/5s dauert. Oder die Bildlösch Taste auf der Tastatur gedrückt wird, wovon aber wiederum die Software nichts mitbekommen kann, genauso wie ein Fernschreiber von einem Blatt Papier vorspulen nichts merkt.

(Die VT05 hat trotz ähnlicher Logik sowohl einen reversierbaren (und sogar beliebig bewegbaren und voll positionierbaren) Cursor, wie auch ein Bild löschen (und auch aktuelle Zeile löschen) Steuerzeichen. Ebenso der TV Typewriter. Es geht also prinzipiell. Bild löschen wäre eigentlich nur nach dem "Steuerzeichen oder Textzeichen" Test falls es Steuerzeichen ist neben auf Carriage Return auch auf z.B. Form Feed testen (VT05 testet auf $1F für Bild löschen und $1E für Zeile löSchen), und mit dem Testergebnis mindestens 1 Bild lang den Bildlösch Taste simulieren. Aber dies wurden hier ebenfalls wegen Minimalrechner eingespart, womit diese Terminal Logik sogar noch weniger Funktionsumfang hat als ein VT05 Terminal!)

Apple II im Vergleich

Als Vergleich dazu, hat der Apple II selbige 6502, selbige 1.0227MHz, von selbigem 14.31818MHz Quarz, auch durch 14 teilen. Ein originaler Apple II hat ebenfalls keine Power-On Reset Logik, ein Apple II Plus hat solche. Dazu kommen bis zu 3 statt 2 Bänke DRAM, aus entweder 8 Stück selbiger 4096er Chips (= 4kByte), oder 8 Stück neuerer 4116er (= 16kByte), oder gar Bänke beider Sorten im Rechner, und somit 4 8 12 16 20 24 32 36 oder 48kByte. Mit der Language Card konnten weitere 16k an 4116er addiert werden.

Dazu hat es bis zu 6 Stück 2kx8bit ROMs, und somit bis 12kByte. Diese mit massiv erweitertem Monitor, sowie bereits eingebauter Kassettenband Software, im obersten der 2k (Apple II hat Monitor II, und Apple II Plus hat Autostart Monitor). Ebenso gibt es erweitertes Basic im ROM (Apple II hat Integer Basic in 3*2=6k, und Apple II Plus hat Applesoft II Basic (ein Microsoft Basic mit Floating Point) in 5*2=10k). Vor der Language Card gab es noch die ROM Card, mit der man beide Softwares umschaltbar haben konnte, später wurde die Language Card für beide plus weiteres benutzt.

Die 74154 und Lötpunkte sind durch aufwendigere flexiblere Logik und Steckplätze ersetzt. Diese kann 7 Orte für 4k DRAMs an 0xxx 1xxx 2xxx 3xxx 4xxx 5xxx oder 8xxx, bzw 3 Orte für 16k DRAMs an [0-3]xxx [4-7]xxx oder [8-B]xxx decodieren. Das mit Steckplätzen statt Lötpunkten, um die Bänke den Orten zuzuordnen, mit für alle typischen Konfigurationen fertige Steckmodule angeboten (und im Handbuch eine Anleitung um untypische selber herzustellen). Dies ergibt alle DRAMs in Adressen 0xxx..Bxxx. Dazu kommen ROMs in Dxxx..Fxxx (wovon Monitor in F800..FFFF, und Basic in E000..F7FF bzw D000..F7FF), und Ein-/Ausgabe in Cxxx. Die Language Card addiert ihre 16k als 12k in [D-F]xxx plus 4k als doppelte Dxxx.

Video ist selbiges Schwarzweiss ohne Graustufen, selbige 40 Zeichen/Zeile zu 24 Zeichenzeilen = 960 Zeichen. Das mit selbige 5+2=7 Pixel und 7+1=8 Videozeilen pro Zeichen, aus selbigem 2513 Zeichen ROM und somit im selbigem 5x7 Font. Ergibt insgesammt selbige 280x192 Pixel, ebenso "breite" Pixel und streifiges Bild. Also selbige Eckdaten wie der Apple 1, abgesehen von mehr Speicher, passend zu einem revidierten und erweiterten Design!

Komplett fehlen aber alle Schieberegister! Das Bild wird direkt aus dem DRAM Speicher geholt, aus 960 Bytes davon. Dies bremst den Prozessor aber nicht, weil die neueren DRAM Chips sogar 2MHz aushalten, dem Prozessor und Video je 1MHz davon geben. Auch der Refresh bremst den Prozessor nicht mehr auf 0.960MHz, da es im Video seiner Zeit gemacht wird, bzw die ohnehin notwendigen Videozugriffe gleich den Refresh liefern. Weil das DRAM 8bit breit ist, die 2513 wegen ihrer 64 Zeichen aber weiterhin nur 6bit ausnutzen kann, schalten die verbleibenden 2bit zwischen normaler reverser oder blinkender Darstellung. Mit letzerem vom selbigen 555 Chip gesteuert. Das dann für das Zeichen mit den Cursor blinken benutzt, diesmal echtes reversblinken, und somit auch bei allen Zeichen machbar, nicht nur bei Leerzeichen zu @ blinken.

Es gibt weiterhin zwei Graphikmodi, "Low Resolution" mit nur 40x48 Blöcke aber in 16 Farben, aus selbigen 960 Bytes, sowie "High Resolution" mit 280x192 Pixel Bitmap aber nur in 6 Farben, aus 8*960 Bytes. Zudem kann man 20*8 Zeilen oben Graphik mit 4*8 Zeilen unten Text mischen. Ebenso kann man 2* 960 bzw 2* 8*960 Bytes umschalten, weil es Speicherplatz für zwei Bildseiten hat, um bessere Animationstechniken zu erlauben. (Der Apple II Europlus kann neben NTSC 60Hz auch PAL 50Hz Timing. Aber die Farben funktionieren auf PAL Farbmonitor oder Fernseher nicht, weil es dazu 17.734472MHz statt 14.31818MHz als Taktbasis bräuchte.)

Der Prozessor beschreibt den Bildspeicher direkt, wie auch den restlichen Speicher, von dem der Bildspeicher einfach ein Ausschnitt ist, weshalb dies ein echter Homecomputer ist. Alle Schieberegister Probleme sind weg. Nichts mehr mit langsamer Ausgabe, diese ist nur noch durch mit dem Prozessor das Bild scrollen umkopieren auf etwa 1000 Zeichen/Sekunde limitiert. Ebenso kann er Cursorposition reversieren, und somit auch Bild korrigieren oder löschen. All das ohne Zeilen separat zu wiederholen, oder unbenutzte Bits durchzutakten, oder Carriage Return auffüllen. Ebenso weg ist die 6820, sowie bei Ausgabe auf deren Status warten.

Auch weg ist aber die automatische ASCII Zeichenverarbeitung der Terminal Logik, sowie automatisches löschen und scrollen, sowie automatisches Cursor positionieren. Dies alles muss nun von der Systemsoftware im Treiber simuliert werden, welcher ebenfalls im grösseren Monitor ROM drin ist. Diese geht sogar soweit, den Cursor nach Bild löschen auf die unterste Zeile zu setzen. Sie liefert aber auch mehr Funktionalität. Wegen dem gemischten oben Graphik und unten Text kann der gescrollt werdende Bildspeicherbereich reduziert werden. Diese Funktion wurde gleich auf alle vier Bildkanten ausgeweitet, was beliebige scrollbare Fenster erlaubt, um Titel-/Fusszeilen oder seitliche Menus stehenzulassen. Was ansgesichts dessen aber erstaunlicherseise komplett fehlt, ist Cursor beliebig positionieren, es bleibt weiterhin eine reine Fernschreiber-artige Ausgabe!

Tastatur ist eine sehr ähnliche, selbiges direkt ASCII erzeugend, nur ohne der Bildlösch Taste. Sie wird aber gleich mitgeliefert. Sie wird neu ebenfalls ohne 6820 gelesen, mit nur 2 74LS257 und dem Status in 1/2 74LS74. Dabei ging aber auch die Möglichkeit von Tastatur von IRQA/KYBD an IRQ legen verloren, weshalb er trotz mehr Monitor keine Tasten/Zeichen vorzu in einen Tastenbuffer lesen kann, weiterhin solche nur sieht wenn er auf Eingabe wartet. Weiterhin hat die Tastatur wegen nur leicht erweitertes ASCII erzeugen unvollständige Pfeiltasten (links/rechts aber kein auf/ab, und links erzeugt ein Backspace, ist also eher eine Korrekturtaste), was neben obigem fehlenden Cursor positionieren, einen auf solchen aufbauenden komfortablen Kommandozeileneditor praktisch verhindert.

Slots sind bereits 8 eingebaut, mit Nummern 0..7, ohne Erweiterungsplatine. Die 1..7 sind auf je eine Page bei Adressen C1xx..C7xx fest verdrahtet für PROMs darauf, sowie alle 8 zudem auf 16er Sätze C08x..C0Fx für Ein-/Ausgabe darauf. Des weiteren sind C800..CFFF frei für schaltbare grosse ROMs auf Karten. Dazu kommt noch dass das Kassetten Interface bereits eingebaut ist. Zudem hat es einen Beep Tongenerator, sowie einen 4Paddle/2Analogjoystick Anschluss, weil Wozniak an Breakout-artigen Spielen interessiert war (er hatte für Atari am Breakout Spielautomaten optimieren gearbeitet). Alle eingebaute Ein-/Ausgabe ist in C00x..C07x, mit als Teil davon auch die Videomodi und Bildseiten schalten.

Schliesslich hat es mitgelieferte Schaltnetzteil und Gehäuse, und alles ist fixfertig zusammenmontiert. Nur einen normalen NTSC Schwarzweiss oder Farb Videomonitor oder Fernseher, sowie einen Kassettenrekorder, musste man haben oder besorgen. Dafür kostete es auch $1300, statt den $666 vom nackten Apple I. (Hier gab aber, es analog zur seltenen blanken Platine Ausgabe der Apple1, auch eine seltene nackte Platine Ausgabe. Diese war vor allem als Upgrade für bestehende Kunden gedacht, welche schon Tastatur hatten.)

(Dieses revidierte Design ist übrigens die Folge davon, dass der Apple 1 Designer Steven Wozniak diesen dem 6502 Designer Chuck Peddle zeigte. Wonach jener ihm als Antwort einen Zusammenschiss erteilte, dass er keine Ahnung habe, wie man mit Mikroprozessoren designt, sprich dass man dedizierte Hardware durch Prozessor und Software ersetzt. Dazu gehört eben Systemsoftware im Treiber statt Hardware ASCII Terminal Logik, aber deswegen auch Bildspeicher in RAMs statt Schieberegister. Mit dem Apple II hat Wozniak diese Lektion umgesetzt, und dazu noch massiv erweitert.)

(Anderseits hat Peddle davon inspiriert den PET 2001 geschaffen. Dieser ist noch konsequenter in Software statt Hardware. Zeichen sind statt 2513 Spezialchip mit 64 Zeichen in 7x8 Platz, ein normales 2kx8bit ROM mit eigenen 2*128 Zeichen in 8x8 Platz. Das erlaubt umschaltbar teil ASCII 32..63 plus 64 Graphikzeichen inklusive 2x2 Blockgraphik, oder voll ASCII 32..127 plus 32 Graphikzeichen inklusive 2x2 Blockgraphik. Es bleibt noch 1bit für normale oder reverse Darstellung, mit daher Cursor blinken in Software statt mit einer 555. Allerdings hat er bloss SRAM Speicher, mit nur dem 2*4k Platz der Apple 1, trotz der Herstelltechnologie der 16k DRAMs im Apple II. Zudem hat er den Bildspeicher in separaten 1k SRAM, dafür aber 40x25=1000 Zeichen und 320x200 Pixel. Er hat keine Graphikmodi, kann Low Res noch teilweise mit den Blockgraphik Zeichen kompensieren, aber hat keinerlei Bitmap wie bei High Res, und auch keine Farben. Die Tastatur erzeugt nicht ASCII per Spezialchip, sondern arbeitet mit der Tastenmatrix direkt vom Prozessor einscannen und in Software zu ASCII verarbeiten, und kann daher auch vollen Satz an Pfeiltasten anbieten. Dazu erst noch mit einem generischen Zeitpuls an IRQ nutzen, um zu scannen und in einem Tastenbuffer ablegen. Ebenso hat die Ausgabe Cursor beliebig positionieren, und der komfortable Kommandozeileneditor kann direkt im Bildspeicher editieren. Mit dafür noch mehr Systemsoftware im Treiber von dessen Monitor ROM. Insgesammt hat es 3* 2kx8bit Monitor und 1* 2kx8bit Editor und 4* 2kx8bit Basic (sowie 1* 2kx8bit Font). Der Videomonitor und ein Kassettenrekorder sind bereits eingebaut, er kann so aber keine bestehenden benutzen/teilen.)

Kommandozeile Interface

Das ist die Apple 1 Hardware. Aber wie ist der zu benutzen? Was kann die Systemsoftware darauf, welche in nur 256 Bytes an PROM passen muss? Eigentlich alles was man braucht, und mit einem Monitor Programm üblicherweise machen kann, Daten und Programme anzeigen, ebensolche eingeben und modifizieren, sowie Programme starten! Aber auch alles sehr primitiv und minimalistisch. Für die vollen Details siehe das Apple I Handbuch, Seiten 3 und 4.

Einschalten (bzw erst Reset Taste auf der Tastatur) tut genau einen Backslash ausgeben als "Abbruch" Zeichen (eben weil kein löschen im Terminal existiert), und dann die Cursorposition auf die nächste Zeile setzen. Einen Prompt gibt es keinen. Nur den Leer/@/Leer/@/... blinkenden Cursor. Auf der Kommandozeile kann man eintippen, maximal 128 Zeichen. Bei mehr bricht er mit obigem Backslash ausgeben und zu nächste Zeile gehen ab, praktisch einen Reboot des Rechners ergibt. Dabei gehen keine Daten/Programme vom Speicher verloren, aber die aktuelle Eingabezeile schon. (Dem Apple II sein massiv erweiterter Monitor II gibt * als Prompt aus, und hat maximal 255 Zeichen.)

Mit ASCII "_" (auf alten ASCII 1963 kompatiblen Tastaturen ist das ein Pfeil nach links, zum "_" wurde es erst mit ASCII 1967) kann man ein Backspace/Backdelete machen. Im Speicher der Kommandozeile wird ein Zeichen gelöscht, aber auf der Anzeige bleibt das Zeichen erhalten, bzw genauer wird dahinter auch noch das "_" ausgegeben. Mit ASCII Escape kann man "Abbruch" verlangen, wieder gibt der Monitor einen Backslash aus. ASCII Carriage Return veranlasst die Kommandozeile auszuwerten.

Kommando Ausgabe

Bei als Kommando einfach eine Hexzahl (Ziffern 0..9, A..F) eintippen, werden dessen letzten 4 Ziffern als eine Adresse verwertet und diese gefolgt von : und ihren Inhalt in Hex ausgegeben. Zahlen mit 1..3 Ziffern werden mit 0-en davor auf 4 Ziffern aufgefüllt. Tippt man Mist kann man statt "Abbruch" einfach 4 weitere richtige Ziffern eingeben, die davor gehen dabei verloren, weil "vorne" herausgeschoben, aber mit "_" Backspace/Backdelete ist eh schneller. Mehrere Adressen mit Leerzeichen getrennt gelten als mehrere Kommandos, und erzeugen mehrere Zeilen mit je Adresse und Daten. So wie hier gezeigt:

Benutzer:   FF00
Rechner:    FF00: D8
Benutzer:   2B
Rechner:    002B: 00
Benutzer:   28002B
Rechner:    002B: 00
Benutzer:   28_B
Rechner:    002B: 00
Benutzer:   FF00 FF10 FF20 FF30
Rechner:    FF00: D8
Rechner:    FF10: DF
Rechner:    FF20: 8D
Rechner:    FF30: D0
    

Kommando Blockausgabe

StartAdresse.EndAdresse gibt Startadresse und alle Daten in diesem Adressbereich aus. Diese als maximal 8 Bytes pro Zeile, was 4 Adresse + 1 ":" + 8 * (1 Leer + 2 Daten) = 29 Zeichen pro Zeile an Platz benutzt, für soviele Zeilen wie nötig. Was wegen 29 Zeichen plus Carriage Return (29+1=30)/60Hz=0.5s pro Zeile dauert, nicht unterbrechbar ausser mit Reset Taste. Nur .EndAdresse gibt aber nach der letzten ausgegebenen Adresse fortgesetzt aus, und erlaubt so portionenweise ausgeben. Wieder sind mehrere Adressen und/oder StartAdresse.EndAdresse beliebig gemischt mit Leerzeichen getrennt erlaubt. Damit kann man beliebige Daten/Programme anzeigen. Das Monitorprogramm selber kann mit FF00.FFFF ausgegeben werden, ist aber 32 Zeilen zu 8 Bytes. Das passt nicht voll auf den Bildschirm, weshalb man eher FF00.F7FF und danach .FFFF benutzt, was dann zweimal 16*0.5=8 Sekunden dauert. Hier nur einen Ausschnitt davon:

Benutzer:   FF00.FF1F
Rechner:    FF00: D8 58 A0 7F 8C 12 D0 A9
Rechner:    FF08: A7 8D 11 D0 8D 13 D0 C9
Rechner:    FF10: DF F0 13 C9 9B F0 03 C8
Rechner:    FF18: 10 0F A9 DC 20 EF FF A9
Benutzer:   .FF3F
Rechner:    FF20: 8D 20 EF FF A0 01 88 30
Rechner:    FF28: F6 AD 11 D0 10 FB AD 10
Rechner:    FF30: D0 99 00 02 20 EF FF C9
Rechner:    FF38: 8D D0 D4 A0 FF A9 00 AA
Benutzer:   FF00.FF07 FF10 FF20.FF23 FF34.FF35
Rechner:    FF00: D8 58 A0 7F 8C 12 D0 A9
Rechner:    FF10: DF
Rechner:    FF20: 8D 20 EF FF
Rechner:    FF34: 20 EF
Benutzer:   .FF3F
Rechner:    FF36: FF C9
Rechner:    FF38: 8D D0 D4 A0 FF A9 00 AA
    

(Apple II tut bei leerem Return einfach die nächste einzelne Zeile als Block ausgeben. Ein Apple II Plus mit Autostart Monitor kann durch Ctrl-S (Stop) eingeben eine zu lange Ausgabe pausieren.)

Kommando Eingabe

Bei als Kommando StartAdresse:Daten... eingeben, mit die einzelnen Datenbytes durch Leerzeichen getrennt, gibt es zuerst den alten Inhalt der StartAdresse aus und überschreibt dann diese, und auch alle folgende Adressen ohne weitere Ausgaben. Wieder gilt 1 Ziffer wird mit 0 auf 2 aufgefüllt. Ebenso bei Mist tippen einfach 2 richtige Ziffern eingeben, die davor gehen "vorne" herausgeschoben vergessen. Ebenso wirkt auch mit "_" löschen. Nur :Daten... schreibt nach der letzten beschriebene Adresse weiter, und erlaubt so längere Eingaben. Dies geschieht ohne die StartAdresse und den alten Inhalt ausgeben. Damit kann man beliebige Daten und Programme eingeben und modifizieren. Wie dieses kleine Demoprogrämmchen:

Benutzer:   300.30F
Rechner:    0300: 00 00 00 00 00 00 00 00
Rechner:    0308: 00 00 00 00 00 00 00 00
Benutzer:   300: A9 8D 20 EF FF A9 C1 20 EF FF 4C 1F FF
Rechner:    0300: 00
Benutzer:   300.30F
Rechner:    0300: A9 8D 20 EF FF A9 C1 20
Rechner:    0308: EF FF 4C 1F FF 00 00 00
    

(Apple II kann auch einen Ausschnitt vom Speicher an einen anderen Ort umkopieren. Damit kann er zudem Speicher mit Kopien eines einmal gegebenen Musters füllen, bzw mit als Muster nur ein Byte von 0 auch Speicher löschen. Ebenso kann er 2 Ausschnitte vom Speicher vergleichen, mit nur die Differenzen ausgebend.)

Kommando Starten

Als Kommando Adresse gefolgt von R (Run) eingeben gibt wieder zuerst den Inhalt der Adresse aus, und startet dann ein Program ab dieser Adresse. Nur ein R nimmt wieder die letzte angezeigte Adresse. Falls man gerade von einer StartAdresse:Daten Eingabeserie kommt, nimmt es dessen erste einzige ausgegebene (und überschriebene) Adresse, und nicht etwa die letzte überschriebene! Selbst nach mehrern :Daten... gilt dies, nur die letzte ausgegebene zählt. Das Adresse und R Kommando gibt ebenfalls erste Adresse und Inhalt aus, R alleine aber nicht. R kann wiederholt die selbige Adresse starten. Man kann auch fast beliebig Adresse, StartAdresse.EndAdresse, StartAdresse:Daten... und AdresseR in einer Kommandozeile mischen, bis zu den maximal 128 Zeichen. Genauer darf nach einem ":" keine Adresse mehr in der Zeile erscheinen, weil alle Zahlen ab dann Daten sind.

Die Cursorposition bleibt nach dem angezeigten Inhalt stehen, falls nach AdresseR oder StartAdresse:Daten... R vorhanden. Sonst am Anfang einer leeren Zeile, falls nur R benutzt. Programme sollten daher normalerweise mit Return ausgeben anfangen. Nach jedem Kommando, und so auch R und dann Programende gibt der Monitor ein Return aus, also kann man sich dort eines einsparen. Das AdresseR und R kann dann bei obigem Demoprogrämmchen so aussehen:

Benutzer:   300R
Rechner:    0300: A9
Programm:   A
Benutzer:   R
Rechner:    ... nichts hier, weil keine Adresse eingegeben!
Programm:   A
    

(Apple II kann neben Programm stur laufenlassen auch zwecks debuggen es schrittweite ausführen, mit nach jeden Schritt alle Register anzeigen. Oder stur laufenlassen mit vorzu die Register anzeigen. Ebenso kann es nach normal laufenlassen explizit die Register anzeigen. Zudem kann es ihren Inhalt modifizieren und Programm fortsetzen. Apple II Plus sein Autostart Monitor wurde aber zu gross und hat daher das schrittweite ausführen fallengelassen.)

Kassettenband

Wer Daten/Programme abspeichern und laden will, braucht das Kassettenband Interface. Dieser benutzt das Signal "R" am Slotstecker, welches mit Cxxx verbunden sein muss. Dessen eigene Software wird vom Monitor aus mit C100R gestartet. Es bietet dann eigene Kommandozeile nach gleichem Muster an: StartAdresse.EndAdresse, gefolgt von W (Write) schreibt, gefolgt von R (Read) liest. Nach jedem Kommando gibt es automatisch "Abbruch" zum Monitor. Weiteres Kommando braucht daher zuerst wieder C100R, aber man kann mehrere Kommandos in einer Zeile eingeben, aber nur alle schreibend oder alle lesend, anderes ist wegen Bandlaufwerk Verhalten sinnlos.

(Apple II kann direkt schreiben mit W und lesen mit R, ohne zuerst ein C100R, weil Kassettenband Interface und Software bereits eingebaut sind. Daher braucht er für starten auch G (Go) statt R (Run).)

Basic kommt auf Kassette daher, braucht die zweite Bank DRAM, auf E gelötet, und wird mit C100R und dann E000.EFFFR geladen, was 30 Sekunden dauert, plus Band zurückspulen. Apple empfiehlt, nach dem ersten laden mit C100R und E000.EFFFW auf ein zweites Band zu backupen. Basic starten ist vom Monitor aus mit E000R.

(Apple II hat Basic in ROM, muss es daher nicht laden. Es kann direkt mit Ctrl-B (Basic) gestartet werden. Es wird sogar mit dem Apple II Plus Autostart Monitor nach Reset automatisch gestartet. Weshalb man dort mit Befehl CALL an Adresse $FF69 den Monitor starten muss, der wiederum mit Ctrl-C (Continue) verlassen werden kann.)

Beliebige Bytes

Wer sich nun fragt, was all die ausgegebenen und eingetippten Daten als Zahlen eigentlich bedeuten: Die erste Antwort ist: beliebiges! Die genauere Antwort: Strikte sind sie einfach eine Darstellung der 8 Bits der Bytes im Speicher. Dies in hexadezimaler Notation. Dabei werden die 8 Bits zu 2 mal 4er Gruppen zusammengefasst um Tipparbeit zu sparen. Wobei man nur auswendig lernen muss, dass es pro 4bit dann 2^4 = 16 Kombinationen gibt, bei welchen folgende kleine 4x4 Tabelle gilt:

0=0000  1=0001  2=0010  3=0011          00xx sind also 0123
4=0100  5=0101  6=0110  7=0111          01xx sind also 4567
8=1000  9=1001  A=1010  B=1011          10xx sind also 89AB
C=1100  D=1101  E=1110  F=1111          11xx sind also CDEF

  xx00    xx01    xx10    xx11
  sind    sind    sind    sind
  also    also    also    also          02468 und ACE sind   gerade Ziffern
  048C    159D    26AE    37BF          13579 und BDF sind ungerade Ziffern

obige Adresse FF00, Ausgabe Daten D8, sind D=1101 und 8=1000, also 1101'1000
obige Adresse 0300, Eingabe Daten A9, sind A=1010 und 9=1001, also 1010'1001
    

Was die Bytes wiederum bedeuten, hängt davon ab, was für Daten man gerade am eingeben, bzw Programm man am codieren ist. Für Daten will man entweder direkt Zahlenwerte eingeben, oder Textcodes.

Für Text braucht man eine Tabelle der ASCII Codes 00..7F (weil 7bit Umfang, Damit Zahlenwerte Dezimal 0..127 bzw Hex 00..7F). Manche Rechner wie der Apple 1 (und auch Apple II) verlangen nach ASCII mit Bit7=1, weshalb statt 00..7F dann 80..FF verwendet werden müssen. Ebenso werden wegen der 6bit Terminal Logik die Kleinbuchstaben 60..7F (bzw E0..FF) zu Duplikaten der Grossbuchstaben 40..5F (bzw C0..DF). Somit entsteht:

      ASCII     Apple     Zeichen
    Dez   Hex  +Bit7=1  +x0 1 2 3 4 5 6 7 8 9 A B C D E F 

  0..15    0x    8x       --- nur 0D = Zeilenumbruch, rest unbenutzt ---
 15..31    1x    9x       ---          alle unbenutzt                ---
 32..47    2x    Ax         ! " # $ % & ' ( ) * + , - . /
 48..63    3x    Bx       0 1 2 3 4 5 6 7 8 9 : ; < = > ?
 64..79    4x    Cx       @ A B C D E F G H I J K L M N O
 80..95    5x    Dx       P Q R S T U V W X Y Z [ \ ] ^ _
 96..111   6x    Ex       @ A B C D E F G H I J K L M N O     (Duplikate)
112..127   7x    Fx       P Q R S T U V W X Y Z [ \ ] ^ _     (Duplikate)
    

Der Text "APPLE 1" wird damit zu: A in Zeile Cx + Spalte x1 = C1, P in Dx + x0 = D0, L in Cx + xC = CC, E in Cx + x5, Leerzeichen in Ax + x0 = A0, 1 in Bx + x1 = B1, also insgesammt C1 D0 D0 CC C5 A0 B1. Dies an 0400 eingeben wird zu:

Benutzer:   400.407
Rechner:    0400: 00 00 00 00 00 00 00 00
Benutzer:   400: C1 D0 D0 CC C5 A0 B1
Rechner:    0400: 00
Benutzer:   400.407
Rechner:    0300: C1 D0 D0 CC C5 A0 B1 00
    

Für Programmcode gibt der Prozessorhersteller in seinem jeweiligen Handbuch die Beschreibung der Befehle und ihrer Codes. Dies zumeist auch mit in einem Anhang zwei Listen der Codes. Die eine nach Befehlen geordnet, um diese in Hexzahlen zu übersetzen (zumeist einfach alphabetisch sortiert, bessere nach logischen Kriterien tabelliert). Die andere nach Hexzahlen geordnet, um diese in Befehle zu übersetzen (oft einfache Liste, bessere wieder als Tabelle). Im Apple 1 wird eine 6502 verwendet. Siehe zu dieser gleich anschliessend ihre Beschreibung.

Viele Benutzer haben darauf aufbauend ihre eigenen Tabellen geschrieben, gerade auch wo der Hersteller nur Listen lieferte. Siehe weiter unten am Ende der Prozessor Beschreibung für meine Zusammenfassung inklusive meiner Tabellen. Das war aber auch so immer noch langsam und mühsam, weshalb man die häufigen Befehle bald auswendig lernte.

(Apple II hat als eine seiner Erweiterungen, dass diese Listen zum übersetzen eingebaut sind, der Rechner dies für einem gleich selber machen kann. Was dort als LIST (Ausgabe) bzw Miniassembler (Eingabe) bekannt ist. Wobei strikte nur LIST ein eingebauter Befehl ist, aber der Miniassembler ein externes Program welches mit F666G gestartet wird. (Wobei letzteres nur auf Apple II mit Integer Basic der Fall ist. Auf Apple II Plus mit Applesoft II Basic war dieses zu gross und hat den Miniassembler wieder verdrängt.)

6502 Prozessor

Obiges ist den Apple 1 Monitor benutzen. Aber was sind nun die Programm Bytes? Diese sind 6502 Maschinencode, der nun besprochen wird. Die Geschichte der 6502 ist ebenfalls weitherum bekannt. Ich werde sie daher hier nur kurz zusammenfassen, plus noch ein paar unbekanntere Sachen addieren. Neben Intel ihre 8080, anfangs 1974, als revidierte 8008, kam Motorola mit ihrer 6800 heraus, ende 1974, und wurde der zweite grosse Hersteller. Mehrere andere Hersteller welche auch 1974..76 herauskamen, hatten in ihren Prozessoren zuviele Designfehler und/oder Marketingfehler und setzten sich nicht durch.

Beide diese waren recht grosse und teure Chips (eine 8080 kostete anfangs $360). Einige der Motorola Leute meinten es sollte kleiner und billiger gehen, wurden aber vom Management geblockt. Sie verliessen die Firma und landeten bei MOS Technology. Entgegen weit verbreiteter Ansicht haben sie MOS nicht selber gegründet, da diese bereits seit 1969 existierte! (Motorola selber ging mit der 6809 zu einem grösseren Chip. Intel revidierte die 8080 weiter zur unwesentlich grösseren 8085, und deren Leute welche grösser haben wollten und deswegen geblockt wurden gründeten Zilog und brachten die erweiterte Z80 heraus.)

Die 8080 brauchte 4500 Transsitoren in kompakterer 12V Technologie. Die nur leicht erweiterte 8085 brauchte 6500 wegen aufwendigerer 5V Technologie. Die 6800 hatte nur 4100 in 12V mit eingebautem 5zu12V Spannnungswandler, dann revidiert 5000 in 5V, war also schon etwas kleiner. Dagegen brauchte die 6502 nur noch 3500 trotz von Anfang an 5V! (Obige 6820 ist auch in 12V mit 5zu12V Wandler, 6821 revidiert in 5V, aber leicht inkompatibles Timing und daher andere Nummer. Die 6520 ist ein Clone mit von Anfang an 5V.)

Ein derart kleinerer Chip ist nicht nur billiger, sondern hat auch weniger Defektexemplare zum wegwerfen, was ihn nochmals billiger macht. Folglich wurde die 6502 mit $25 eingeführt, als 8080 und 6800 noch $150 bzw $175 kosteten. Diese wurden beide über Nacht auf $75 reduziert. (Alle Zahlen sind wegen Inflation für heute 2018 mit etwa *4 zu korrigieren, entsprechen also nur $100 statt andere $600 bzw $700, welche zu $300 wurden. Bzw eine 8080 anfangs $1440!)

Alle diese Prozessoren sind 8bit mit 16bit Adressen, als 256 Pages (0..255) zu je 256 Bytes (0..255) organisiert. Alle verwenden, wie fast alle anderen 8bit auch, die 1-Adress Logik, bei der eine Rechnung der Sorte V1=V2+V3 in drei Schritte Temp=V2; Temp=Temp+V3; V1=Temp zerlegt werden muss. Das Temp ist ein 1Byte Register (eine Speicherstelle im Prozessor drin), und wird Akkumulator oder kurz A genannt. Die 8080 hat im Prozessor zudem 6 Bytes für lokale Variablen. 6800 und 6502 sparen diese ein. Die 6800 kompensiert das mit 2 Temp A und B haben, die 6502 lässt selbst dies weg, hat nur das Temp A. Die 8080 hat dabei 8 Rechenoperationen, die 6800 sogar 9, die 6502 aber nur 7 davon. Man sieht deutlich wo das kleiner und billiger herkommt!

Die 8080 muss bei mehr als 6 Variablen explizit vom Speicher holen (verbesserte Methoden dazu sind der Hauptunterschied von 8008 zu 8080), ausser Konstanten welche stets implizit sind (in 8008 und 8080). 6800 und 6502 dagegen holen implizit bei jeder Operation, inklusive Konstanten (ausser die 6800 nimmt Daten von B zu A). Dies macht beide einfacher zu programmieren, aber auch langsamer wegen weit mehr Speicherzugriffen brauchen, neben Befehl auch noch Adresse und Daten transferieren. Was sie aber mit bei gleicher Technologie halber Speicherzugriffszeit teilweise kompensieren können.

Dazu hat die 6800 noch ein 2 Byte Hilfsregister (Indexregister genannt, ist aber eigentlich nur ein Basisregister), die 6502 dagegen 2 separate mit je 1 Byte (und erst noch echte Indexregister). Die 6800 kennt dazu neben Konstante auch 3 Methoden den Speicherort zu definieren (2 ohne und 1 mit Hilfregister), welche als Adressmodi bekannt sind. Die 6502 kann erstaunlicherweise sogar ganze 7 Adressmodi (2 ohne und 5 mit den beiden Hilfsregistern), was ihre Hauptstärke ist, wodurch sie trotz einfacher sein mit der 6800 etwa gleichziehen kann. (Die 8080 nimmt Paare ihrer 6 Variablen als Hilfsregister, kann neben Konstante nur 2 Methoden den Speicherort zu definieren (1 ohne und 1 mit Hilfregister).)

Befehlssatz

Da dies ein Apple 1 Text ist, und nicht ein 6502 Text, werden hier nur die wichtigsten Befehle und ihre Basiscodes und Adressmodi davon eingeführt, welche oft verwendet werden, um den Programmcode vom Monitor nachvollziehen zu können:

Alle Befehle sind stets 1 Byte, mit danach allenfalls 1 Byte an Daten, bzw 1 oder 2 Bytes an Adressen (je nach Adressmodus). Alle 16bit Adressen werden in 2 Bytes zerteilt wegen 8bit Prozessor. Damit besteht der 64k Speicher ja auch aus 256 Pages (Nummern 0..255) zu je 256 Bytes (0..255), wegen 2*8bit. Zudem werden diese beiden Bytes reversiert gespeichert, zuerst die untere/niedere/Bytenummer Hälfte und danach die obere/höhere/Pagenummer, falls beim Gebrauch der Hilfsregister und dabei benutzter Addition Übertragsrechnungen anfallen. (Die 8080 macht das auch reversiert. Die 6800 aber nicht, und muss bei Übertrag einen Korrekturzyklus abwarten.)

Befehl LDA: Ist Lade (= LoaD) zu Akkumulator vom Speicher, macht A = Daten, ohne zu rechnen. Gefolgt von #Daten bedeutet dieser Befehl eine 1 Byte Konstante holen, genauer vom Speicher das Byte gleich nach dem Befehl, was Immediate Adressierung heisst. Bei reinem # ist die Konstante in Dezimal, bei #$ die Konstante in Hex. Bei nur $ ohne # ist von Speicher holen, mit expliziter Adresse in Hex. Falls 4-stellig eine volle 2 Byte 16bit Adresse als Modus, wie oben reversiert. Oder falls 2-stellig eine kompaktere und schnellere 1 Byte 8bit Adresse als Modus, welche mit 00 davor erweitert wird. Daher sind auch die 0000..00FF Zeropage als RAM so wichtig. (All dies gilt ebenso bei der 6800, nicht aber der 8080.) Die weiteren fünf Adressmodi mit Hilfsregister sind seltener, werden hier ignoriert, bzw wo benutzt vor Ort beschrieben. (LDA hat als Basiscode A1, mit Adressmodi Konstante/Immediate +08 = A9, 16bit Adresse +0C = AD, 8bit Adresse +04 = A5.)

STA: Ist das selbige umgekehrt, Speichere (= STore) von Akkumulator zum Speicher, macht Daten-Variable = A. Geht aber nicht mit Konstante, weil in eine Konstante speichern sinnlos ist, ansonsten hat es selbige Adressmodi. (STA hat als Basiscode 81, Rest der Adressmodi wie bei LDA, nur ohne Konstante.)

LDX,STX,LDY,STY: Sind selbige beides mit den zwei Hilfsregistern, welche X und Y heissen. LDX und LDY sind X = Daten bzw Y = Daten, inklusive Adressmodus Konstante, STX und STY sind Variable = X bzw Variable = Y, ohne Konstante. (Basiscodes sind LDX A2, STX 82, LDY A0, STY 80. Man sieht alle LDx haben Ax, alle STx haben 8x, ebenso alle xxA haben x1, alle xxX haben x2, alle xxY haben x0 (und mit x3 gibt es gar nichts). Solche Systematiken helfen auswendig lernen. Adressmodi sind selbige +0C und +04 wie gehabt, aber bei Konstante/Immediate ist hier +00 statt +08. Das ist komplett irregulär, und nervig zum lernen. Noch schlimmer, das Gebastel um dies im Prozessor zu machen beinhaltet erst noch einen Prozessorbug, der bei Codes 02 22 42 62 sicher, und nach manchen Aussagen bei allen x2 ausser A2, den Prozessor abstürzt!)

ADC,SBC,AND,EOR,ORA: Sind rechnen mit Akkumulator und Daten vom Speicher, machen A = A <Operation> Daten. Daten wie gehabt, inklusive Konstante. Operation ist: ADC (= ADd with Carry) macht Addition, SBC (= SuBtract with Carry) macht Subtraktion, AND,EOR,ORA machen die benamsten logischen Operationen. ADC und SBC erzeugen einen Übertrag, und benutzen auch stets den Übertrag von der letzten Rechnung. Es gibt hier keine ADD und SUB ohne Übertrag von letztem (wie sie bei 6800 und 8080 vorhanden sind). Die Implikationen davon werden vor Ort beschrieben. (Basiscodes sind ADC 61, SBC E1, AND 21, EOR 41, ORA 01, wieder alle mit x1 weil auf den Akkumulator A wirkend. Ebenso sind Adressmodi wie bei LDA, inklusive Konstante/Immediate.)

CMP,CPX,CPY,BIT: Sind testen A oder X oder Y durch Vergleich mit Daten vom Speicher. Operation ist bei CMP,CPX,CPY vergleich (= CoMPare) mit testweiser Subtraktion. Also ohne das Resultat in A abzulegen, nur der bei allen LDx oder Rechnungen gesetzte Teststatus wird hier doch gesetzt. Diesmal ohne Übertrag von der letzten Rechnung, aber erzeugt einen Übertrag. Daten wie gehabt, inklusive Konstante. Operation is bei BIT (BInary Test) nur mit A als testweises AND. Ohne Konstante. (Basiscodes ist CMP C1, wieder x1 weil Akkumulator. Adressmodi sind wie LDA. Dieses bricht aber die Namensregel, sollte eigentlich CPA heissen. Aber dann sind CPX E0 und CPY C0. Wobei das CPX sowohl die CPx sind Cx wie auch die xxX sind x2 Coderegeln bricht. Adressmodi wie LDX und LDY. Und BIT ist 20. Dies kann gar keine Konstante, wegen Regelkonflikt in der Prozessorverdrahtung, vom Konstanten/Immediate Adressmodus ihrer +00 bei x0 aber +08 bei xxA. Was nervt wenn man diesen Modus brauchen würde.)

INX,DEX,INY,DEY: Sind INcrement (= +1) und DEcrement (= -1), und Rechnen mit den Hilfsregistern, X = X+1, X = X-1, Y = Y+1, Y = Y-1, zumeist um die nächste oder vorherige Adresse zu erzeugen. (Codes sind INX E8, DEX C8, INY C0, DEY 80, komplett irregulär. Es hat bei diesen logischerweise keine Basiscodes + Adressmodi, da auch kein Speicher benutzt wird oder adressiert werden muss.)

BPL,BMI,BVC,BVS,BCC,BCS,BNE,BEQ: Sind verzweige (= Branch) von der linearen Fortsetzung des Programs, falls eine von 4 Bedingungen erfüllt sind oder nicht. Diese testen falls das Ergebnis der letzten LDx oder Rechnung oder Vergleich resultierte in: BPL (= Branch PLus) falls positiv, BMI (= MInus) falls negativ, BVC wird wo einmal benutzt vor Ort beschrieben, BVS wird hier nicht benutzt, BCC falls kleiner, BCS falls grösser-oder-gleich, BNE (= Not Equal) falls ungleich 0, BEQ (= EQual) falls gleich 0. Bei nicht erfüllt wird linear weiter gefahren, aber bei erfüllt wird zur Adresse nach dem ganzen Bxx Befehl eine 1 Byte 8bit Adressdifferenz vom zweiten Byte addiert, was -128..+127 Adressen an Sprungdistanz erlaubt. (Codes sind BPL 10, BMI 30, BVC 50, BVS 70, BCC 90, BCS B0, BNE D0, BEQ F0, also alles "ungerade" x0, wieder einfach zu merken.)

JMP: Ist gehe (= JuMP) ohne Bedingung zu einem anderen Ort im Programm, und führe ab dort linear aus. Hier stete als 2 Byte 16bit Adresse gegeben, keine 1Byte 8bit Adressdifferenz. (Code ist 4C.)

JSR: Ist gehe (= Jump) ohne Bedingung temporär (= SubRoutine) zu einem anderen Ort im Programm, und führe ab dort linear aus. Wieder als 2 Byte 16bit Adresse gegeben. Dies aber nur bis ein RTS (= ReTurn from Subroutine) hierhin zurückschickt. Zu merken wo "hierhin zurück" war und wieder sein soll, braucht es die 0100..00FF Stackpage als RAM, sonst versagt der JSR dies abzuspeichern und das RTS geht einfach irgendwo hin weitermachen. Die Limite auf eine Page ist die Folge eines weiteren 1 Byte grossen Hilfsregisters. (Diese Limite gilt nicht bei der 6800 oder 8080, welche beide dazu 2 Byte Hilfsregister haben.) (Codes sind JSR 20, RTS 60. Der JSR 20 kollidiert mit BIT 20 wenn mit +00 Konstante, und ist wohl der Grund warum diese Kombination nicht existiert. Warum JSR nicht den weit passenderen und unbenutzten 0C hat ist mir unbekannt.)

Alle anderen Befehle sind hier genug selten, oder gar unbenutzt, dass sie falls vorhanden vorzu beschrieben werden.

Mit den Codes wissen, wird obiges Demoprogrämmchen von Hexzahlen: A9 8D 20 EF FF A9 C1 20 EF FF 4C 1F FF, zu aussprechbarern und so auch merkbareren Befehlen: LDA #$8D; JSR $FFEF; LDA #$C1; JSR $FFEF; JMP $FF1F. Mit den Befehlen kennen, wird das weiter zu: LDA #$xx die Konstante xx in A laden, sowie JSR $Fxxx ein Unterprogramm bei $Fxxx aufrufen, und JMP $Fxxx wegspringen zu $Fxxx. Mit zudem der Apple 1 Hardware kennen, weiss man dass alle Adressen $Fxxx im PROM liegen, womit man sieht dass dies alles Systemaufrufe sind, mit den LDA Konstanten als Parameter.

(Wer mehr Details zur 6502 wissen will, kann das originale Handbuch anschauen.)

(Oder kompakter meine Zusammenfassung davon, mitsammt meinen Tabellen am Schluss. Zu unterst ist Zahlen zu Befehle übersetzen. Zur Repetition der Codes ist z.B. in obigem Demoprogrämmchen das erste Byte A9, zu Befehl übersetzen mit zuerst oben quer sehen dass +09 die zweite Reihe zweite Spalte ist (die damals benutze Papiervariante war in Querformat mit einer Reihe von 16 Spalten, sie ist für die Webausgabe "gefaltet" worden), dann links bis zu A0 herunter und dort zweite Reihe bis zweite Spalte rein, und man landet bei dem LDA #. Gleich darüber ist die nach logischen Kriterien sortierte Befehle zu Zahlen. Für z.B. obiges LDA # zu Hexzahl, zuerst zur zweiten Gruppe (Akkumulator Arithmetik) gehen, LDA ist die A1 Zeile und LDA # ist dritte Spalte (LDA s ist mit 1 Byte 8bit Adressen und LDA hl mit 2 Byte 16bit, alles mit ,X oder ,Y darin benutzen diese Hilfsregister), dann hinauf zu +08 für Adressmodus, zu A1 addiert gibt dies A9. Die Tabellen benutzen ist somit etwas aufwendig, aber nicht schwierig, und daher schnell auswendig lernbar, aber ebenso in LIST und Miniassembler einfach automatisierbar.)

(Man sieht in der zweiten Tabelle bei A0/A1/A2 und 80/81/82 auch obige x0=xxY x1=xxA x2=xxX und x3=nichts Logik, an den vier Blöcken, mit dem letzten leer. Man sieht aber auch bei C0/E0/C1 den Bruch mit CPX in der E0 statt C2 Zeile. Man sieht ebenso wie die +04 und +0C Spalten durchgehend s und hl Adressmodi sind. Man sieht aber auch den Bruch mit +08 als # nur bei x1, weil x0 und x2 auf +00 ausbrechen. Ebenso wie speichern in Konstante fehlt, bei den drei --- #. Aber auch wie 20 +00 statt BIT # sein, vom JSR weggenommen wird, trotz dass dieser wegen hl Modus eigentlich in die +0C Spalte gehört. Sowie einiges mehr an Irregulärem, alle davon mit ! markiert. Zudem sollten alle Codes mit - und 3 Buchstaben danach eigentlich den genannten Befehl beinhalten, der aber schlicht in diesem Modus fehlt. Generell ist dies ein ziemlich unsorgfältig designter Befehlssatz, im Vergleich zu 6800 und 8080, vermutlich weil überhastet gemacht, weil von 6800 Einfüuhrung via Firma verlassen bis zu 6502 Einfüuhrung nur ein Jahr dauerte.)

Systemsoftware Programmcode

Das ist der 6502 Prozessor im Apple 1. Nach dieser kurzen Einführung können wir nun den Programmcode vom Monitor lesen und analysieren. Dieser wurde im Apple I Handbuch abgedruckt, Seiten 5 und 6. Ich habe eine selbst erstellte etwas ausgebaut kommentierte Form davon als Listfile auf meiner Website, welche übersetzt die Basis vom Code hier ergab.

Ich gehe aber hier die Software durch, in der Reihenfolge wo Sachen benutzt werden, oder vor ihrer Nutzung als Grundlage aufbauen sinnvoll ist. Wer es linear haben will kann das Handbuch anschauen gehen, oder obiges auf der Website, diese aber beide in Englisch. Das ganze hier nennt man einen Code Walkthrough, bzw heute im Zeitalter wo Game Walkthroughs neuerdings "Let's Play!" heissen ist dies wohl ein "Let's Read Code!". Danach werdet ihr wissen wie man obige recht ordentliche Kommandozeile als Interface in nur 256 Bytes implementieren kann. Unter anderem mit an jedem Ort jedes vermeidbare Byte einsparen!

Aufstarten

Als erstes starten wir den Prozessor:

Adress Hexbytes   Programcode    Kommentar

FFF8   00 00      .DB $00 $00    leerer Platz, zwei Bytes
FFFA   00 0F      .DW $0F00      6502 nach NMI, in Apple 1 unbenutzt
FFFC   00 FF      .DW $FF00      6502 nach Einschalten/Reset, starte bei $FF00
FFFE   00 00      .DW $0000      6502 nach IRQ, in Apple 1 unbenutzt
    

Alle Programm Ausschnitte ab hier haben obiges Tabellenformat, mit Adress(e) + Hexbytes + Programcode + Kommentar. Gefolgt von einem Abschnitt wie diesem, der weiter kommentiert was und warum es geschieht. Die Zeilenkommentare reichen für Assembler Programmierer. Aber da die meisten Leute keinen oder wenig Assembler können, sind zudem die Abschnittkommentare vorhanden.

Die letzten 3 Zeilen definieren je eine 2-Byte 16bit Adresse (= ein Wort, das .DW bedeutet definiere Wort), welche von der 6502 verlangt werden. Die in $FFFC und $FFFD liegende Adresse ist zwingend, und muss auf den Anfang vom System seinem Programcode zeigen, sonst stürzt die 6502 gleich nach Einschalten (bzw Reset) ab! Hier steht der Anfang = $FF00, also das erste Byte des PROMs. Die Adressen in $FFFA und $FFFB sowie $FFFE und $FFFF braucht es falls man 2 Hardware Features NMI bzw IRQ nutzt, welche aber im Apple 1 unbenutzt sind. Ich gehe daher nicht weiter auf diese ein.

(Strikte kann man mit Lötpunkten neben der 6820 die Terminal Logik von IRQB/DSP an NMI und die Tastatur von IRQA/KYBD an IRQ legen. Aber die Monitor Software kann ohne Programm bei $0F00 bzw $0000 damit nicht umgehen, stürzt beim ersten Zeichen ausgeben bzw einkommen ab, bevor der Benutzer überhaupt Code dafür eingeben kann! Womit dieses Feature praktisch unbenutzbar ist, ausser man ersetzt die PROMs.)

Zudem hat es als erste Zeile 2 Bytes an leerem Platz füllen (das .DB bedeutet definiere Byte), weil der Monitor eigentlich nur 256-8 = 248 Bytes braucht! (Diese sind 22 mal 1 Byte und 80 mal 2 Byte und 22 mal 3 Byte Befehle, weil alle bei grösseren Programmen eher häufiger benutzten 3 Byte hier selten benutzt oder gar ganz abwesend sind.)

Treiber

Jedes System braucht Treiber. Der Monitor hat davon genau zwei, beide für den 6820. Die Tastatur/Eingabe wird nur an einem Ort benutzt, und befindet sich daher direkt dort eingebaut, um je einen JSR und RTS ihre 3 bzw 1 Bytes zu sparen. Wir werden den später zu sehen bekommen. Die Terminal/Ausgabe wird aber mehrmals benutzt, und ist daher als Unterprogramm vorhanden. Es befindet sich am Schluss, gerade vor obigem $FFF8:

ECHO:
FFEF   2C 12 D0   BIT $D012      6820 Port B, Test ob bereit Zeichen anzunehmen
FFF2   30 FB      BMI $FFEF      Bit7 = 1 ist nicht bereit, warten bis 0 wird
FFF4   8D 12 D0   STA $D012      6820 Port B, schreibe Zeichen zu Terminal
FFF7   60         RTS
    

Dieses Unterprogram heisst ECHO, und ist ab Adresse $FFEF. Es testet die 6820 auf Status ob bereit. Dies macht er mit dem BIT Test (Basiscode 20), mit einer 16bit Addresse (Adressmodus +0C = 2C), von $D012 (reversiert als $12 und $D0 gespeichert). Dann wartet er, wegen dem BMI (30) den BIT Test solange wiederholend wie das Terminal Minus=1=aktiv ist, also bis es zu Plus=0=bereit wird, mit dem FB als Adressdifferenz -5 um 5 Bytes zurück zu springen, von $FFF4 (nach dem BMI und -5 lesen) zu $FFEF (für nächstes BIT). Die STA (81+0C = 8D) und $D012 (12 D0) sind wie gehabt. Der RTS (60) ist geradeaus. (Das sollte als Repetition der Anwendung der Codes ausreichen, ab jetzt werden nur noch die Befehle angeschaut.)

Erstaunlicherweise testet dies Bit7 (Datenbit7) vom 6820 Ausgabedaten Register an $D012 und nicht etwa Bit7 (IRQB1) vom Ausgabestatus Register an $D013. Wozu extra eine Leitung vom externen Statuspin CB2 an den Datenpin PB7 (und somit Datenbit7) gezogen wurde! Was als Seiteneffekt die Ausgabe auf 7bit reduziert, während Eingabe und Prozessor und Speicher alle eigentlich 8bit sind. Der Grund dafür ist mir unbekannt. Ich spekuliere aber dass dies 3 Bytes spart, statt einmal nach dem Reset $D013 lesen zu müssen um IRQB1 zu löschen, weil Terminal bereit werdend würde dann dies wieder setzen.

(Beim Apple II ohne die ganze Terminal Logik, muss diese in Software nachgebildet werden. Diese braucht etwa 200 Bytes, statt obigen 9. Damit ist sie alleine für (2048-256)/200 = etwa 1/9 der ROM Platzzunahme dort zuständig! Dieses beinhaltet aber auch die scrollbare Fenster Funktionen.)

Hilfsfunktionen

Neben Treiber brauchen Systeme weitere Hilfsfunktionen. Der Monitor hat auch hiervon zwei, beide als Unterprogramme, die zweite den ersten wiederum selber zweimal benutzend. Der erste gibt eine Zahl 0..15 als Hexziffer aus:

PRHEX:
FFE5   29 0F      AND #$0F       lösche jegliche oberen Bits von Ziffer
FFE7   09 B0      ORA #$30+$80   nicht-ADC "ADD" von ASCII "0", mit Bit7 = 1
FFE9   C9 BA      CMP #$39+$80+1 ist Result <= "9", und so eine Dezimalziffer?
FFEB   90 02      BCC $FFEF        ja, gebe diese Ziffer aus ohne Korrektur
FFED   69 06      ADC #$41-$39-1 ASCII "A"-"9" = 7, aber ADC mit Carry=1 also 6
FFEF   !!! durchfallen in ECHO   statt JSR+RTS oder JMP
    

Dieses Unterprogram heisst PRHEX, und ist ab Adresse $FFE5. Das AND ist nur eine Vorsichtsmassnahme, falls die Zahl in A grösser als 15 ist (= maximale Hexziffer) wird sie abgeschnitten. Danach wäre eigentlich ein ADD #$30+$80 angebracht, was die 6502 aber nicht kann! Man könnte CLC plus ADC benutzen, was aber 3 Bytes braucht. Weil hier aber nur ein $0x + $B0 gerechnet wird, was keinen Übertrag rechnen muss, kann ein ORA das in 2 Bytes!

Das +$80 braucht es nur, weil die Apple 1 eigenartigerweise ASCII mit gesetztem Bit7 erzeugt (der Apple II macht dies auch so). (Dies trotz dass obige 6820 Ausgabe PB7 Verdrahtung das obere Bit wieder wegwirft! Es mit der Eingabe konsistent machen ist auch fraglich, da diese 8bit ist, und nur von der Tastatur her Bit7=1 gegeben hat, weil diese so verdrahtet verlangt wird, statt auf Bit7=0.)

Die Ziffern 0..9 sind so bereits gegeben, mit dem CMP auf <= "9" (strike auf < "9"+1) und BCC geht es in diesem Fall weiter zu $FFEF. Für A..F müssen mit "A"-"9" = $41-$39 die 7 Zeichen :;<=>? und @ zwischen "9" und "A" übersprungen werden. Weil der BCC bei Carry=0 gesprungen ist, somit beim ADC ein Carry=1 gegeben ist, muss die 7 auf 6 zu korrigiert werden.

Danach muss das Zeichen ausgegeben werden. Um wieder 3+1 Bytes Platz zu sparen ist kein JSR ECHO gefolgt von RTS, auch nicht ein nur 3 Bytes JMP ECHO, sondern dieses Unterprogram wurde einfach direkt vor ECHO hingestellt, so gleich in dieses durchfallend.

Der zweite Hilfsfunktionen gibt ein ganzes Byte als zwei Hexziffern aus:

PRBYTE:
FFDC   48         PHA            speichere Byte für rechte/LSB Hexziffer
FFDD   4A         LSR A          schiebe linke/MSB Hexziffer nach rechts/LSB
FFDE   4A         LSR A            braucht 4 mal 1 bit schieben
FFDF   4A         LSR A
FFE0   4A         LSR A
FFE1   20 E5 FF   JSR $FFE5      gebe linke/MSB Hexziffer mit PRHEX aus
FFE4   68         PLA            hole Byte für rechte/LSB Hexziffer
FFE5   !!! durchfallen in PRHEX  gebe rechte/LSB Hexziffer mit PRHEX aus
    

Dieses Unterprogram heisst PRBYTE, und ist ab Adresse $FFDC. Das PHA (und sein Gegenstück PLA am Schluss) speichern Datenbytes am (bzw holen sie vom) selbigen Ort in der Stackpage wo auch JSR und RTS ihre "hierhin zurück" Adressen speichern bzw holen. LSR ist soweit hier relevant einfach eine Division durch 2, mit 4 mal gibt es durch 16 teilen, also um eine Hexadezimalstelle von links nach rechts schieben, was die rechte Ziffer verdrängt.

Ein Byte von z.B. 4A wird mit dem /16 zu 04, das A geht als Unterlauf verloren. Der JSR benutzt PRHEX um die linke/erste Ziffer auszugeben, bis dem ECHO sein RTS hierhin zurück schickt. Dann holt PLA das Byte zurück, und fällt wieder direkt in PRHEX durch. Dessen AND Vorsichtsmassnahme schneidet die bereits ausgegebene linke Hexziffer ab. Obiges 4A wird so zu 0A. Und ECHO gibt somit nur noch die rechte/zweite Ziffer aus. Strikte könnte das AND auch nur Teil vom PRBYTE sein, aber es wäre am gleichen Ort, nur der Name PRHEX bei $FFE7 statt $FFE5, also wird es zu PRHEX gezählt, weil universeller und kostet nichts.

Konfigurieren

Jetzt wo alle Hilfsfunktionen gegeben sind, 9+10+9 = 28 Bytes davon, können wir das eigentliche Hauptprogramm anschauen, mit noch 256-8-28 = 220 Bytes, von $FF00 bis $FFDB. Es fängt an, wie in $FFFC und $FFFD gegeben, bei $FF00, mit den 6502 und die 6820 konfigurieren:

RESET:
FF00   D8         CLD            6502 ausschalten Dezimalarithmetic Modus
FF01   58         CLI            6502 ausschalten Interruptsperre
FF02   A0 7F      LDY #$7F       6820 Pin Richtungen, Pins0..6 AUS, Pin7 EIN
FF04   8C 12 D0   STY $D012      6820 Port B so setzen, Port A bleibt #$00 EIN
FF07   A9 A7      LDA #$A7       6820 Steuerwort, CA1/CB1 mit Status verwalten
FF09   8D 11 D0   STA $D011      6820 Port A so setzen, Eingabe mit Status
FF0C   8D 13 D0   STA $D013      6820 Port B so setzen, Ausgabe mit Status
    

Die CLD und CLI sind Prozessor Konfigurationsbits, um zwei im Apple 1 unbenutzte Features abzuschalten (CLD) bzw nicht zu blockieren (CLI). Ich gehe wieder nicht weiter auf sie ein. Man beachte hier noch, dass der ganze Monitor keinen TXS Befehl beinhaltet, womit das S Register nicht konfiguriert wird, also JSR und RTS sowie PHA und PLA zufällig irgendwo in der Stackpage benutzen werden.

Die LDA STA STA sind normales Konstante in Akkumulator laden, und dann weiter zur 6820 speichern. Das weil direkt nicht geht, weil die 6502 ja eine 1-Adress Logik hat, die Rechnung V2=V1 daher zu Temp=V1; V1=Temp wird. Die LDY STY verwenden genau selbiges, lassen aber das #$7F in Y, statt es bei einem folgenden LDA zu verlieren, wenn dort zuerst LDA STA benutzt worden wären.

Das #$7F in $D012 sorgt genau dafür, dass Pin PB7 eine Eingabe bleibt, den Status von Pin CB2 lesen kann. Das #$A7 ist eine 6820 spezifische Konfiguration. Ich gehe ebenso nicht auf diesen ein, ausser hinweisen dass selbiges in beide Register $D011 und $D013 geschrieben wird, weil bei beiden Ports der Status verfolgen Modus einschaltet werden soll.

(Mit hier #$A6 setzen wäre der Absturz bei IRQB/DSP oder IRQA/KYBD mit Lötpunkte an NMI bzw IRQ legen verhindert worden. Weil damit wären diese inaktiv, bis der Benutzer passenden Code eingegeben hat, der dann auch #$A7 setzt um sie zu aktivieren. Weshalb so mit #$A7 man die NMI und IRQ nur nutzen kann, wenn man die PROMs durch andere ersetzt. Ich erachte das #$A7 hier dementsprechend als Designbug.)

(Wer mehr Details zur 6820 wissen will, kann das originale 6821 Datenblatt anschauen.)

Zeileneditor

Danach ist der Rechner fertig betriebsbereit, gebootet, nach nur $FF0F-$FF00 = 15 Bytes! Trotz nur 1.0227MHz 8bit Prozessor bootet er in unter 1ms! Ab jetzt werden nur noch Tasten geholt und als Kommandos ausgewertet. Dabei kommt im Monitor zuerst die Kommandozeileneditor Auswertung und dann erst Tasten holen, weil es so angeordnet leicht kompakter ist. Dazu muss aber der Rechnerstart durch die ganze Auswertung hindurchfallen, was es komplexer macht.

Ich überspringe daher zuerst mal die Auswertung in $FF0F bis $FF28, und zeige als erstes die Tasten holen, und baue dann darauf den Resten davor auf:

NEXTCHAR:
FF29   AD 11 D0   LDA $D011      6820 Port A Status, Test ob bereit mit Eingabe
FF2C   10 FB      BPL $FF29      Bit7 = 0 ist nicht bereit, warten bis 1 wird
FF2E   AD 10 D0   LDA $D010      6820 Port A, lese Zeichen von Tastatur
FF31   99 00 02   STA $0200,Y    zu Zeilenbuffer, $0200..$027F, Y = Position
FF34   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
FF37   C9 8D      CMP #$0D+$80   ist Taste ASCII Carriage Return, mit Bit7 = 1
FF39   D0 D4      BNE $FF0F        nein, weiter Zeilenbuffer editieren
    

Die ersten 3 Befehle von NEXTCHAR sind genau das Gegenstück zu ECHO, der direkt hier eingebaute zweite Treiber, für die Tastatur/Eingabe. Wieder Status testen, diesmal den echten vom Eingabestatus Register an $D011. Ausgabe war warten solange Terminal Minus=1=aktiv bis Plus=0=bereit, hier ist Eingabe warten solange Tastatur Plus=0=inaktiv ist, also bis es zu Minus=1=bereit wird, also ist mit BPL den LDA wiederholend. Warum LDA benutzen statt konsistenter BIT als Test ist mir unbekannt. Dann folgt Taste vom Eingabedaten Register an $D010 abholen. (Apple II verwendet das passendere BIT. Auch ist dort dieser Treiber separat, mit JSR und RTS. Er heisst dann KEYIN. Dazu kommt erweitert RDKEY, welches zuerst den Cursor anzeigt, was der KEYIN danach stets beseitigt.)

Danach wird die Taste mit STA gespeichert. Dazu hat es von $0200 bis $027F einen maximal 128 Bytes bzw Tasten grossen Buffer (Zwischenspeicher) für die Kommandozeile. Das $0200,Y beim STA Befehl bedeutet als Adressmodus den 2Byte 16bit als Anfangsadresse $0200 nehmen plus die 8bit als Position/Index von Hilfsregister Y addieren, hier von 0..127 gehend. Das ist eines der 5 anderen Adressmodi. Die Einstellung von Y kommt noch, sie ist im übersprungenen Code.

Der JSR $FFEF geht zu ECHO, dem Terminal/Ausgabe Treiber, der das getippte Zeichen auf den Bildschirm weitergibt. Genau daher heisst der Treiber auch ECHO, weil er dazu dient, das was herein kommt wieder hinaus zu geben. Dabei wird ein "_" für Backspace/Backdelete wie jedes andere Zeichen ausgegeben. Ein Escape für Abbruch ebenso, aber wie jedes Steuerzeichen ausser Carriage Return wird es von der Terminalllogik nicht angezeigt. Anderseits gibt ECHO auch anderes aus, was nicht herein kam, wäre daher mit PRCHAR besser benamst. (Apple II ersetzt daher den Namen mit COUT, für CharacterOUT.)

Am Schluss wird auf Taste = ASCII Carriage Return getestet, also auf das Enter am Ende der Kommandozeile. Falls gleich diesem wird der BNE durchfallen, ende editieren, gehe auswerten. Mit ungleich wird BNE genommen und ist editieren noch nicht zu ende, hinauf zu $FF0F, also genau nach dem Reset, zu dem was wir übersprungen haben, und jetzt nach und nach anschauen gehen:

NOTCR:
FF0F   C9 DF      CMP #$5F+$80   ist Taste ASCII "_", mit Bit7 = 1
FF11   F0 13      BEQ $FF26        ja, letztes Zeichen vom Buffer vergessen


BACKSPACE:
FF26   88         DEY            Backspace: reduziere Anzahl Zeichen in Y
FF27   30 F6      BMI $FF1F      ist Y < 0, aus Zeilenbuffer gefallen, abbruch
FF29   !!! weiter bei NEXTCHAR   gleich nächste Taste holen


GETLINE:
FF1F   A9 8D      LDA #$0D+$80   Zeilenanfang: ASCII Carriage Return neue Zeile
FF21   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
FF24   A0 01      LDY #0+1       Anfang Zeilenbuffer, Y = 0, +1 kompensiere DEY
FF26   !!! weiter bei BACKSPACE  jetzt durch Backspace weiter
    

Der Name NOTCR ist genau das: Alles ausser Carriage Return (CR) landet hier. Erster Test ist auf Taste gleich "_", also Backspace/Backdelete, die Korrekturtaste. Falls es diese war, geht es mit BEQ zu $FF26. Wo das letzte Zeichen "vergessen" wird durch DEY (Y = Y-1) rechnen. Das Zeichen bleibt im Buffer, wird einfach durch das nächte getippte Zeichen überschrieben werden. Es hat keine ECHO Ausgabe, da die Terminal Logik kein löschen kann! und das "_" wurde ja bereits ausgegeben.

Das BMI testet auf Y negativ, also falls vorher Y = 0, nun mit dem DEY zu -1 geworden, weil schon davor nichts mehr im Buffer drin war. Falls dies zutrifft wird zu $FF1F gegangen, und dort ein Carriage Return mit ECHO ausgegeben, als neue Zeile um dem Benutzer den Fehler sichtbar zu machen, dass er nicht mehr in der alten Zeile am editieren ist. Wieder ist es ECHO, trotz dass solche Ausgabe eben kein ECHO mehr ist! Schliesslich wird mit LDY das Y auf 1 gestellt, nicht auf 0, weil sonst das an $FF26 nachfolgende DEY es zu -1 machen würde. So etwas nennt man vorkompensieren. Es kostet 2 weniger Bytes als den BACKSPACE Code überspringen.

War die Taste kein Backspace gehen die Tests es weiter mit:

       *** weiter in NOTCR
FF13   C9 9B      CMP #$1B+$80   ist Taste ASCII Escape, mit Bit7 = 1
FF15   F0 03      BEQ $FF1A        ja, Zeile abbrechen, "\" und Y = 0


ESCAPE:
FF1A   A9 DC      LDA #$5C+$80   Zeilenabbruch: ASCII "\" um dies zu zeigen
FF1C   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
FF1F   !!! weiter bei GETLINE    jetzt durch Zeilenanfang und Backspace weiter
    

Zweiter Test ist auf Escape, also Kommadozeile editieren abbrechen Taste. Falls es diese war, geht es mit BEQ zu $FF1A. Dieses gibt nur ein \ als Abbruchbestätigung aus mit ECHO, weil Escape ja nicht sichtbar ausgegeben wird, gefolgt von ab $FF1F neue Zeile anfangen wie gehabt. Obiger Y = -1 Fall hat einfach diesen Fall mit ausgenutzt.

Ansonsten gilt für alle anderen Zeichen:

       *** weiter in NOTCR
FF17   C8         INY            nächste Position in Buffer
FF18   10 0F      BPL $FF29        ist Y < $80, noch Platz im Buffer, weiter
FF1A   !!! weiter bei ESCAPE     jetzt Zeilenabbruch mit ASCII "\" ausgeben
    

Ist die Taste weder Backspace noch Escape wird die Zeichenzahl mit Y = Y+1 gerechnet. Damit wird auch beim nächsten STA $0200,Y der nächste Platz im Buffer benutzt. Dies aber nur falls Y positiv bleibt, also im Bereich 0..127 ist, und somit noch im Buffer. Auf was der BPL testet. Versagt dies weil zu 128 geworden fällt er zum obigen ESCAPE durch, für Abbruch, etwas gröber als bei von 0 zu -1 werden, wo nur GETLINE ist, für neue Zeile.

Nach all diesem kann man nun sehen, wie alles zusammenpasst, und was nach Reset damit passiert, wenn ich alle Editor Codeteile nun in der ROM Reihenfolge wieder zusammensetze:

NOTCR:
FF0F   C9 DF      CMP #$5F+$80   ist Taste ASCII "_", mit Bit7 = 1
FF11   F0 13      BEQ $FF26        ja, letztes Zeichen vom Buffer vergessen
FF13   C9 9B      CMP #$1B+$80   ist Taste ASCII Escape, mit Bit7 = 1
FF15   F0 03      BEQ $FF1A        ja, Zeile abbrechen, "\" und Y = 0
FF17   C8         INY             nächste Position in Buffer, Reset #$7F
FF18   10 0F      BPL $FF29       ist Y < $80, noch Platz im Buffer, weiter

ESCAPE:
FF1A   A9 DC      LDA #$5C+$80   Zeilenabbruch: ASCII "\" um dies zu zeigen
FF1C   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO

GETLINE:
FF1F   A9 8D      LDA #$0D+$80   Zeilenanfang: ASCII Carriage Return neue Zeile
FF21   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
FF24   A0 01      LDY #0+1       Anfang Zeilenbuffer, Y = 0, +1 kompensiere DEY

BACKSPACE:
FF26   88         DEY            Backspace: reduziere Anzahl Zeichen in Y
FF27   30 F6      BMI $FF1F      ist Y < 0, aus Zeilenbuffer gefallen, abbruch

NEXTCHAR:
FF29   AD 11 D0   LDA $D011      6820 Port A Status, Test ob bereit mit Eingabe
FF2C   10 FB      BPL $FF29      Bit7 = 0 ist nicht bereit, warten bis 1 wird
FF2E   AD 10 D0   LDA $D010      6820 Port A, lese Zeichen von Tastatur
FF31   99 00 02   STA $0200,Y    zu Zeilenbuffer, $0200..$027F, Y = Position
FF34   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
FF37   C9 8D      CMP #$0D+$80   ist Taste ASCII Carriage Return, mit Bit7 = 1
FF39   D0 D4      BNE $FF0F        nein, weiter Zeilenbuffer editieren
    

Zeichen aufnehmen ist ab NEXTCHAR, dann ausser Carriage Return zu NOTCR. Falls die Taste Backspace/Backdelete war, dann weitere Tests und INY und ESCAPE und GETLINE überspringen zu BACKSPACE, mit dann nur falls aus Buffer vorne raus doch zu GETLINE, sonst wieder in NEXTCHAR. Falls die Taste Escape war, dann nur INY überspringen zu ESCAPE und dann GETLINE, mit durch BACKSPACE hindurchfallen. Ansonsten INY mit dann falls aus Buffer hinten raus zu ESCAPE, sonst wieder zu NEXTCHAR. Sowas nennt man Spaghetticode, weil ohne Blockstruktur hin und her gesprungen wird. Wobei es aber trotzdem geordnete Spaghetti sind, weil jedes Codefragment darin einem spezifischen Zustand vom Editor entspricht, welcher zwischen den Zuständen ausführen herumspringt, dabei in jedem passendes abarbeiten bevor er in den nächsten Zustand übergeht. Was alles als eine Statemachine bekannt ist (von State = Zustand).

Nach dem konfigurieren von Prozessor und 6820 kommt es oben bei NOTCR herein. Dabei ist immer noch A = $A7, von der 6820 Konfiguration her. Somit ist bei NOTCR weder $DF Backspace noch $9B Escape, also greift keine der BEQ. Es wird also trotz keine Taste abholen das INY gemacht! Weil aber Y vom 6820 Port B Pins einstellen mit LDY STY statt LDA STA immer noch $7F = 127 ist, wird es jetzt zu 128, und der BPL fällt ebenfalls durch. Womit automatisch der volle "zu grosse Zeile" Abbruch kommt. Somit kommt auch das Abbruch \ als Laufendbestätigung, gefolgt von Neuzeile, sowie das Y = 1 plus DEY mit davon kein BMI, um die Kommandozeile erstmals vorzubereiten, gefolgt von auf Eingabe warten.

Damit wurde auch die maximale Kommandozeile auf 128 Zeichen definiert, statt etwa 256 (was Y = 0..255 eigentlich erlauben würde, mit BEQ für dem "zu gross" Test), weil deren letzte Position 127 zum Pinkonfiguration Muster $7F passte, und so 2 Bytes an LDY sparte, bzw eher 2 Bytes an BNE um direkt zu ESCAPE zu springen! Warum nicht einfach die NOTCR Tests nach der Eingabe stellen und an $FF0F mit ESCAPE anfangen, ist mir unbekannt, vermutlich auch mehr Bytes. Nur die beiden CMP und BEQ nach dem Zeichen ausgeben wäre sicher keine Differenz, und der A Inhalt wäre so irrelevant. Aber die INY und BPL vor den CMP #$0D+$80 und BNE liegend könnte in Konflikt kommen, was einen BNE seine 2 Bytes mehr braucht, oder ohne dies Y weiterhin doppelt nutzen muss.

(Apple II hat ohne diesen Trick maximal 255 Zeichen Kommandozeile. Ebenso ist der ganze Kommandozeileneditor eine mit JSR und RTS benutzbare Hilfsfunktion, namens GETLN. Dieses zeigt auch den Prompt an, der je nach was das aufrufende Program haben will, Monitor *, Miniassembler !, Integer Basic <, Applesoft Basic ], Benutzeringaben ?.)

Kommandozeichen auswerten

Danach ist die Kommandozeile fertig editiert, nach nur $FF3B-$FF0F = 44 Bytes. Was geschieht nun nach einem Carriage Return? Dann geht es nach dem BNE weiter zu $FF8B, die Kommandozeile auswerten, zuerst mit dazu etwas Vorbereitungen:

       *** weiter nach NEXTCHAR
FF3B   A0 FF      LDY #0-1       Anfang Zeilenbuffer, Y = 0, -1 kompensiere INY
FF3D   A9 00      LDA #0         A = 0 für X setzen und anfangs Hexmodus
FF3F   AA         TAX            X = A für anfangs Hexzahl (später)

SETSTOR:
FF40   0A         ASL A          kein Effect bei A = 0, 2*$BA=$174=$74 bei ":"

SETMODE:
FF41   85 2B      STA $2B        Hexzahl verarbeiten Modus, 0 = Ausgabe Adresse
    

Bisher war in Y die Anzahl Zeichen und deren Position im Buffer eingeben. Nachdem das Carriage Return gespeichert wurde, wird Y aber frei, ist jetzt die Position für Zeichen auswerten, also wieder ab 0. Was aber wegen dem INY in $FF43 mit -1 vorkompensiert wird. A wird 0, mit dem bald folgenden ASL bleibt es immer noch 0, und wird abgespeichert in $2B in der Zeropage. Damit wird später nach Einlesen einer Hexzahl entschieden was damit zu machen ist. Mit 0 wird diese als Adresse angeschaut, und sie als Position gesetzt und mit ihren Inhalt ausgeben. Das TAX ist nur um bei dieser Gelegenheit in 1 Byte das X mit 0 zu löschen, statt es später mit LDX #0 in 2 Bytes zu machen. X wird per Konvention im Monitor immer auf 0 gelassen, oder falls anderst benutzt wieder zu 0 restauriert.

Dann muss ein Zeichen geholt und ausgewertet werden:

BLKSKIP:
FF43   C8         INY            nächstes Zeichen, -1 wird zu 0 = erstes

NEXTITEM:
FF44   B9 00 02   LDA $0200,Y    von Zeilenbuffer, $0200..$027F, Y = Position
FF47   C9 8D      CMP #$0D+$80   ist Taste ASCII Carriage Return, mit Bit7 = 1
FF49   F0 D4      BEQ $FF1F        ja, Carriage Return ausgeben, mit GETLINE
FF4B   C9 AE      CMP #$2E+$80   ist Taste ASCII ".", mit Bit7 = 1
FF4D   90 F4      BCC $FF43        kleiner, vielleicht Leerz, ignorier, BLKSKIP
FF4F   F0 F0      BEQ $FF41        ja, zu SETMODE, mit Hex $AE = Bereich ausgeb
FF51   C9 BA      CMP #$3A+$80   ist Taste ASCII ":", mit Bit7 = 1
FF53   F0 EB      BEQ $FF40        ja, zu SETSTOR, mit 2*$BA=$74 = schreiben
FF55   C9 D2      CMP #$52+$80   ist Taste ASCII "R", mit Bit7 = 1
FF57   F0 3B      BEQ $FF94        ja, starte Programm an Adresse
    

Bisher hatten wir beim Editieren STA $0200,Y und dann INY, mit Y anfangs 0, was Postincrement genannt wird. Hier ist es INY und dann LDA $0200,Y, mit Y anfangs -1, was Präincrement genannt wird. Dies wirkt fast gleich, aber siehe weiter unten für zwei gewollte Seiteneffekte. Der erste Test, auf ein Carriage Return finden bedeutet die Zeile ist fertig abgearbeitet, gehe neue holen, daher mit BEQ wieder ab nach $FF1F GETLINE, was wir bereits kennen.

Eine Hexzahl einfach so ist eine Adresse, aber nach "." eine Endadresse und nach ":" eine Dateneingabe. Hier wird daher auf "." bzw ":" getestet und dieses vermerkt, durch mit erstem BEQ zu $FF41 hinauf, direkt mit "." = $AE im STA, oder zweitem zu $FF40 hinauf, das ASL und dann STA. Also wird das Kommandozeichen zur neuen Hexzahl Modusnummer, statt normal auf 0 gesetzt. ASL ist eine Multiplikation mal 2, hier wird es benutzt um per Seiteneffekt aus ":" = $BA mit *2 ein $174 zu machen, von dem aber wegen 8bit nur die $74 abgespeichert werden. Wonach gilt bei Hexzahl: Adressmodus = 0, Endadressmodus = $AE, Schreibmodus = $74. Auch dies ist eine Form von Statemachine, aber mit den Zustand in einer Variable gehalten statt direkt im angesprungenen Codefragment, weil zuerst vom Zustand unabhängiger Code dran sein wird, und erst danach der Zustand relevant wird.

Das eine BCC nach dem "." Test sorgt mit Sprung nach $FF43 dafür, dass alle Zeichen mit Codes unterhalb von "." einfach fallengelassen werden, durch mit nächstem Zeichen weitermachen. Das beinhaltet gewollt die Leerzeichen als Adressen/Kommandos bzw Datenbytes Trenner, aber ebenso werden alle !"#$%&'()*+,- als "Leerzeichen" behandelt, ein undokumentiertes Feature! Dies vermeiden würde einen expliziten CMP #$20+$80 plus BEQ statt dem BCC brauchen, also 2 Bytes mehr.

Alle diese Varianten nutzen erneut das eine INY vor dem LDA, was mehrere solche Bytes einspart, erster gewollter Seiteneffekt! Auch das ASL vor dem Hexzahl Modus STA spart 2 Bytes, weil sonst nach dem ":" Test ein BNE notwendig wäre um bei nicht-":" ein ASL hier zu überspringen. Oben hatte ASL bei Modus 0 keinen Effekt, konnte einfach durchlaufen werden.

Weiter bedeutet ein "R" als Kommando, dass ein Programm ab Adresse ausgeführt werden soll. Da "R" gewisse Vorarbeiten braucht, welche bei Adresse eingeben Befehl bereits geschahen, lasse ich den "R" Fall an $FF94 weiter verfolgen jetzt weg, und hole ihn ganz am Schluss nach. Damit sind wir bereits alle Kommandozeichen durch.

Hexzahl konvertieren

Ist es kein Zeile fertig oder Kommandozeichen kann nur noch eine Hexzahl dran sein. Wieder zuerst etwas Vorbereitungen um solche zu konvertieren:

       *** weiter in NEXTITEM
FF59   86 28      STX $28        Hexzahl untere Hälfte = 0
FF5B   86 29      STX $29        Hexzahl obere Hälfte = 0
FF5D   84 2A      STY $2A        merke Anfangsposition Y der Zahl im Buffer
    

Zuerst wird mit beiden STX das X = 0 von $FF3F oben in $28 und $29 gespeichert, 2 Bytes welche die zu entstehende maximal 16bit grosse Hexzahl aufnehmen werden. Eine ziffernlose Zahl hat damit einfach den Wert 0. Damit geschieht automatisch auch die Erweiterung von 1..3 ziffrigen Zahlen mit vorangestellten Nullziffern auf 4 ziffrig. Mit dem STY wird die aktuelle Position in der Kommandozeile gemerkt, um später zu testen ob überhaupt Ziffern verdaut wurden.

Dann wird auf gültige Ziffern getestet:

NEXTHEX:
FF5F   B9 00 02   LDA $0200,Y    von Zeilenbuffer, $0200..$027F, Y = Position
FF62   49 B0      EOR #$30+$80   nicht-SBC "SUB" von ASCII "0", mit Bit7 = 1
FF64   C9 0A      CMP #9+1       ist Resultat <= 9, und so eine Dezimalziffer?
FF66   90 06      BCC $FF6E        ja, addiere diese Ziffer ohne Korrektur
FF68   69 88      ADC #$FA-$71-1 falls "A".."F" war $C1..$C6, EOR mach $71..$76
                                   schiebe $71.. zu $FA.., aber ADC mit Carry=1
FF6A   C9 FA      CMP #$FA       ist Resultat < $FA..$FF, so nicht Ziffern A..F
FF6C   90 11      BCC $FF7F        ja, keine Hexziffer, fertig Zahl Konvertiert
    

LDA holt erstes/nächstes Zeichen von der Zahl. Weil INY vor dem obigen LDA war, und nicht danach, ist Y unverändert, die erste Ziffer hier holt einfach wieder die gleiche Ziffer, zweiter gewollter Seiteneffekt! Das EOR ist genau Gegenstück zum ORA in PRHEX, wieder statt 3 Bytes SED und SBC nur 2 Bytes EOR. Auch der Test auf <= 9 (strikte < 9+1) ist das Gegenstück zu dort. Ebenso mit BCC weiter zu $FF6E falls 0..9.

Auch hier wird mit einem ADC korrigiert, aber weit eigenartiger. PRHEX hat nur 7 Zeichen übersprungen. Hier werden dagegen die Ziffern A..F zu 250..255 gemacht, weil danach diese später noch mit -240 abschneiden zu 10..15 gewandelt werden. Wieder gilt dass Carry=1 ist, also muss die Konstante um -1 korrigiert werden. Ist die Ziffer nun unter 250, ist es damit kein A..F. Das weil auch alles G..oberstes nun zwar über 255 wären, aber damit nach Verlust von 256 wegen 8bit Prozessor seinem Zahlenbereichsüberlauf, auch unter 250 fallen. Genau daher wurden die A..F dort hinauf verschoben! War es keine Ziffer bricht der BCC aus nach $FF7F. Dies ist eindeutig das eigenartigste Stück Code im ganzen Monitor!

Haben wir nun eine Ziffer, wird diese zur entstehenden Hexzahl addiert, was das Gegenstück zu PRBYTE seinem zerlegen ist, allerdings hier mit einer 16bit Zahl, nicht nur 8bit Zeichen. Hier muss es, weil spätere Ziffern eine niedere Wertigkeit haben, nach z.B. bereits eine 12 vorhanden sein eine weitere 3 daraus 120+3 machen. Weshalb die bestehende Hexzahl mit *16 nach links verschoben werden muss und dann die neue Ziffer addiert werden:

DIG:
FF6E   0A         ASL A          schiebe rechte/LSB Hexziffer nach links/MSB
FF6F   0A         ASL A            braucht 4 mal 1 bit schieben
FF70   0A         ASL A            löscht links/MSB $F0 von A..F Ziffern
FF71   0A         ASL A
FF72   A2 04      LDX #4         starte Schleife, für 4 Bits pro Hexziffer

HEXSHIFT:
FF74   0A         ASL A
FF75   26 28      ROL $28        Hexzahl untere Hälfte, neu = alt *16 + A
FF77   26 29      ROL $29        Hexzahl obere Hälfte, neu = alt *16 + A
FF79   CA         DEX
FF7A   D0 F8      BNE $FF74      Schleife 4 mal ab HEXSHIFT
FF7C   C8         INY            Ziffer wurde verarbeitet, nächste Ziffer
FF7D   D0 E0      BNE $FF5F      Schleife immer, nächstes Zeichen, NEXTHEX
    

Die 4 ASL entsprechen genau den 4 LSR vom PRBYTE, nur eben *2 statt /2 Gegenstücke. Danach steht die Ziffer in der linken Hexadezimalstelle von A bereit. War die Ziffer 0..9 wurden die Bytes 00..09 vom EOR nun geschoben zu 00..90, die linke 0 ging verloren. War die Ziffer A..F wurden nun die Bytes FA..FF vom ADC geschoben zu A0..F0, die linke F wurde so abgeschnitten, was auch gleich das erwähnte -240 ergibt!

Das LDX sorgt nur dafür, dass alles nach HEXSHIFT 4 mal stattfindet. Dessen ASL *2 schiebt stets das oberste Bit der neuen Ziffer aus A hinaus, ins Carry, einem 1bit Hilfsregister welcher bei Rechnungen der Sorte A = A (0..255) + Daten (0..255) + Carry (0..1) = 0..511, bei allen Ergebnissen oberhalb von A = 0..255, wo sonst 256 verloren gehen würden, auf 1 gesetzt wird, womit es zum neunten Bit wird. Dieser wird von ADC (und SBC) sowie ASL (und LSR) gesetzt, und kann neben von ADC (und SBC) auch von ROL (und ROR) ausgewertet werden. Wobei ROL genau das selbige macht wie ASL, nur eben neben dem *2 noch das Carry 0 oder 1 dazu addieren. Womit die ASL ROL ROL Folge die ganze Gruppe A,$28,$29 um 1 Bit verschiebt, also 3*8=24bit Arithmetik macht, mit 16alt+4neu=20bit Nutzdaten darin.

Das DEX macht X = X-1, und BNE tut bei solange nicht X = 0 ab $FF74 wiederholen, was nach 4 mal -1 dann nicht mehr geschieht, und somit eine typische Abzählschleife ergibt. Insgesammt werden so alle 4 linken Hexziffer Bits aus A nach Carry und dann in $28 geschoben, dessen untern 4 nach oben, dessen oberen 4 nach Carry und in $29, dessen untern 4 nach oben, dessen oberen 4 gehen verloren. Womit auch zuviele Hexzahlenbits "vorne" herausgeschoben werden. Genau daher kann man nach Fehlern in Adresse (oder Daten) tippen einfach 4 (bzw 2) weitere richtige Ziffern eingeben, und nur diese bleiben erhalten, wieder ein Seiteneffekt. Das ganze sieht als Bits so aus:

Eine Zahl 1248 eingeben wird zu

erste Ziffer 1 in A
   $29       C       $28       C        A             X
0000'0000 <- ? <- 0000'0000 <- ? <- 0001'0000  |  0000'0100

4 mal ASL ROL ROL
   ROL               ROL               ASL           DEX
0000'0000 <- 0 <- 0000'0000 <- 0 <- 0010'0000  |  0000'0011
0000'0000 <- 0 <- 0000'0000 <- 0 <- 0100'0000  |  0000'0010
0000'0000 <- 0 <- 0000'0000 <- 0 <- 1000'0000  |  0000'0001
0000'0000 <- 0 <- 0000'0001 <- 1 <- 0000'0000  |  0000'0000

zweite Ziffer 2 in A
0000'0000 <- ? <- 0000'0001 <- ? <- 0010'0000  |  0000'0100
4 mal ASL ROL ROL
0000'0000 <- 0 <- 0001'0010 <- 0 <- 0000'0000  |  0000'0000

dritte Ziffer 4
0000'0001 <- 1 <- 0010'0100 <- 0 <- 0000'0000  |  0000'0000

vierte Ziffer 8
0001'0010 <- 1 <- 0100'1000 <- 0 <- 0000'0000  |  0000'0000
    

Der INY geht wie gehabt zum nächsten Zeichen weiter, und wird daher mindestens 1 und maximal 127 sein. Daher wird der zweite BNE immer wiederholen, zu $FF5F hinauf gehen und nächstes Zeichen mit LDA holen und auswerten ob Ziffer. Damit ist auch dieses INY fast direkt vor einem LDA, wenn auch nichtlinear angeordnet. Das BNE so ausgenutzt braucht nur 2 Bytes, statt einem 3 Byte JMP welches immer springt. (Die 6800 hat ein BRA das in 2 Bytes immer springt. 8080 kennt dagegen nur 3Byte 16bit Adresse Sprungbefehle, für bedingt und immer springend.)

Fehler erkennen

Einziger Weg aus der Zahlenverarbeitung heraus ist somit das BCC $FF7F in $FF6C bei auffinden einer Nicht-Ziffer. Danach folgen Tests was mit der entstandenen Hexzahl anzustellen ist:

NOTHEX:
FF7F   C4 2A      CPY $2A        vergleiche Y mit Anfangsposition im Buffer
FF81   F0 97      BEQ $FF1A      keine Ziffern, keine Zahl, abbrech, mit ESCAPE
    

Der Name NOTHEX ist wie NOTCR genau das. Das erste nicht Hexziffer Zeichen landet hier. Das CPY vergleicht das aktuelle Y mit dem einst bei $FF5D gemerkten Wert, bevor eine Zahl konvertieren versucht wurde. Sind beide gleich, war gar keine Ziffer dort, es wurde sofort hierher gesprungen. Also war es weder Zeile fertig, noch ein bekanntens Kommandozeichen, noch ein Leerzeichen, noch eine Ziffer, und muss folglich ein Tippfehler gewesen sein. Also wird mit dem BEQ abgebrochen, wie nach einem Zeilenbuffer voll oder Escape beim editieren, ab nach $FF1A, ESCAPE, mit dessen \ als Abbruchbestätigung, gefolgt von neuem Zeilenanfang.

Da bereits die ganze Zeile eingetippt ist, mitsammt Carriage Return, kommt das \ auf die Zeile danach, nur Angabe dass ein Fehler war, aber nicht wo. Der Benutzer muss die Zeile nach dem real fehlgetippten Zeichen absuchen. Und wissen dass alle Kommandos davor bereits ausgeführt wurden, aber das fehlerhafte und alle danach nicht! Gefolgt von letztere ohne Fehler wiederholen. Mit z.B. obiges Demoprogrämmchen falsch getippt, im vierten Byte EG statt EF, sowie danach ab dort korrigiert:

Benutzer:   300: A9 8D 20 EG FF A9 C1 20 EF FF 4C 1F FF
Rechner:    0300: 00\
Benutzer:   303: EF FF A9 C1 20 EF FF 4C 1F FF
Rechner:    0303: 0E
    

Was ist da alles geschehen? Zuerst hat die 300 zum 0300: 00 ausgeben geführt. Dann hat das : den Hexmodus auf Speichern gestellt. Dann wurden A9 8D 20 abgespeichert. Dann ist EG gescheitert und hat das \ erzeugt. Der Rest wurde ignoriert. Man beachte, dass dieser Test aber nur ungültige Tasten abfangen kann. Ein ED statt EF würde einfach falsche Daten im Speicher ablegen, ein defektes Programm ergebend. Auch ein ER wäre trotz keine Hexzahl sein gültig, mit zuerst Zahl einlesen auf dem R abbrechen, dann das E als 0E anschauen und so abspeichern, und danach gleich das R als Kommando ausführen, mit dem defekten und unvollständigen Programm, gefolgt von Absturz! Auch bei diesem EG wird zuerst mit auf G abbrechen als ein 0E abgespeichert werden, dann erst das G als Kommando und Hexzahl scheitern. Weshalb auch mit 303: die Adresse neu setzen nötig ist, nur : ab würde 304 weiter machen, mit in 303: das falsche 0E belassen.

Hexzahl verwerten

War es eine Zahl, muss diese jetzt verwertet werden:

       *** weiter in NOTHEX
FF83   24 2B      BIT $2B        Test Hexzahl verarbeiten Modus, $74 = speicher
FF85   50 10      BVC $FF97        nein, teste $00 = Adresse oder $AE = EndAdr


NOTSTOR:
FF97   30 2B      BMI $FFC4      Test Hexzahl weiter, $00 = Adresse, $AE = Ende
    

Dabei testet BIT jetzt den Hexzahlen verarbeiten Modus. Dabei werden die Bits 6 und 7 angeschaut, Bit6 entscheidet BVC bzw BVS, Bit7 entscheidet BNE bzw BMI. Falls es $74 mit Bit6=1 ist, wird der BVC scheitern, gleich bei $FF87 weitergehen (und ein Datenbyte speichern), sonst wird es zu $FF97 gehen. Falls $00 ohne Bit7=0 wird der BMI scheitern, gleich bei $FF99 weitergehen (und Adresse setzen und dessen Daten ausgeben), sonst zu $FFC4 gehen (und Daten bis an Endadresse ausgeben). Womit die Statemachine von Zustand in Variable zu direkt im aktuellen Codefragment wechselt.

Auf den ersten Blick könnte man statt BMI auch BNE benutzen, zumal nach BVC schon erledigt hier der Test nur noch auf $00 oder eben nicht ist. Aber da macht der BIT einen Strich durch die Rechnung! In der 6800 hatte es separate BIT und TST Befehle, mit BIT eine testweise AND Rechnung mit Akkumulator und Speicher machen, aber TST nur eine Zahl im Speicher abtesten. Bei der 6502 hat es nur ein BIT, als Gemisch der beiden. Die BVC/BVS und BPL/BMI Bedingungen werden wie beim 6800 TST abgetestet, was wir hier benutzen wollen, aber die BEQ/BNE Bedingung wird wie beim 6800 BIT mit AND getestet, was wir nicht haben wollen. (Die PDP-11 hat auch separate BIT und TST, die 6800 hat diese von dort kopiert.)

Daher geht mit BNE auf beliebige Bits gesetzt sein testen nicht, weil BIT für BEQ/BNE einen AND von den Daten und dem Akkumulator Wert macht, weshalb dazu zuerst ein LDA #$FF notwendig gewesen wäre, 2 Bytes mehr. Da der BMI aber nur von Bit7=1 abhängt, welches direkt vom "." als #$2E+$80 in $28 abspeichern herkommt, ist dies vermutlich der Grund für die eigenartige Konvention dass alle Zeichen mit Bit7=1 benutzt werden. Was darauf hinausläuft, dass das Bit7 auf der Tastatur auf 5V=1 verdrahten nur dazu dient, um diesen Test zu erlauben, der Rest aus Konsistenz dazu folgte. Das ist das mit Abstand schrägste am ganzen Design! Und war auch das wofür ich am längsten brauchte um den Zusammenhang zu erkennen und verstehen.

(Beim Apple II ist der Grund für Bit7=1 benutzen dagegen definitiv bekannt: Ohne eine 6820 wird das Eingabestatus als Bit7 in den Eingabedaten gelesen, wie im Apple 1 der Ausgabestatus als Bit7 in den Ausgabedaten. Und dieses hat 1=gültig. Das loswerden würde ein AND #$7F kosten, 2 mehr Bytes. Aber diese Logik ist hier irrelevant, mit separat Status.)

Kommando Adresse

Da Adresse eingeben der erste benutzte Fall ist, und alle anderen erst vorbereitet, lass ich den direkten speichern Fall an $FF87 fortsetzend hier ebenfalls weg, und hole ihn am Schluss nach. Folglich werden wir zuerst Adresse setzen anschauen:

       *** weiter in NOTSTOR
FF99   A2 02      LDX #2         starte Schleife, für 2 Bytes pro Adresse

SETADR:
FF9B   B5 27      LDA $28-1,X    benutze Hexzahl, beide Hälften
FF9D   95 25      STA $26-1,X    setze speichern Adresse
FF9F   95 23      STA $24-1,X    setze Anzeigen Addresse
FFA1   CA         DEX
FFA2   D0 F7      BNE $FF9B      Schleife 2 mal ab SETADR
    

Wieder mal eine von LDX gesteuerte Abzählschleife, alles nach SETADR, dieses nur 2 mal. Dabei wird die Hexzahl von $28 und $29 sowohl nach $26 und $27 wie auch nach $24 und $25 kopiert. Der Grund für dieses Doppel ist, dass man mit StartAdresse:Daten... R den Anfang setzen kann, dann während den Daten schreiben $26 und $27 verändert werden, aber danach steht in $24 und $25 immer noch der Anfang, den das R direkt nutzen kann.

Die Schleife sind 11 Bytes, einfach 2 mal LDA STA STA wären 12, also wieder ein Byte gespart. Ohne separate $26 und $27 wären es mit nur LDA STA nur 8 Bytes, dieses Feature kostet also 3 Bytes.

Grund für die -1 überall in den Adressmodi ist, dass X ja 2 bzw 1 als Index drin hat, und nicht 1 bzw 0, weil der DEX erst nach kopieren stattfindet. Den DEX vor kopieren würde dessen Nulltest verlieren, weil LDA auch einen solchen auf die geladenen Daten macht! Mit LDX #1 anfangen, würde mit nach dem DEX ein BPL benutzen gehen, aber würde dann X = -1 statt X = 0 zurücklassen, und danach ein extra INX brauchen um X auf 0 zu holen, was später gebraucht wird. Also wäre so doch kein Byte gespart.

Danach wird die Adresse ausgegeben:

NXTPRINT:
FFA4   D0 14      BNE $FFBA      nicht gesetzt, Adresse nicht ausgeb, nur Daten
FFA6   A9 8D      LDA #$0D+$80   ASCII Carriage Return, mit Bit7 = 1
FFA8   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
FFAB   A5 25      LDA $25        Anzeigen Addresse obere Hälfte
FFAD   20 DC FF   JSR $FFDC      Byte als zwei Hexziffern ausgeben, mit PRBYTE
FFB0   A5 24      LDA $24        Anzeigen Addresse untere Hälfte
FFB2   20 DC FF   JSR $FFDC      Byte als zwei Hexziffern ausgeben, mit PRBYTE
FFB5   A9 BA      LDA #$3A+$80   ASCII ":", mit Bit7 = 1
FFB7   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
    

Der BNE ist unerwartet. Er sorgt dafür dass dieser Programmteil fakultativ sein kann. Nach Adresse setzen, und DEX ein X = 0 machen, wird die Adresse stets ausgegeben werden. Aber falls NXTPRINT von anderswo her aufgerufen wird, ist die Ausgabe fakulativ, je nach ob eine Rechnung dort 0 gab oder nicht. Wir werden später sehen, dass dies nur von einem einzelnen Ort her geschieht, und der BNE ohne mehr Bytes zu brauchen dort hätte sein können, also hier nur Taktzyklen verschwendet und Code weniger lesbar macht!

Der Rest ist geradeaus: Ein CR um die neue Zeile mit der Adresse und ihre Daten anzufangen. Daher erscheinen bei mehrere Adressen als Kommandos ihre Ausgaben auch auf separaten Zeilen. Dann wird die Adresse wegen 16bit auf einem 8bit Prozessor in zwei Hälften ausgegegen, jede mit einem PRBYTE. Dann kommt noch das ":" nach der Adresse ausgeben.

Danach kommt das Datenbyte dieser Adresse ausgeben:

PRDATA:
FFBA   A9 A0      LDA #$20+$80   ASCII " ", mit Bit7 = 1
FFBC   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
FFBF   A1 24      LDA ($24,X)    Byte von der Adresse (X = 0)
FFC1   20 DC FF   JSR $FFDC      Byte als zwei Hexziffern ausgeben, mit PRBYTE
    

Das Leerzeichen wird vor jedem Byte ausgegeben, um es von Adresse oder vorherigem Byte zu trennen, daher nicht erst danach. Generell gilt im Monitor eine Konvention, dass am Anfang von etwas Platz geschaffen wird, sei das Anfang der Eingabe neue Zeile, Anfang der Adresse ausgeben neue Zeile, oder anfang eines Bytes ausgeben ein Leerzeichen, bzw eine neue Zeile mit Adresse. Am Schluss wird die Cursorposition stehen gelassen, weil das was danach kommt schon passend neuen Platz machen wird! Daher müssen Programme das selbige machen, am Anfang neue Zeile, am Schluss nichts. Dies ist auch analog zu INY vor LDA benutzen.

(Dies im Kontrast zu moderner Software. Wo als Konvention gilt dass Ausgaben sich selber abschliessen, dem Nachfolgenden ihren Ort fest vorgebend. Sowie ebenso INY-artiges als Postincrement nach LDA-artigem kommt, dem Nachfolgenden ihren Ort fest vorgebend.)

Der LDA mit ($24,X) ist wie die STA und LDA mit $0200,Y bzw $24,X ein berechneter Adressemodus. Hier werden allerdings mit X = 0 als Index addiert einfach die beiden Adressen $24 und $25 benutzt, um mit der in diesen beiden zusammen liegenden weiteren indirekten Adresse die tatsächlichen Daten zu finden. Daher gilt im Monitor eben die Konvention, dass X = 0 der Normalzustand ist, auch um solches indirekt adressieren nicht zu beeinflussen, sowie damit Hexzahlen mit 0 anfangen, und um Hexzahlen Modus auf zu 0 setzen. Weshalb auch mit LDX gesteuerte Schleifen stets mit 0 enden müssen.

(Da diese indirekte Adressierung und eine weitere mit Y nur mit Zeropage funktioniert, sind diese beiden Adressenmodi der Grund warum dort RAM sein muss. Neben JSR und RTS als Grund warum in der Stackpage RAM sein muss, das sind die beiden Funktionen welche sonst versagen.)

Kommando Endadresse

Eigentlich ist das Adresse Kommando nun erledigt. Aber da es auch ein StartAdresse.EndAdresse Kommando gibt, und dieser selbige PRDATA Datenbyte ausgeben Programmteil von beiden benutzt wird, muss nun ein Test auf die Endadresse kommen. Bei der Startadresse von StartAdresse.EndAdresse wurde ebenfalls $24 und $25 auf diese gesetzt, von der Hexzahl in $28 und $29 her. Dann wurden bereits diese und ihre Daten ausgegeben. Erst danach kam überhaupt den "." lesen und der Hexzahlen Modus ging von 0 auf $AE. Dann kam die Endadresse, und ist nun in $28 und $29, aber nicht in $24 und $25, wegen dem BMI $FFC4 in $FF97, der die bereits gemachten (Start-)Adresse Sachen übersprungen hat. Dann werden die Bytes mit der Adresse in $24 und $25 durchgegangen bis bei der Adresse in $28 und $29 angekommen.

Bei nur Adresse Kommando, und auch nach der StartAdresse, sind dagegen $28 und $29 immer noch gleich wie $24 und $25, also reicht der selbige Endadresse Test. Falls StartAdresse.StartAdresse eingegeben würde, wird letzteres auch abbrechen, ohne etwas zu machen. Beim nur .EndAdresse Kommando wird wiederum durch das BMI $FFC4 genau hierhin gesprungen, weil die Adresse und das erste Byte ja bereits ausgegeben sind. Damit ist jedes .EndAdresse nur eine Erweiterung, selbst mit StartAdresse direkt davor sind das strikte 2 Kommandos, Adresse und .EndAdresse, egal ob zusammen oder mit Leerzeichen getrennt, oder auf zwei separaten Kommandozeilen!

Also wird nun getestet auf Endadresse schon erreicht:

XAMNEXT:
FFC4   86 2B      STX $2B        Hexzahl verarbeiten Modus, wieder auf 0
FFC6   A5 24      LDA $24        Vergleiche aktuelle Addresse mit Hexzahl
FFC8   C5 28      CMP $28
FFCA   A5 25      LDA $25
FFCC   E5 29      SBC $29
FFCE   B0 C1      BCS $FF91      Endadresse erreicht, zurück zu NEXTITEM
    

Da dies auch der Einsprungpunkt für .Endadresse ist, wird zuerst mit dem STX der Hexzahlen Modus wieder auf 0=Adresse gestellt, damit die nächste Hexzahl wieder als Adresse gewertet wird! Nach einem Adresse oder StartAdresse war es schon 0, bleibt einfach gleich. Dann werden die unteren Hälften in $24 und $28 verglichen, dann obere in $25 und $29, letztere mangels Übertrag im CMP mit SBC. Der BCS bricht ab, falls Ende erreicht ist.

Eigentlich wollen wir dann zurück zu NEXTITEM an $FF44, um die Kommandozeile weiter abzuarbeiten. Aber die Distanz von $FFD0 zu $FF44 = -$8C = Dezimal -140 ist dem BCS etwas zu weit, er kann ja maximal -128. Also wird ein ohnehin nach der Speicherroutine bei $FF91 liegender weiterer Sprung nach $FF44 angesprungen, was in einem Zweisprung resultiert. Das ist eine normale Methode um auf 8bit Prozessoren mehr Distanz zu bekommen. (6800 macht das auch so. 8080 kann ohnehin nur volle 3Byte 16bit Adresse Sprungbefehle, mit beliebiger Distanz.)

Falls ungleich Endadresse wird das nächste Byte ausgeben vorbereitet:

       *** weiter in XAMNEXT
FFD0   E6 24      INC $24        nächste Adresse untere Hälfte
FFD2   D0 02      BNE $FFD6      keine Pagegrenze überschritten
FFD4   E6 25      INC $25        nächste Adresse obere Hälfte
    

Falls nicht Endadresse, werden die INC benutzt um die Adresse +1 zu rechnen. Zuerst $24 = $24 + 1. Aber dann falls das am Ende einer Page von 255 zu 0 überschritten wurde und so der BNE durchfällt, auch noch $25 = $25 + 1 für nächste Page. Das ist die normale Methode um auf einem reinen 8bit Rechner 16bit Adressen zu rechnen.

(Hier haben 6800 und 8080 dedizierte 16bit +1 und -1 Befehle (und auch 16bit LDx #). Die 6800 aber nur auf ihr Hilfsregister, sowie die 8080 nur paarweise in ihren 6 Bytes im Prozessor. Die 8008 kann sogar nur 8bit, wie oben, und das nur in ihren 6 Bytes im Prozessor, von denen zudem nur ein Paar Adresse sein kann.)

Da nun weitere Daten ausgeben werden, kommt wieder die "am Anfang einer Ausgabe Platz schaffen" Konvention zum Zug. Bei beliebigen Bytes reicht das PRDATA Leerzeichen vor den Daten. Aber falls bereits 8 Bytes ausgegeben wurden, braucht es mehr. Ob dies der Fall ist wird nun getestet:

MOD8CHK:
FFD6   A5 24      LDA $24
FFD8   29 07      AND #$07       Test erstes=0 or anderes=1..7 Byte in Zeile
FFDA   10 C8      BPL $FFA4      Schleife immer, zu NXTPRINT oder dann PRDATA
    

Dies testet die neue Adresse ihren $24 Anteil darauf, ob die niedersten 3 Bits, mit dem AND ausgefiltert, 0 oder 1..7 sind. Das ergibt eine Modulus Division durch 8, und wird benutzt um die Ausgabe von Bereichen, in Zeilen von maximal 8 Bytes Länge zu zerlegen. Strikte tut es nur bei mit einer durch 8 teilbaren Adressen anfangen volle 8er Gruppen machen, bei anderem anfangen gibt es eine erste gekürzte Gruppe, dann volle. Auch ein undokumentiertes Feature.

Dabei tut der BPL immer springen, weil 0..7 niemals negativ sind. Wieder in 2 Bytes, statt einem 3 Byte JMP welches immer springt. Bei $FFA4 sitzt dann der oben schon erwähnte Taktzyklen verschwendende BNE, der bei 0 durchfällt, und die Adresse wie gehabt ausgibt, bei 1..7 aber springt, und so die Adresse weglässt. Er hätte ohne weitere Bytes zu brauchen hier vor dem BPL liegen können, neben dort dem Adresse Kommando beschleunigend (kein BNE) auch hier den häufigeren 7/8 Fall ohne weitere Adresse ebenso (nur BNE, kein BPL), mit dann langsamer BNE und BPL (oder auch einen lesbareren BEQ) nur in 1/8 der Fälle ablaufend. Und es wäre lesbarerer Code!

Das nächste Byte nach obigen BPL ist bereits die Adresse $FFDC vom PRBYTE. Also ist das Hauptprogramm hiermit durch! Es fehlen nur noch die zwei weggelassenen kleinen Sachen: Was geschieht wenn Hexzahlen im Modus nach ":" kommen, sowie was geschieht nach dem "R" Kommando?

Kommando Speichern

Zuerst nach Hexzahl mit ":" um Daten/Programm zu speichern, wo wir bei $FF87 weiter verfolgen weggelassen hatten:

       *** weiter in NOTHEX
FF87   A5 28      LDA $28        nur untere Hälfte von 16bit Hexzahl
FF89   81 26      STA ($26,X)    Byte zu der Adresse (X = 0)
FF8B   E6 26      INC $26        nächste Adresse untere Hälfte
FF8D   D0 B5      BNE $FF44      hole nächstes Zeichen, mit NEXTITEM
FF8F   E6 27      INC $27        nächste Adresse obere Hälfte

TONEXTITEM:
FF91   4C 44 FF   JMP $FF44      hole nächstes Zeichen, mit NEXTITEM
    

Man beachte, dass ":" eigentlich gar keine Addresse oder alten Inhalt ausgibt. Es ist lediglich die Adresse vor dem ":" welches dies bereits gemacht hat. Daher wird ja auch der alte Wert ausgegeben! Das ":" macht einfach danach weiter, mit Daten von der Kommandozeile nehmen, ohne Ausgaben. Dies geht beliebig lange so, weil nach einem ":" kein neuer Hexzahlen Modus mehr gesetzt wird. Erst eine neue Kommandozeile kann diesen wieder zu 0 machen, und so eine neue Adresse eingeben erlauben, oder nach neuem ":" wieder nur Daten speichern.

Hier sieht man auch, dass dabei nur $28 als Daten benutzt wird, nicht $29. So wird die Hexzahl von 4 weiter auf 2 Ziffern abgeschnitten. Genau daher kann man auch hier nach Fehlern in Daten tippen einfach 2 weitere Ziffern eingeben, und nur diese bleiben erhalten, die anderen 2 sind zwar weiterhin in $29, aber haben keine Auswirkung!

Der STA mit STA ($26,X) ist selbiges Verfahren wie der LDA mit STA ($24,X). Auch das INC Zeugs ist genaues Gegenstück. Der BNE und der JMP gehen beide zum $FF44 bei NEXTITEM, um die Kommandozeile weiter abzuarbeiten. Genau dieser JMP bei TONEXTITEM ist auch wohin der obige zu weite BCS hinspringt, der Mittelpunkt von dessen Zweisprung nach NEXTITEM.

Speziell ist nur, dass hier die separate Speicheradresse $26 und $27 benutzt wird, damit die Ausleseadresse in $24 und $25 für "R" unverändert erhalten bleibt. Erst das erlaubt ein "R" direkt nach Daten eingeben, weil ja keine Adresse in dieser Daten Kommandozeile mehr folgen kann!

Kommando Laufenlassen

Dann verbleibt nur noch nach dem "R" ein Programm laufen lassen, wo wir bei $FF94 weiter verfolgen weggelassen hatten:

RUN:
FF94   6C 24 00   JMP ($0024)    Programm an Adresse laufen lassen
    

Auch dies ist ein Sprung. Aber wie die beiden LDA ($24,X) und STA ($26,X), verwendet dieses ($0024) weil es in $24 und $25 die reale Adresse des aufzurufenen Programmes erwartet. Aber X ist bei diesem Befehl nicht relevant. Ebenso ist dieser nicht auf die Zeropage limitiert, daher 4 Hexziffern in den Klammern.

(Strikte ist dies kein JMP mit einem ($0024) Adressmodus, sondern ein JMP mit normalem $0024 Adressmodus, gefolgt von einem zweiten impliziten JMP. Was dann erst noch zu einem weiteren Prozessorbug geführt hat, der bei JMP ($xxFF) das erste Byte der indirekten Adresse von dort nimmt, aber das zweite in-Page von ($xx00), und nicht vom 00 der nächsten Page! Dieser Bug ist nur in der ursprünglichen NMOS 6502, wurde dann in der CMOS 65C02 korrigiert.)

Wieder gibt "R" gar keine Addresse oder Daten aus. Lediglich die Adresse vor dem "R" machte dies, und "R" macht einfach danach weiter. Es werden auch keine Anstalten gemacht, dem aufgerufenen Program zu helfen. Weder wird die Bildausgabe mit einem Carriage Return aufgeräumt, das Programm muss sich selber Platz schaffen. Noch wird dem Program eine Rücksprungadresse für einen RTS hingelegt, geschweige denn ist BRK als Abbruch benutzbar, wohl alles weil kein Platz mehr dafür war.

Programmkonventionen

Es wird lediglich im Handbuch, in der Monitor Anleitung, Seite 4, direkt nach dem "R" Kommando beschreiben, hingewiesen auf die drei Unterprogramme $FFEF für ECHO und $FFE5 für PRHEX und $FFDC für PRBYTE, sowie empfohlen mit ersterem am Anfang ein CR auszugeben.

Weil das Gegenstück zu ECHO ab NEXTCHAR fest eingebaut wurde, um JSR und RTS zu sparen, gibt es kein Unterprogramm dazu, muss jedes Programm welches die Tastatur lesen will diesen Treiber in sich duplizieren. Was im Handbuch nicht steht, geschweige denn Beispielcode dafür. Programme können aber auch die weitere Kommandozeile nach dem R auswerten. Was auch nicht im Handbuch steht, geschweige denn Beispielcode dafür hat.

Des weiteren wird noch hingewiesen, dass Programme mit JMP $FF1F nach GETLINE zu beenden sind, um wieder sicher in den Monitor zu gelangen, sowie dass danach ein CR kommen wird. Oder man kann auch mit Reset beenden, was nach dem \ für Abbruch auch ein CR machen wird.

Mit all dies können wir nun das Demoprogrämmchen verstehen:

0300   A9 8D      LDA #$0D+$80   ASCII Carriage Return, mit Bit7 = 1
0302   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
0305   A9 C1      LDA #$41+$80   ASCII "A", mit Bit7 = 1
0307   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
030A   4C 1F FF   JMP $FF1F      beenden, zurück in Monitor, mit GETLINE
    

Die JSR $FFEF sind der ECHO Systemaufruf um ein Zeichen ausgeben, wobei die LDA # davor die Zeichen vorgeben, und der JMP $FF1F ist der GETLINE Systemaufruf am Programmende, mit einem folgendem Return ausgeben. Wer ASCII kennt, sowie weiss dass der Apple 1 alle Zeichen mit Bit7=1 haben will, sieht bei den LDA #$8D und #$C1 dass es folglich die ASCII Zeichen 0D und 41 sind, also CR und "A". Womit dieses Demoprogrämmchen wie gesehen Return und A ausgibt, mit ersterem gleich nachdem der Rechner sein 0300: A9 ausgegeben hat.

Mit 6 weiteren LDA+JSR, mit den Konstanten D0 D0 CC C5 A0 B1, hätte es voll "APPLE 1" ausgeben können. Das kostet aber 5 Bytes pro Zeichen, und somit +6*5=30 Bytes, weshalb es sich schnell lohnt, dies kompakter mit einer Schleife zu machen, mit dann nur 1 Byte Daten pro Zeichen:

0300   A0 05      LDY #7         starte Schleife, für 8 Zeichen, 7..0
NEXTCHAR:
0302   B9 0E 03   LDA $030E,Y    Zeichen holen, von hinten im String her(!)
0305   20 EF FF   JSR $FFEF      Zeichen ausgeben, mit ECHO
0308   88         DEY            nächste Position in String
0309   10 F7      BPL $0302        ist Y >= 0, noch Zeichen, weiter
030B   4C 1F FF   JMP $FF1F      beenden, zurück in Monitor, mit GETLINE
030E   B1 A0 C5   .DB '1 SP 'E   CR und APPLE 1, reversiert, weil 7..0
0311   CC D0 D0   .DB 'L 'P 'P
0314   C1 8D      .DB 'A CR
    

Hinter dem Code in 0300..030D folgt der String in 030E..0315, mit so nur 14+8=22 Bytes statt obige 13 auf 43 anwachsend. Was bedeutet, dass ab 4 Zeichen mit 14+4=18 statt 4*5+1=21 sich diese Schleife lohnt, aber noch nicht bei 3 Zeichen mit 14+3=17 statt 3*5+1=16.

Den String reversiert im Speicher ablegen und von hinten her benutzen war früher eine normale Technik, um eine simple DEY Abzählschleife zu benutzen. Dies statt LDY #0, und nach einem INY mit einem zusätzlichen CMP #8 testen, und danach BNE statt BPL benutzen. Oder statt am Ende vom String, welcher nur 7bit ASCII ist, das letzte Zeichen mit invertiertem Bit7 markieren, und nach dem LDA mit einem BPL die Schleife abbrechen, zu einem weiteren letzten JSR $FFEF vor dem JMP $FF1F, sowie nach einem INY ohne CMP stets springen mit BNE. Oder am Anfang Y mit -8 laden, beim LDA dies mit $030E+8,Y kompensieren und dann INY benutzen gefolgt von BNE welches nach dem letzten INY abbricht.

Auch den String so in 3-Byte .DB Portionen aufteilen war früher eine durchaus normale Technik, weil manche sehr einfachen Assembler maximal 3 Bytes pro Codezeile erzeugen konnten, auch bei Datenbytes.

Schlussbetrachtung

Damit sind wir die Hardware und den Monitor durch. Für sowenige Chips und 256 Bytes an Code ist das ziemlich beeindruckend! Wer sich beschwert, dass der Apple 1 primitiv ist, er passt dafür in so wenig. Wer sich beschwert, dass das zu wenig sei, dem sei errinnert, dass im Vergleich dazu die Konkurrenz Altair 8800 oder Imsai 8080 gar keine Terminal Logik hatten, oder sonstig Tastatur oder Bildschirm, ebenso kein PROM, und so auch keinen Monitor oder Kommandozeile! Die waren nur Kisten mit an der Vorderseite Reihen von LEDs und Schaltern bzw Tastern, um den Speicher zu editieren, mit einem in Hardware(!) implementierten Editor. Bei Imsai dies wenigstens breite flache fingerfreundliche, bei Altair nicht mal das.

Statt Hexzahlen tippen, war mit LEDs und Schaltern direkt in Binär anschauen bzw eingeben notwendig. Dazu pro Byte eingeben 8 Schalter kippen und einen "Speichern" Taster drücken, statt hier nur 2+1 Tasten tippen. Ebenso für Adresse 16 Schalter und einen "Adresse" Taster. Was stets nur ein Byte ausgab, weil kein .EndAdresse. Danach musste man für jedes weitere Byte einen "Adresse+" Taster benutzen, und den Speicher byteweise mit binär auf 8 LEDs durchschreiten. Auch eingeben mit "Speichern" Taster ging den Speicher byteweise durch. Bis die Finger wehtaten, gerade auch beim Altair seinen Schaltern und Tastern. Mehr kann der Hardware Editor nicht. Das war weit langsamer und mühsamer zu benutzen.

Dazu kommt, dass obiges Demoprogrämmchen um A auszugeben zwar 1:1 in deren 8080 Prozessoren ihre Befehle übersetzbar ist, aber mangels Monitor scheitert. So hat der JMP am Ende kein Ziel, weil kein PROM um anzuspringen. Was man noch mit HALT Befehl benutzen substituieren kann. Im Altair oder Imsai steht der Prozessor nach dem Einschalten still, bis man ihn erst nach einem Program eingeben mit erneut Adresse Schaltern und "Start" Taster drücken laufen lässt! Ein HALT Befehl stoppt ihn wieder. Weit wichtiger aber haben die JSR keinen Systemaufruf um Zeichen auszugeben. Das ECHO mag zwar einfach sein, und die Befehle darin auch übersetzbar. Aber ohne eine 6820 mit Terminal Logik dahinter, bzw wegen 8080 Prozessor wohl eher eine 8255, oder wegen altmodischer sein noch eher eine 8251 UART mit echtem seriellen Terminal dahinter, ist nichts zu machen. Damit verbleibt nur seine Daten im Speicher ablegen und mit Adresse eingeben auslesen, also äquivalent zu LDA #$ gefolgt von STA $ und HALT, mit dann dem Benutzer diese Addresse einschaltern und anzeigen. Somit ist bereits dieses kleine Progrämmchen dort ohne die Hardware zu erweitern praktisch unmachbar!

Der Sol-20 hatte dagegen PROM mit einem Monitor drin, mit 1oder2kByte sogar 4bzw8 mal mehr. Darin bei 1k ein minimaler Monitor CONSOL, bzw bei 2k einen komfortableren SOLOS. Differenzen sind scheints ob Kassettenband Software sowie Komfortfunktionen drin. Ebenso hatte er Tastatur und Videomonitor. Letzteren sogar mit Bild von einem Speicher im direktem Prozessorzugriff. Er ist somit ein echter Homecomputer, und das trotz dass er eigentlich als Terminal designt und vermarktet wurde. Dies weil aus der VDM-1 Videokarte entstanden, welche anstelle eines Terminals benutzt, die Altair oder Imsai gleich zu vollen Homecomputern aufrüsten konnte. Bzw sogar bis zu vollen Personalcomputern, wenn man noch Disks addierte. Aber der kam erst 2 Monate später und war teurer. Damit war der Apple 1 ein recht guter Zwischenschritt, was ihn genau technologisch speziell macht.

(Der Sol-20 hatte von der VDM-1 her separates SRAM, mit 64x16=1024 Zeichen, aus einen Spezialchip mit 128er Zeichensatz. Das erlaubt volles ASCII 32..127, plus etwas an Graphikzeichen, aber hat keine Blockgraphik. Es bleibt noch 1bit normale oder reverse Darstellung. Es hat keine Graphikmodi, sowie keinerlei Bitmap, auch keine Farben. Dazu nur noch 1k SRAM, weil eben als Terminal designt. Verwendet einen 8080 Prozessor, mit S-100 Bus wie Altair und IMSAI, aber diesen nur als Slots. Kann mit dem Bus auch beliebige DRAM oder SRAM Speicherkarten addieren bis 48k, sowie ROM Karten bis 12k, oder mehr RAM wie bei der Language Card. Läuft mit separatem Videomonitor und Kassettenrekorder.)

Dazu ist der Apple 1 der Vorfahre vom massiv erweiterten Apple II. Zudem inspirierte er den PET 2001. Womit zwei der drei grossen 1977er Rechner, welche zusammen die Mikrocomputer Revolution lostraten, ideologisch vom Apple I abstammen. Damit war er ein bedeutender Entwicklungsschritt, was ihn auch historisch wichtig macht.

(Der dritte der drei grossen, der TRS-80, ist wiederum eine Kreuzung von Sol-20 und PET 2001 ihren Features. Mit vom 8080 abstammendem Z80 Prozessor. Mit 4oder12kByte ROM, für Level I (Integer) oder Level II (Microsoft mit Floating Point) Basic. Ohne die 1k SRAM vom Sol-20, weil als Rechner statt Terminal direkt mit 4..16k Speicher (mir unbekannt ob alte 4096er DRAMs wie Apple 1 oder ineffiziente 4k SRAMs wie PET). Eine Erweiterungsbox kann weitere 32k Speicher addieren (definitiv 2 Bänke 4116 DRAMs), sowie Slots. Wie der Sol-20 mit 64x16=1024 Zeichen Video in separatem 1k*7bit(!) SRAM Bildspeicher. Wie Sol-20 Font ebenfalls aus Spezialchip, aber mit nur 64er Zeichensatz mit teil ASCII 32..95, wie Apple 1. Dies aber in Hardware erweitert, mit 2x3 Blockgraphik. Wie PET hat er keine keine Graphikmodi, kann Low Res auch teilweise mit der Blockgraphik kompensieren, aber auch keinerlei Bitmap, ebenso keine Farben. Läuft mit separatem Videomonitor und Kassettenrekorder, welche aber als Paket mitgeliefert wurden, in einheitlichem Design.)


Home | Informative Texts | Apple 1

Diese Seite ist von Neil Franklin, letzte Änderung 2018.11.10