ZX Spectrum von Coronavirus und Sticks (eigentlich nicht wirklich)

Selbstisolation ist die Geißel der modernen Menschheit. Hier, zum Beispiel in der Nachbarstadt, organisieren sie freitags und samstags nach dem traditionellen Klatschen um 20 Uhr Balkonkonzerte. Sie fühlen sich gut, ihre Häuser sind groß und ihre Nachbarn sind jung. Unsere Nachbarn sind älter, sie wollen keine Konzerte. Und die Häuser sind niedrig, was auch nicht zum Nichtstun beiträgt. Deshalb werden wir gerettet, so gut wir können.

Am Nachmittag an einem abgelegenen Ort, nicht so schlimm. Wie abends, bis die Kinder einschlafen. Wie in den ersten Tagen, bis die Bücher ausgehen und sich die Serie langweilt. Aber ein Monat vergeht, gefolgt von einem anderen. Die Seele braucht altes Eisen. Aber nicht nur, sondern mit Perversion. Und ich kramte in den Mülleimern und fand dort den Zilog Z80-Prozessor:

Bild

Ich muss sagen, ich liebe diesen Prozessor wirklich. Wahrscheinlich ist das einzige, was ich an ihm mag, der 486. Chip, aber meine Hände werden ihn nicht bald erreichen, weil es schwierig und sinnlos ist, ihn in das Steckbrett einzusetzen. Müssen löten. Aber ich möchte noch nicht löten. Und noch mehr als das Z80 selbst liebe ich den ZX Spectrum-Computer, der auf dieser Basis gebaut wurde. Das native Spectrum leidet jedoch unter einer Katastrophe in Form eines benutzerdefinierten ULA-Logikchips, und seine Klone auf der losen Seite sind zwar nicht besonders schwer zu erstellen und zu verfeinern, aber immer noch nicht für das Steckbrettmodell geeignet, und warum so viele Sorgen, wenn es Arduino gibt?

Ein intelligenter, ausgewogener und adäquater Leser hört hier entweder auf zu lesen oder wirft etwas wie „1 FPGA-Chip wird die Spectrum-Computerklasse aufnehmen“, bevor er ihn stoppt. Ich bin nicht schlau, nicht angemessen, obwohl ausgeglichen, aber ich weiß nur über FPGA, dass es cool ist. Ich kann nur Arduino machen. Möchte aber wirklich die Drähte im Z80 stecken. Höchst.

Lasst uns beginnen

Beginnen wir natürlich. Aber zuerst Haftungsausschluss., , , . — . , , . , (, ?), , , , , . , , , , , .

Was ist ein adäquater 8-Bit-Computer? Dies ist in der Tat ein Prozessor, der mit ROM und RAM verbunden ist, und an der Seite befinden sich einige Zähler, die auf dem zusammengesetzten Bildschirm angezeigt werden sollen. Manchmal ein Timer zum Quietschen. ZX Spectrum unterscheidet sich nicht vom traditionellen Schema, außer einem. Es gibt eine ULA. Dies ist in der Tat der „Chipsatz“ des Spektrums. ULA verwaltet Peripheriegeräte wie Tonbandgeräte, Hochtöner und Tastatur (teilweise), die auf dem Bildschirm ausgegeben werden (ja, ja, die integrierte Grafikkarte wurde im Spectrum-Chipsatz angezeigt, bevor sie zum Mainstream wurde). Es gab auch ein gemeinsames Denkmal, die ersten 16 KB RAM (Adressen von 0x4000 bis 0x5B00). Daraus zeichnete die ULA ein Komposit auf den Bildschirm, und damit die Z80 dort nicht herumfummelte, wenn es nicht notwendig war, konnte die ULA den Prozessor bei Bedarf stoppen, da das Taktsignal auf der Z80 von dieser kam. Das heißt, wenn ULA mit Speicher gearbeitet und erkannt hat,Da sich der Prozessor auch in diesen Speicher einschleicht (dafür überwachte er ständig die MREQ- und die A15- und A14-Leitungen), stoppte er einfach die Prozessortaktung, bis er selbst fertig war, was er brauchte. Um eine Datenkorruption auf dem Bus zu vermeiden, wurden übrigens Teile des Busses auf der Prozessorseite und auf der ULA-Seite durch ... Widerstände ... begrenzt. Außerdem befand sich der Speicher von der ULA-Seite auf dem Bus und ignorierte dementsprechend im Falle einer Kollision die Daten und Adressen von der Prozessorseite vollständig.Die Daten und Adressen des Prozessors wurden vollständig ignoriert.Die Daten und Adressen des Prozessors wurden vollständig ignoriert.

Darüber hinaus verfügte das Spectrum über ROMs (Adressen 0x0000 - 0x3FFF) und einen eigenen Prozessorspeicher (0x8000 - 0xFFFF), auf die ULA keinen Zugriff hatte und der schneller als 16 KB gemeinsam genutzter Speicher arbeitete, da der Prozessor ULA in diesem Bereich nicht störte . Das war aber nur auf der 48K-Version des Computers. In der Basisversion gab es nur ROMs und 16 KiB, die mit ULA kompatibel waren. Wir fangen mit ihr an.

