Byte enable

Grund
Entspricht die Speicherbreite nicht der Breite des Buses, so müssen die Bytes des Busses über enable aufgeteilt werden können.
Mit enable sagt man, ob man den ersten oder zweiten Teil der Busbreite will.

Bsp
32-Bit-System für einen Baustein nur 16 Bit (z.B. für ein IO-Port oder ein Speicherbaustein).
ByteEnable

Byte_enable_0:
Bezieht sich auf die höheren Bits des Datan-Signals im Bus:   Data[16] – Data[31]
Byte_enable_1:
Bezieht sich auf die tieferen Bits der aktuellen Busdaten:     Data[0] – Data[15].

Setzt man Byte_enable_0, so werden nur die 15 oberen Bits des akutellen Bussiganals geschrieben oder gelesen.

Aktuelle Busdaten und Speichervorgang
Hier liegen in einem Speicher bereits Daten an den Adressen a0, a1 und a2.
Auf dem Bus liegt ein aktuelles Datenpaket (data) von 32 Bit.
Teile (oder auch das ganze) Datenpaket sollen auf die belegten Speicheradressen geschrieben werden.

Byte_Enable_timing

Da auch der Befehl Lesen aktiviert ist, wird „zeitgleich“ von der bestehenden Adresse auch der Wert an den Datenausgang (q) gelegt.

Aubau einer Speicherzelle

Logik

Logik_FF

Ein FF besteht aus logischer Sicht aus zwei Invertern. Durch die zwei Inverter, erscheint der Eingangswert wieder am Ausgang. Der Wert wurde gespeichert. Tiefer betrachtet, ist die Basis eines FF ein Latch. Das Latch ist der Baustein, der durch Set-Reset am Ausgang ein Wert behält. Das Latch ist aber asynchron und deshal kein FF im engen Sinn. Das FF hat zusätzlich einen Clock. Dadurch werden erst (bei steigender Flanke) die Ausgänge gesetzt.

Hardware (mit Transistoren)

Hardware_FF

Pro Speicherzelle (FF) hat es zwei Bit-Lines. Eine ist die Inversion der anderen.
Auf der Bit-Line wird das aktuelle Bit gesetzt (siehe erstes Bild für Logik).
Die Word-Linien, ist die Verbindung einer Reihe von Speicherzellen.
Unterschied Transistoren <-> Kondensatoren als Speicherelement
FF können mit Transistoren (z.B. in SRAM, s = static = stabil) oder mit Kondensatoren (z.B. DRAM, d = dynamisch = instabil) aufgebaut sein. Die Transistoren behalten ihren Wert (Zustand ‚1‘ oder ‚0‘), sind sie einmal geschalten, was bei den Kondensatoren nicht gilt. Die Kondensatoren entladen sich (‚1‘ – > ‚0.7‘ -> ‚0.5‘), weshalb ihr Wert immer wieder neu gesetzt (refresh) werden muss.
Das Refrehen wird zeilenweise gemacht.
Bsp. Bei einem 16-Bit-Memory, wird in einem Refresh-Zyklus 16 FF neu gesetzt.

Gute Website zu detaillierteren Informatioenen zum digitalen Speichern („How RAM works“).

Memory an Prozesssor anbinden

Takt anpassen
Die Geschwindigkeit des Prozessors ist oft langsamer als der Speicher.
Hier braucht es eine Synchronisation durch einen Takt-Generator.
Das Timing (einhalten der Setup und Holdzeit) war traditionell die grösste Fehlerquelle für ungültige Daten.

Word Grösse
Bei 32-Bit Prozessoren ist ein Word 32 Bit breit. Der Bus hat dieselbe Breite. Am einfachsten ist es, wennd der Speicher ebenfalls 32 breit ist. Dann entspricht ein Word einer Speicher-Zeile. Ansonsten braucht es Anpassungen (siehe Byte-enable).

Schreib- und Leserichtung
Traditionell hat der Prozessor nur ein Bus, der in beide Richtungen kommuniziert.
Bei FPGAs hat es immer zwei Busse, einer fürs Lesen und einer fürs Schreiben.

Zugriffe auf Speicher (Port)
Normalerweise gibt es einen Port. Über diesen gehen die Lese- wie auch die Schreibzyklen.
Im FPGA hat es zwei Ports. Beide können für beides gebraucht werden und können unterschiedliche Busbreiten haben.

 

VHDL IO Debuggen

Signalüberprüfung
Zum Debuggen können den Top-Level-Ports spezifische Wert zugewiesen werden:

GPIO_0 <= '0';
GPIO_0 <= '1';

Am KO kann dann der Wert überprüft werden oder man kann die Pins ausläuten, um zu sehen, ob sie funktionieren. Problem: Pins können auch sonst auf ‚0‘ oder ‚1‘ per default sein.

Besser: Clock-Zuweisung. (Problem auch hier: ClK könnte per default herauskommen.) Am sichersten: CLK auf eigene Frequenz einstellen, so ist man sicher, dass es der gewünschte Pin ist.

GPIO_0 <= CLK_50;


Instanzen anpassen

Im Top-Level könnendie IO der Instanzen mit open auf inaktiv gesetzt werden.

inst_counter: counter
    PORT MAP( clk          => CLOCK_50,
              verification => open,   -- GPIO_0   
              zero_out      => open   -- GPIO_1                
        );