Es ist praktisch, dass der Z80-Prozessor DRAM regenerieren kann, aber irgendwie möchte ich mich nicht darum kümmern, da SRAM leichter zu finden ist und ich keinen Multiplexer habe (oder ich kann ihn nicht finden). Also werden wir SRAM verwenden. Zunächst werden wir das Hauptskelett zusammenbauen, an dem dann alles andere aufgehängt werden kann. Das Skelett wird ein Prozessor sein, ein ROM mit Firmware, der der Adresse des Spectrum-ROM, dem RAM, den ersten 16 KB nach dem ROM und einigen Chips zugeordnet ist, um alles zu verpacken ... Ich muss sagen, dass ich lange Zeit nicht drehen wollte, weil ich chinesische Layouts habe $ 1 für 2 Stück in ibee. Aber für mich lohnt sich die Aufregung. Wenn Sie nicht lange herumspielen möchten, nehmen Sie gute Layouts.

Installieren Sie also den Z80.

Wie Sie dem Datenblatt entnehmen können ,



Der Prozessor verfügt über 40 Pins, die in Gruppen unterteilt sind: Adressbus, Datenbus, Systemsteuerung, Prozessorsteuerung, Prozessorbussteuerung, Well, Leistung und Takt. Nicht alle dieser Schlussfolgerungen werden in realen Systemen wie dem ZX-Spektrum verwendet, wie aus dem Diagramm ersichtlich ist.. Von der Gruppe "Prozessorsteuerung" im Spektrum werden nur INT- und RESET-Signale verwendet. Das Signal M1 wird nicht von der Gruppe "Systemsteuerung" verwendet, die Gruppe "Bussteuerung" wird überhaupt nicht verwendet. Dafür gibt es einen Grund. Die alten 8-Bit-Systeme waren sehr einfach, und das Spektrum wurde mit der Idee erstellt, so einfach wie möglich zu sein, und alles, was ignoriert werden konnte, wurde ignoriert. Natürlich konnten Peripheriegerätehersteller Interrupts (INT- und NMI-Signale) verwenden, sie wurden zum Erweiterungssteckplatz geleitet, aber NMI wurde im Spektrum selbst nicht verwendet. Wie aus dem obigen Diagramm ersichtlich ist, werden die NMI-, WAIT- und BUSREQ-Signale von Leistungswiderständen hochgezogen, da es sich um aktivierte Eingänge mit niedrigem Pegel handelt (dies wird durch den Balken über dem Signalnamen angezeigt), und es muss eine logische Einheit (d. H. + 5 V) vorhanden sein, damit Gott bewahre, dass das unnötige Signal nicht funktioniert hat. Und hier sind die Ergebnisse, BUSACK, HALT, M1,und in der Luft hängen, mit nichts verbunden. Beachten Sie übrigens, dass das Spektrum keine Reset-Taste enthält. Der Reset-Pin ist über verbundenRC-Kette zur Stromversorgung (RESET wird auch durch einen niedrigen Pegel aktiviert), da laut Datenblatt nach dem Einschalten von RESET mindestens 3 Taktzyklen aktiv sein müssen, damit der Prozessor in den Betriebsmodus wechselt. Diese RC-Schaltung hält einen niedrigen Pegel, bis der Kondensator über einen Widerstand auf einen hohen Pegel geladen wird.

Lassen Sie uns kurz auf den Rest der Signale
eingehen : M1. Brauchen wir nicht. Er berichtet, dass der Prozessor begonnen hat, die nächste Anweisung auszuführen.
MREQ. Ich brauche es. Es wird gemeldet, dass der Prozessor auf den Speicher zugreift. Wenn dieses Signal niedrig wird (dh an die Strommasse angeschlossen ist), müssen wir den an den Prozessor angeschlossenen Speicher aktivieren.
IOREQ . Ich brauche es. Es wird gemeldet, dass der Prozessor auf ein Peripheriegerät zugreift. Zum Beispiel zur Tastatur.
RD . Ich brauche es. Informiert, dass der Prozessor Daten aus dem Speicher (wenn MREQ aktiv ist) oder Peripheriegeräten (IOREQ) liest.
Wr . Ich brauche es. Meldet, dass der Prozessor Daten in Speicher / Peripheriegeräte schreibt.
RFSH . Ich brauche es. Im Allgemeinen wird dieses Signal für den dynamischen Speicher (DRAM) benötigt. Ich habe nicht vor, es zu verwenden, da seine Adressierung schwieriger ist (Matrix, nicht linear, dh es wird notwendig sein, einen Multiplexer zu installieren), und im Allgemeinen sind SRAM-Mikroschaltungen mit geringer Kapazität in unserer Zeit leichter zu bekommen. Da der Prozessor selbst DRAM durch Sortieren von Adressen auf dem Speicherbus regeneriert, können wir mit diesem Signal die Regenerationszyklen ignorieren und den Speicher nicht mit aktivem RFSH aktivieren.
HALT . Nicht benötigt. Zeigt an, dass der Prozessor gestoppt ist.
WARTEN. Nicht benötigt. Dieses Signal wird benötigt, um den Prozessor aufzufordern, anzuhalten und etwas zu warten. Wird normalerweise von langsamen Peripheriegeräten oder Speichern verwendet. Aber nicht im Spektrum. Wenn in den Spectrum-Peripheriegeräten (ULA) der Prozessor gestoppt wird, sendet er einfach kein Taktsignal mehr an ihn. Dies ist zuverlässiger, da der Prozessor nach dem Empfang von WAIT nicht sofort stoppt.
INT . Unterbrechen. Es ist noch nicht klar. Wir gehen davon aus, dass es noch nicht benötigt wird. Dann werden wir es herausfinden.
Das NMI . Unmaskierbare Unterbrechung. Super Interrupt. Nicht nötig.
RESET . Ohne es wird es nicht fliegen.
BUSREQ . Nicht benötigt. Fordert den Prozessor auf, die Verbindung zu den Daten- / Adressbussen sowie den Steuersignalen zu trennen. Dies ist erforderlich, wenn ein Gerät die Kontrolle über den Bus erlangen möchte.
BUSACK. Nicht benötigt. Dient dazu, das Gerät, das BUSREQ ausgeführt hat, darüber zu informieren, dass der Bus frei ist.
Die UHR . Taktsignal. Klar, er wird gebraucht.
Mahlzeiten werden auch benötigt. Ehre sei den Entwicklern, nur + 5V / GND. Keine 3 Belastungen für Sie.
A0-A15 ist der Adressbus. Darauf zeigt der Prozessor entweder eine Speicheradresse (MREQ ist aktiv) oder eine E / A-Portadresse (IOREQ ist aktiv) mit entsprechenden Aufrufen an. Wie Sie sehen können, ist der Bus 16 Bit breit, sodass Sie 64 KB Speicher direkt adressieren können.
D0-D7 - Datenbus. Der Prozessor gibt die angeforderten Daten an ihn aus (WR aktiv) oder liest daraus (RD aktiv).

Also werden wir den Prozessor auf das Steckbrett legen. Seine Schlussfolgerungen sind also physisch lokalisiert:

Bild

Schließen Sie die Stromversorgung an (Pin 11 und 29). Für alle Fälle habe ich auch einen 10 pF Kondensator zwischen diese Beine gelegt. Aber er hat mir am Ende nicht geholfen. Die Pins 27, 23, 18 können mit nichts verbunden bleiben. Die Pins 26, 25, 24, 17, 16 sind über Widerstände (ich habe 10 kOhm verwendet) mit der Stromversorgung verbunden. Ich brachte den Adressbus (Pins 1-5 und 30-40) auf die gegenüberliegende Seite des Steckbretts und den Datenbus (Pins 7-10 und 12-15) auf einen separaten Datenbus, der aus Prototyp-Leistungsbussen besteht.
Die Pins 6 (Taktsignal) und 26 (RESET) sind (später) mit Arduin verbunden, damit Sie den Prozessor von dort aus steuern können.

Es stellte sich so heraus:



Bis Sie auf die Drähte von oben achten, gehen sie aus dem ROM, wir werden etwas später darauf eingehen. Auf dem Foto neben dem Prozessor ist außerdem ein weiterer Chip sichtbar. Wir brauchen es, um die oberen Bits der Adresse zu dekodieren. Wie ich oben sagte, gibt es 3 Arten von Speicher im Spektrum. Die unteren 16 KiB des Adressraums sind ROM. Wenn sich die Klemmen A14 und A15 in einem niedrigen Zustand (0 Volt) befinden, müssen wir dementsprechend alles außer dem ROM-Chip vom Bus trennen. Als nächstes stehen 16 KB gemeinsamer Speicher zur Verfügung. Dementsprechend müssen wir diesen Speicher an den Bus anschließen (und den Rest trennen), wenn der Ausgang A15 niedrig und A14 hoch ist (+5 Volt). Nun, dann kommen 32 KiB schneller Speicher. Wir werden diesen Speicher später anhängen und ihn aktivieren, wenn sich der Ausgang A15 in einem hohen Zustand befindet. Vergessen Sie außerdem nicht, dass wir den Speicher nur aktivieren, wenn er aktiv ist (hier aktiv - niedrig,0 Volt) MREQ und inaktiv (hier inaktiv - hoch, + 5 V) RFSH. All dies ist recht einfach in Standardlogik zu implementieren, auf denselben NANDs wie 74HC00 oder orthodoxem K155LA3, und ich verstehe, dass diese Aufgabe für die Vorbereitungsgruppe des Kindergartens bestimmt ist, ich kann jedoch nur in Wahrheitstabellen in Freiheit und in Gefangenschaft denkenIch habe dort ein vollständiges Harlekin-Diagramm , aus dem Sie einfach den Teil entnehmen können, in dem U4 gezeichnet ist (74HC138, zum Glück habe ich ungefähr hundert davon). Wir werden U11 aus Gründen der Klarheit ignorieren, da die oberen 32 KB für uns bisher nicht von Interesse sind.

Das Anschließen ist sehr einfach.



Wie aus der kurzen Beschreibung ersichtlich istDie Mikroschaltung ist ein Decoder, der Binärzahlen von 000 bis 111 für Ausgänge vom 1. bis 3. empfängt und einen von 8 Ausgängen (Abschnitte 7 und 9 bis 15) aktiviert, die dieser Nummer entsprechen. Da nur 8 verschiedene Nummern in 3 Bits gespeichert werden können, gibt es nur acht Ausgänge. Wie Sie sehen können, sind die Schlussfolgerungen invertiert, dh derjenige, der aktiv ist, hat einen Pegel von 0 V und alle anderen + 5 V. Zusätzlich ist ein Schlüssel in Form eines Gatters mit 3 Eingängen vom Typ "I" in den Chip eingebaut, und zwei seiner drei Eingänge sind ebenfalls invertiert.

In unserem Fall verbinden wir den Decoder selbst wie folgt: Das höchstwertige Bit (3. Zweig) mit dem Boden, es wird immer 0 sein. Das mittlere Bit ist die Leitung A15. Es gibt nur 1, wenn der Prozessor auf die oberen 32 KB Speicher zugreift (Adressen 0x8000 - 0xFFFF oder 1000000000000000 - 1111111111111111 in Binärform, wenn das höchstwertige Bit immer auf 1 gesetzt ist). Wir verbinden das niedrigstwertige Bit mit der A14-Leitung, wo der hohe Pegel für den Fall ist, dass entweder nach den ersten 16 KiB auf den Speicher zugegriffen wird, aber bis zu den obersten 32 KiB (Adressen 0x4000 - 0x7FFF oder 0100000000000000 - 0111111111111111 in binärer Form) oder mit den letzten 16 KiB der Adresse Leerzeichen (Adressen 0xB000 - 0xFFFF oder 1100000000000000 - 1111111111111111 in binärer Form).

Mal sehen, wie die Ausgabe in jedem der Fälle sein wird:

  • 14 15 , 16 , , 000, 0 ( ), Y0 (15 ). , .
  • 14 , 15 — , 16 , 32 , 001, 1 , Y1 (14 ). , 16 , .
  • 14 , 15 — , - 32 48 , 010, Y2 (13 ). , .
  • Wenn beide Leitungen (A14 und A15) aktiv sind, greift der Prozessor auf die obersten 16 KB Speicher zu, von 48 bis 64 KB, wir haben sie nicht, sodass der Y3-Pin (12. Pin) ebenfalls in der Luft ist.

Dank eines anderen Elements aktiviert die Mikroschaltung ihre Ergebnisse nur dann, wenn die Eingänge 4 und 5 niedrig und 6 hoch sind. Der 4. Eingang befindet sich immer im niedrigen Zustand (er ist direkt mit Masse verbunden), der fünfte ist nur niedrig, wenn der Prozessor auf den Speicher zugreift (denken Sie daran, MREQ im niedrigen Zustand bedeutet Zugriff auf den Speicher), und der sechste ist hoch, wenn der Prozessor keinen Aktualisierungszyklus durchführt DRAM (wir haben SRAM, daher sind DRAM-Aktualisierungszyklen der sicherste Weg, sie einfach zu ignorieren). Es stellt sich als großartig heraus.

Als nächstes setzen Sie das ROM.

Ich habe den W27C512 genommen, weil er billig und gut gelaunt ist, alles passt und Sie auch Bankgeschäfte tätigen können. 64 KB! 4 Firmware kann hochgeladen werden. Nun, ich habe ungefähr eine Million dieser Mikroschaltungen. Ich entschied, dass ich nur die obere Hälfte nähen würde, da bei Harlequin das A15-Bein an + 5V gebunden ist und das A14 mit einem Jumper verstellbar ist. So kann ich die Firmware auf Harlequin testen, um nicht lange herumzuspielen. Smorim Datenblatt . Wir legen den Chip auf das Steckbrett. Ich habe es wieder in die rechte Ecke gestellt, um den Adressbus links zu platzieren. Wir ziehen das Bein A15 an die Stromversorgung, die A14-Kabel an den Boden. Verkabelung - Auf diese Weise können Sie die Speicherbänke ändern. Da der A15 immer auf einem hohen Niveau sein wird, stehen uns nur die besten 32-KiB-Flash-Laufwerke zur Verfügung. Von diesen wählt die A14-Leitung die oberen (+ 5V) oder unteren (Masse) 16 KiB. In ihnen füllte ich das Testbild mit dem Programmiererund 48K BASIC Firmware .

Die restlichen 14 Adressleitungen (A0 - A13) sind links mit dem Adressbus verbunden. Wir verbinden den Datenbus (Q0 - Q7) in Form von Leistungsbussen der Steckbrettmodelle mit unserem improvisierten Bus. Essen nicht vergessen!

Nun die Steuersignale. OE ist eine Ausgangsfreigabe. Wir benötigen das ROM, um Daten an den Datenbus zu senden, wenn der Prozessor sie liest. Wir verbinden uns also direkt mit dem Ausgang des RD-Prozessors. Praktischerweise sind beide Pins, sowohl OE auf ROM als auch RD auf dem Prozessor, in einem niedrigen Zustand aktiv. Dies ist wichtig, Sie müssen nichts umkehren. Zusätzlich hat der ROM einen CS-Eingang, der auch in einem niedrigen Zustand aktiv ist. Wenn dieser Eingang nicht aktiv ist, ignoriert das ROM alle anderen Signale und gibt nichts an den Datenbus aus. Wir werden diesen Eingang mit dem Y0-Pin (15-Pin) des 74HC138-Chips verbinden, der auch im niedrigen Zustand aktiv ist. In der Harlekin- Schaltung ist dieses Signal aus irgendeinem Grund über einen Widerstand verbunden. Wir werden das Gleiche tun. Ich weiß nicht warum. Vielleicht sagen es mir kluge Leute in den Kommentaren ... Sie haben es mir

gesagt. Danke,sterr::
. , «» . .




Alle.

Jetzt RAM.

Es ist schwieriger damit, da nicht nur der Prozessor, sondern auch ULA oder in unserem Fall Arduino mit RAM (mit unseren 16 KiB) arbeiten. Da ist es notwendig, etwas zu lesen, das auf dem Bildschirm angezeigt wird. Daher müssen wir in der Lage sein, Steuersignale und den RAM-Adressbus vom Prozessor zu trennen. Wir werden den Datenbus nicht trennen, wir werden wie im ursprünglichen Spektrum (und in Harlequin) handeln: Wir werden den Bus durch Widerstände (470-500 Ohm) teilen. Die Widerstände sind einerseits der Prozessor und das ROM, andererseits RAM und Arduino. Im Falle eines Konflikts auf dem Datenbus funktioniert er somit als zwei separate Busse. Im Übrigen verwenden wir 74HC245 wie in Harlekin (U43, U44 im Diagramm), obwohl im vorliegenden SpeccyEs gab auch Widerstände (zwischen IC1 einerseits ist dies ULA und IC3, IC4 andererseits).

Der 74HC245 ist ein 8-Bit- Buspuffer . Wir haben jedoch 2 Steuersignale (RD - beim Lesen aus dem Speicher und CE zum Aktivieren des RAM selbst. Wir werden uns beim späteren Schreiben in den Speicher mit WR befassen) und 14 Bits der Adresse: Denken Sie daran, dass wir oben bereits ein Signal in den Speicher nur mit 74HC138 erzeugen Für den Fall, dass der Prozessor A14 mit inaktivem A15 aktiviert hat, sodass keine zusätzliche Dekodierung der Adresse erforderlich ist, funktioniert der Speicher nur, wenn auf die ersten 16 KB nach dem ROM zugegriffen wird. Um 16 KiB zu adressieren, benötigen Sie natürlich nur 14 Adressleitungen (A0-A13). Insgesamt werden 16 Signale erhalten, sodass wir 2 74HC245-Mikroschaltungen benötigen. Wir verbinden sie mit dem Steckbrett links anstelle des Adressbusses.

Aus dem Datenblatt des 74HC245 geht hervor, dass es im Allgemeinen keine Rolle spielt, auf welcher Seite die Mikroschaltungen angeschlossen werden sollen. Da ich jedoch mit dem Aufbau der Layouts von unten nach oben begonnen habe und alle anderen Mikroschaltungen mit dem ersten Pin links installiert sind, wird der Adressbus mit Seite A (Pins 2) verbunden -9 Chips sind im Datenblatt als A0-A7 bezeichnet. Die Übertragungsrichtung ist immer vom Prozessor zum RAM, da der RAM die Adresse nie festlegt, sondern nur empfängt. Beim 74HC245 ist Pin 1 (DIR) für die Übertragungsrichtung verantwortlich. Laut DatenblattDamit auf der B-Seite ein Ausgang vorhanden ist, der dem Eingang auf der A-Seite entspricht, muss das DIR auf HIGH gesetzt werden. Verbinden Sie also den 1. Pin beider Stromkreise mit + 5V. OE (20. Pin, aktiviert durch einen niedrigen Pegel) wird über Kabel mit Masse verbunden, so dass es schnell auf +5 V umgeschaltet und vom Prozessor getrennt werden kann. Weiter einfacher. Schließen Sie die Stromversorgung für beide Chips an. Die am weitesten rechts liegenden Pins der rechten Mikroschaltung (8. und 9. Pins, Eingänge A6 und A7) sind Steuersignale. Ich habe A7 an den RD-Anschluss des Prozessors und A6 an den Y1-Pin des 74HC138-Chips angeschlossen, da nur dann ein niedriger Pegel auftritt, wenn der Prozessor auf unseren RAM zugreift. Die verbleibenden Schlussfolgerungen von Seite A beider Mikrokreise (Beine 2–9 für links und Beine 2–7 für rechts) habe ich an den Adressbus angeschlossen, Klemmen A13-A0. Die oberen 2 Bits der Adresse werden nicht benötigt, da sie bereits im Signal vom 74HC138 decodiert sind.Nun zum RAM selbst. Natürlich habe ich das verwendet, was ich bereits hatte: einen Cache-Chip vom alten Motherboard. Ich bin rübergekommenIS61C256 bei 20 ns, aber jeder wird es tun. Speccy arbeitete mit einer Frequenz von 3,5 MHz, aber im Moment werden wir im Allgemeinen Arduinki behandeln. Wenn 100 kHz herauskommen, wird es Glück geben! Also verbinden wir uns. Vergessen Sie natürlich nicht das Essen. Schlussfolgerungen I / O0 - I / O7 werden NACH den Widerständen an das Steckbrett des Datenbusses angeschlossen. Ich hatte Glück (eigentlich nicht), bei meinen chinesischen Modellen sind die Powerbusse genau in der Mitte geteilt. Ich habe diese Funktion verwendet, um den Bus mit Widerständen zu trennen. Wenn Ihre Layouts falsch sind, müssen Sie pervers seinMachen Sie einen zweiten Datenbus und verbinden Sie ihn mit Widerständen mit dem ersten. Die Schlussfolgerungen von A0-A13 werden auf die entsprechenden B-Schlussfolgerungen der 74HC245-Chips geworfen, wobei nicht zu vergessen ist, dass die am weitesten rechts stehenden nicht mit dem Datenbus, sondern mit den Steuersignalen verbunden sind. A14 - wahlweise entweder am Boden oder auf +5V. Ein 32-KiB-Chip, daher wird diese Schlussfolgerung bestimmen, welche Hälfte wir verwenden werden. Wenn Sie einen 16-KiB-SRAM finden, befindet sich keine A14-Leitung darin. Die Ausgänge sind WE (Schreibfreigabe), CE (Chipfreigabe) und OE (Ausgangsfreigabe). Alle sind niedrig aktiviert. OE muss mit dem RD des Prozessors verbunden sein, aber natürlich nicht direkt, sondern über den rechten 74HC245, wo der RD zu meinem A7-Fuß kommt und dementsprechend aus dem B7-Fuß (11. Pin) herauskommt. Dort und verbinden. CE muss vom 74HC138 an Y1 angeschlossen werden, wodurch die Adresse dekodiert wird. Ihr Signal kommt auf der A6 des rechten Chips 74HC245 zu mirkommt aus Fuß B6 (12 Stifte). WIR habe ich direkt an den Ausgang des WR-Prozessors angeschlossen. Ich habe auch ein Überbrückungskabel aus dem OE-Signal installiert und es einfach in den nicht verwendeten Teil des Steckbretts gesteckt. Durch Anschließen dieses Kabels an die Strommasse kann ich die Aktivierung des RAM erzwingen, wenn ich es von Arduinka lese. Trotzdem habe ich alle Steuersignale des RAM mit Widerständen von 10 kOhm auf + 5V gezogen. Nur für den Fall. Es stellte sich so heraus:



Im Allgemeinen sollte hier und wenn überhaupt zu Beginn ein Schulungsprogramm zum Zeitpunkt der Signale auf den Reifen durchgeführt werden. Ich werde dies nicht tun, da es im Netzwerk schon oft von viel intelligenteren Leuten als mir gemacht wurde. Für Interessierte kann ich dieses Video empfehlen:


Wenn Sie diesen Kanal nicht abonniert haben und sich als Amateur und nicht als Profi für Elektronik interessieren, kann ich es Ihnen generell nur empfehlen. Dies ist ein sehr hochwertiger Inhalt.

Im Allgemeinen ist das fast alles. Jetzt müssen Sie nur noch verstehen, wie Sie Daten aus dem RAM in Arduino lesen. Lassen Sie uns zunächst berechnen, wie viele Arduinki-Schlussfolgerungen wir benötigen. Wir müssen ein Taktsignal geben und den RESET steuern, das sind 2 Pins. 8 Bit Datenbus - weitere 8 Pins. Plus 13 Adressbits, insgesamt 23 Pins. Außerdem müssen wir mit Arduinka kommunizieren, wir werden dies über ihre serielle Schnittstelle tun, dies sind weitere 2 Pins. Leider gibt es nur 20 Schlussfolgerungen zu meiner DNA.

Nun, das spielt keine Rolle. Ich kenne keine einzige Person, die Arduino hat und keine 74HC595 hat. Es scheint mir, dass sie nur im Kit verkauft werden. Zumindest habe ich nur 74HC00 Chips mehr als 595x. Also benutzen wir sie. Darüber hinaus werde ich Raum in dem Artikel speichern, weil die Arbeit des 595x mit Arduino perfekt beschrieben wird hier. 595mi werden wir die Adresse generieren. Der Chip benötigt 2 Teile (da wir 13 Bits der Adresse haben und der 595. 8 Pins hat). Wie Sie mehrere 595x für die Buserweiterung anschließen, wird unter dem obigen Link ausführlich beschrieben. Ich stelle nur fest, dass in den Beispielen an diesem Link OE (Pin 13) 595x zu Boden gezogen wird. Wir werden dies kategorisch nicht tun, wir werden dort ein Signal von Arduinki senden, da die 595x-Pins direkt mit dem RAM-Adressbus verbunden werden und wir dort kein Störsignal benötigen. Nach dem Anschließen der 595x-Pins an den RAM-Adressbus muss an den Modellen nichts mehr getan werden. Zeit, die Arduinka anzuschließen. Aber schreiben Sie zuerst eine Skizze:

// CPU defines
#define CPU_CLOCK_PIN 2
#define CPU_RESET_PIN 3

// RAM defines
#define RAM_OUTPUT_ENABLE_PIN 4
#define RAM_WRITE_ENABLE_PIN 5
#define RAM_CHIP_ENABLE_PIN 6
#define RAM_BUFFER_PIN 7

// Shift Register defines
#define SR_DATA_PIN 8
#define SR_OUTPUT_ENABLE_PIN 9
#define SR_LATCH_PIN 10
#define SR_CLOCK_PIN 11

//////////////////////////////////////////////////////////////////////////

void setup() {
  // All CPU and RAM control signals need to be configured as inputs by default
  // and only changed to outputs when used.
  // Shift register control signals may be preconfigured

  // CPU controls seetup
  DDRC = B00000000;
  pinMode(CPU_CLOCK_PIN, INPUT);
  pinMode(CPU_RESET_PIN, INPUT);

  // RAM setup
  pinMode(RAM_WRITE_ENABLE_PIN, INPUT);
  pinMode(RAM_OUTPUT_ENABLE_PIN, INPUT);
  pinMode(RAM_CHIP_ENABLE_PIN, INPUT);
  pinMode(RAM_BUFFER_PIN, OUTPUT);
  digitalWrite(RAM_BUFFER_PIN, LOW);

  // SR setup
  pinMode(SR_LATCH_PIN, OUTPUT);
  pinMode(SR_CLOCK_PIN, OUTPUT);
  pinMode(SR_DATA_PIN, OUTPUT);
  pinMode(SR_OUTPUT_ENABLE_PIN, OUTPUT);
  digitalWrite(SR_OUTPUT_ENABLE_PIN, HIGH); // active low

  // common setup
  Serial.begin(9600);
  Serial.println("Hello");
}// setup

//////////////////////////////////////////////////////////////////////////

void shiftReadValueFromAddress(uint16_t address, uint8_t *value) {
  // disable RAM output
  pinMode(RAM_WRITE_ENABLE_PIN, OUTPUT);
  digitalWrite(RAM_WRITE_ENABLE_PIN, HIGH); // active low
  pinMode(RAM_OUTPUT_ENABLE_PIN, OUTPUT);
  digitalWrite(RAM_OUTPUT_ENABLE_PIN, HIGH); // active low
  // set address
  digitalWrite(SR_LATCH_PIN, LOW);
  shiftOut(SR_DATA_PIN, SR_CLOCK_PIN, MSBFIRST, address>>8); 
  shiftOut(SR_DATA_PIN, SR_CLOCK_PIN, MSBFIRST, address);  
  digitalWrite(SR_LATCH_PIN, HIGH);
  digitalWrite(SR_OUTPUT_ENABLE_PIN, LOW); // active low
  // write value to RAM
  digitalWrite(RAM_OUTPUT_ENABLE_PIN, LOW); // active low
  delay(1);
  DDRC = B00000000;
  *value = PINC;
  digitalWrite(RAM_OUTPUT_ENABLE_PIN, HIGH); // active low
  // disable SR
  digitalWrite(SR_OUTPUT_ENABLE_PIN, HIGH); // active low
  pinMode(RAM_WRITE_ENABLE_PIN, INPUT);
  pinMode(RAM_OUTPUT_ENABLE_PIN, INPUT);
}// shiftWriteValueToAddress

//////////////////////////////////////////////////////////////////////////

void runClock(uint32_t cycles) {
  uint32_t currCycle = 0;
  pinMode(CPU_CLOCK_PIN, OUTPUT);
  while(currCycle < cycles) {
    digitalWrite(CPU_CLOCK_PIN, HIGH);
    digitalWrite(CPU_CLOCK_PIN, LOW);
    currCycle++;
  }
  pinMode(CPU_CLOCK_PIN, INPUT);
}// runClock

//////////////////////////////////////////////////////////////////////////

void trySpectrum() {
  pinMode(RAM_WRITE_ENABLE_PIN, INPUT);
  pinMode(RAM_OUTPUT_ENABLE_PIN, INPUT);
  pinMode(CPU_RESET_PIN, OUTPUT);
  digitalWrite(CPU_RESET_PIN, LOW);
  runClock(30);
  digitalWrite(CPU_RESET_PIN, HIGH);
  runClock(12500000);
}// trySpectrum

//////////////////////////////////////////////////////////////////////////

void readDisplayLines() {
  uint8_t value;
  digitalWrite(RAM_BUFFER_PIN, HIGH);
  pinMode(RAM_CHIP_ENABLE_PIN, OUTPUT);
  digitalWrite(RAM_CHIP_ENABLE_PIN, LOW);
  for(uint16_t i=16384; i<16384+6144;i++) {
    shiftReadValueFromAddress(i, &value);
    Serial.println(value);
  }
  pinMode(RAM_CHIP_ENABLE_PIN, INPUT);
}// readDisplayLines

//////////////////////////////////////////////////////////////////////////

void loop() {
  trySpectrum();
  Serial.println("Hope we are ok now. Please set up memory for reading");
  delay(40000);
  Serial.println("Reading memory");
  readDisplayLines();
  Serial.println("Done");
  delay(100000);
}// loop

Wie Sie der Skizze entnehmen können (nun, wirklich, plötzlich hat es jemand gelesen), habe ich den Datenbus zu Port C gelesen. Wie Arduischik sich erinnern kann, hat Port C in CID 6 Pins. Das heißt, ich lese nur 6 Bits. Ja, der Einfachheit halber ignoriere ich die 2 hohen Bits in jedem Byte des Bildschirmpuffers. Dies führt dazu, dass alle 2 Pixel nach 6 immer Hintergrundfarben angezeigt werden. Während einer Fahrt, dann reparieren Sie es. Das ist das Skelett.

Nun zur Verbindung selbst. Im Prinzip wird alles ganz oben auf die Skizze gemalt:

// CPU defines
#define CPU_CLOCK_PIN 2 -  2     6  ( )
#define CPU_RESET_PIN 3 -  3     26  (RESET)

// RAM defines
#define RAM_OUTPUT_ENABLE_PIN 4 -  4     22  (OE)
#define RAM_WRITE_ENABLE_PIN 5 -  5    .     .
#define RAM_CHIP_ENABLE_PIN 6 -  6     .        ,        .   - ,   -  .   ,   .
#define RAM_BUFFER_PIN 7 -  ,    6,    .

// Shift Register defines
#define SR_DATA_PIN 8   -  8     14 "" 595.        9 ,     .
#define SR_OUTPUT_ENABLE_PIN 9 -   13  595
#define SR_LATCH_PIN 10 -   12  595
#define SR_CLOCK_PIN 11 -   11  595.

Alles ist einfach. So sieht es aus, als wäre ich alle zusammengebaut (das Arduino wurde im Bild geschnitten, aber es gibt nichts Besonderes zu sehen):



Beim Start sagt Arduino fröhlich Hallo zur seriellen Schnittstelle des Computers (wenn auch virtuell) und beginnt, den Prozessor zu quälen. Nachdem Sie ihn gründlich gefoltert haben (ein paar Minuten), stoppt das Programm den armen Kerl und bietet Ihnen an, die Jumper mit den Stiften auf dem Steckbrett neu anzuordnen und den Speicher von den Adressbus- und Prozessorsteuersignalen zu trennen.

Jetzt müssen wir die Griffe verwenden, um die an den Pins 19 des 74HC245 angeschlossenen Kabel von Masse auf +5 V umzustellen. Daher trennen wir den Prozessor vom RAM. Pin 22 des RAM-Chips selbst muss mit Masse verbunden sein (ich habe oben über die Verkabelung geschrieben, die ich bisher an einer unbenutzten Stelle in das Steckbrett gesteckt habe). Daher schalten wir den RAM gewaltsam ein.

Nachdem Arduinka ein wenig gewartet hat, beginnt er, den Inhalt des Speichers zu lesen und ihn in einer Spalte an die serielle Schnittstelle auszugeben. Es wird viele, viele Zahlen geben. Jetzt können Sie diese Daten von dort kopieren und beispielsweise in eine Textdatei einfügen, ohne zu vergessen, den gesamten unnötigen Text zu bereinigen (ein paar Zeilen oben und "Fertig" unten). Wir benötigen nur Zahlen. Dies ist, was unser Speccy im Videospeicher aufgezeichnet hat. Es bleibt nur zu sehen, was sich im Videospeicher befand. Und der Videospeicher des Spektrums ist nicht einfach ...

Wie Sie sehen können, werden die Pixel selbst getrennt von der Farbe gespeichert. Wir werden die Farbe vorerst ignorieren, lassen Sie uns nur die Pixel selbst lesen. Aber sie sind nicht so einfach zu dekodieren. Nach vielen Schmerzen in Visual Studio kam ich zu dieser eleganten Lösung:


#include "stdafx.h"
#include <windows.h>
#include <stdint.h>
#include <stdio.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
uint8_t *scrData;

VOID OnPaint(HDC hdc) {
	size_t arrSize = 6144;//sizeof(scrData) / sizeof(scrData[0]);
	//int currRow = 0, currX = 0, currBlock = 0, currY = 0, currBase = 0;
	for (size_t arrPos = 0; arrPos < arrSize; arrPos++) {
		int blockPos = arrPos % 2048;
		int currBase = (blockPos % 256) / 32;
		int currX = blockPos % 32;
		int currBlock = arrPos / 2048;
		int currRow = blockPos / 256;
		int currY = currBlock * 64 + currBase * 8 + currRow;
		for (int trueX = 0; trueX < 8; trueX++) {
			char r = ((scrData[arrPos] >> trueX) & 1)*255;
			SetPixel(hdc, currX * 8 + (8-trueX), currY, RGB(r, r, r));
		}
	}
}

void loadData() {
	FILE *file;
	errno_t err;
	if ((err = fopen_s(&file, "data.txt", "r"))) {
		MessageBox(NULL, L"Unable to oopen the file", L"Error", 1);
	}
	scrData = (uint8_t*)malloc(6144);
	int currDataPos = 0;
	char buffer[256];
	char currChar = 0;
	int currLinePos = 0;
	while (currChar != EOF) {
		currChar = getc(file);
		buffer[currLinePos++] = currChar;
		if (currChar == '\n') {
			buffer[currLinePos] = 0;
			scrData[currDataPos++] = (uint8_t)atoi(buffer);
			currLinePos = 0;
		}
	}
	fclose(file);
}

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow) {
	HWND                hWnd;
	MSG                 msg;
	WNDCLASS            wndClass;
	wndClass.style = CS_HREDRAW | CS_VREDRAW;
	wndClass.lpfnWndProc = WndProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = hInstance;
	wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = TEXT("GettingStarted");
	RegisterClass(&wndClass);
	hWnd = CreateWindow(
		TEXT("GettingStarted"),   // window class name
		TEXT("Getting Started"),  // window caption
		WS_OVERLAPPEDWINDOW,      // window style
		CW_USEDEFAULT,            // initial x position
		CW_USEDEFAULT,            // initial y position
		CW_USEDEFAULT,            // initial x size
		CW_USEDEFAULT,            // initial y size
		NULL,                     // parent window handle
		NULL,                     // window menu handle
		hInstance,                // program instance handle
		NULL);                    // creation parameters
	loadData();
	ShowWindow(hWnd, iCmdShow);
	UpdateWindow(hWnd);
	while (GetMessage(&msg, NULL, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return msg.wParam;
}  // WinMain

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
	HDC          hdc;
	PAINTSTRUCT  ps;
	switch (message) {
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		OnPaint(hdc);
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
} // WndProc

Das Programm öffnet die Datei data.txt aus seinem Verzeichnis. In dieser Datei die Textausgabe des Arduino (nach dem Löschen aller zusätzlichen Zeilen, wie oben erwähnt).

Wir geben ihm die resultierende Datei und als Ergebnis:



Ja, das Ergebnis ist zwar alles andere als ideal, aber es ist definitiv die Ausgabe auf dem Bildschirm. Darüber hinaus diejenige, die benötigt wird. Aus dem ROM mit Diagnose-Firmware.

Nun, das Computerskelett ist fertig. Ja, es ist noch nicht möglich, es zu verwenden, aber Sie können sehen, wie einfach die alten 8-Bit-Computer angeordnet waren. Ich habe immer noch ein wenig über das Steckbrett geschlagen, aber das Fazit wurde nur noch schlimmer. Es scheint, dass der nächste Schritt darin besteht, ein normales, nicht gelötetes Steckbrett mit normaler Leistung anzulöten.

Aber ist es notwendig?

All Articles