05.11.2012 Aufrufe

Das RAM

Das RAM

Das RAM

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

6. Die Spartan-Familie<br />

1


Programm für heute:<br />

Die Spartan-Familie<br />

• Aufbau, Größe und Ausführung<br />

• S<strong>RAM</strong> und D<strong>RAM</strong><br />

• Block <strong>RAM</strong><br />

• LCs, CLBs und Slices<br />

• IO-Blöcke<br />

• Routing Matrix<br />

2


Der Spartan-3-Chip<br />

Globaler Aufbau<br />

Die Spartan-3-Familie besteht aus 8 Chips unterschiedlicher Komplexität, die mit<br />

XC3Sn bezeichnet werden n∈{50, 200, 400, 1000, 1500, 2000, 4000, 5000}. Die<br />

Chips unterscheiden sich durch den Parameter n, wobei der XC3Sn etwa 1000n<br />

Gatter-Äquivalente implementieren kann.<br />

Unser Chip ist der XC3S5000, der ein Feld von 104x80 = 8320 CLBs besitzt. Er<br />

verfügt über 300 I/O-Pins und einen in den LUTs verteilten Speicher von 1.198.080<br />

Bit. Darüber hinaus stellt er ein globales <strong>RAM</strong> von 1.916.918 Bit zur Verfügung.<br />

Unsere Ausführung ist in einem GFF676 Gehäuse verpackt. (Fine Pitch Ball Grid<br />

Array mit 676 pins)<br />

Die komplette Baumusterbezeichnung unseres Chips ist XC3S5000-5 GFF676 C<br />

Dabei steht die -5 für Standard Performance (High Performance wäre -6) und das C<br />

am Ende für den kommerziellen Temperaturbereich von 0 bis 85 Grad Celsius.<br />

Die folgende Folie zeigt den Aufbau des Spartan.<br />

Der Spartan-3 kann mit internen Taktraten von bis zu 400 MHz betrieben werden<br />

3


<strong>RAM</strong><br />

Random Access Memory<br />

5


<strong>Das</strong> <strong>RAM</strong><br />

<strong>Das</strong> Random Access Memory ist ein Speicher für N Worte der Breite m Bit. Man<br />

bezeichnet einen solchen Speicher als N x m-<strong>RAM</strong>. Jedes dieser Worte ist durch eine<br />

Adresse identifizierbar. Die Adresse hat n = log N Bits. Wenn eine Adresse a n-1a n-1...a 1a 0<br />

angelegt wird, kann auf das zugehörige Wort lesend oder schreibend zugegriffen werden.<br />

Zu diesem Zweck legt man die Adresse an einem Dekodierer an, der sie in einen 1-aus-<br />

N-Code dekodiert. Für jedes der N Worte gibt es nun eine sogenannte word-Leitung.<br />

Durch den Dekodiervorgang wird auf die gesuchte word-Leitung eine 1 gelegt, auf alle<br />

anderen eine 0. An jeder dieser word-Leitungen liegt nun ein Register der Breite m Bit.<br />

Durch das Aktivieren der word-Leitung kann dieses Register nun von außen gelesen oder<br />

beschrieben werden.<br />

Ein einfacher Aufbau eines <strong>RAM</strong> mit N = 4 und m = 4 ist auf der nächsten Folie<br />

dargestellt. Die Speicherbausteine sind r-s-Flipflops. Jeweils vier davon sind zu einem<br />

parallelen Wortspeicher zusammengeschaltet.


a 1<br />

a 0<br />

read<br />

bit 3 bit 2 bit 1 bit 0<br />

word 0<br />

word 1<br />

word 2<br />

word 3<br />

7


Die Funktionsweise des <strong>RAM</strong><br />

Beim Schreiben wird an die Bit-Leitungen ein m-Bit-Wort angelegt. Dieses soll in die<br />

Zeile i geschrieben werden. Die Adresse i liegt am Decoder an. Dadurch wird die i-te<br />

word-Leitung auf 1 gelegt. Die And-Gatter vor den Flipflops der i-ten Zeile lassen somit<br />

am s-Eingang jedes r-s-Flipflops den Bit-Wert und am r-Eingang den invertierten Bit-<br />

Wert durch. Alle anderen word-Leitungen sind auf 0, d.h. die And-Gatter legen an alle<br />

anderen r-s-Flipflops die Speicherkombination r=0 und s=0 an. Somit wird in Zeile i das<br />

neue Wort „eingespeichert“. Alle anderen Zeilen speichern die alten Werte.<br />

Beim Lesen wird an die Bit-Leitungen von außen nichts angelegt, sie sind im<br />

hochohmigen Zustand Z. Durch die Word-Leitung werden nun die Transmission-Gates<br />

der Ausgang der Flipflops in der i-ten Zeile geöffnet, die gespeicherten Werte gelangen<br />

auf die Bit-Leitungen. Somit werden die Werte der i-ten Zeile an den Ausgang des <strong>RAM</strong><br />

transportiert.<br />

In der Realität werden <strong>RAM</strong>s nicht aus r-s-Flipflops und And-Gattern und Transmission-<br />

Gates aufgebaut, da diese Realisierung zu aufwendig wäre. Man unterscheidet zunächst<br />

zwischen S<strong>RAM</strong> (statischem <strong>RAM</strong>) und D<strong>RAM</strong> (dynamischem <strong>RAM</strong>). <strong>Das</strong> statische<br />

<strong>RAM</strong> speichert einen Wert und hält diesen, solange die Versorgungsspannung<br />

eingeschaltet bleibt. Unser <strong>RAM</strong> aus r-s-Flipflops ist ein Beispiel für eine Realisierung<br />

eines statischen <strong>RAM</strong>.


Aufbau einer 6-Transistor S<strong>RAM</strong>-Zelle<br />

bit bit<br />

Bit_R<br />

1<br />

1<br />

1<br />

1<br />

word<br />

9


Beim Schreiben auf eine solche S<strong>RAM</strong>-Zelle wird zunächst das zu schreibende Bit auf<br />

die Leitung „bit“ und sein Inverses auf die Leitung des invertierten „bit“ gelegt. Sodann<br />

wird (meist über einen Takteingang am Dekoder) die word-Leitung aktiviert. Sie steuert<br />

die beiden n-Kanal Transistoren an, die hier als sogenannte „pass-Transistoren“ eine<br />

Verbindung zur <strong>RAM</strong>-Zelle öffnen. Da die innere Kapazizät der <strong>RAM</strong>-Zelle sehr klein<br />

ist im Vergleich zur Kapazität der „bit“-Leitung, setzt sich sehr schnell das Potential der<br />

„bit“-Leitung auch innerhalb der <strong>RAM</strong>-Zelle durch. Dieser Effekt wird verstärkt, weil<br />

auf der anderen Seite auch die invertierte „bit“-Leitung ihr Potential auf den anderen<br />

Inverter aufzwingt und der Inverter durch seine Funktion die neuen Werte sofort<br />

stabilisiert.<br />

Dieser Effekt, der das Schreiben auf eine <strong>RAM</strong>-Zelle erleichtert, wirkt sich beim Lesen<br />

negativ aus: Würde man ebenfalls nur die „word“-Leitung aktivieren und damit die pass-<br />

Transistoren öffnen, so würde es den (kleinen) Invertern in der <strong>RAM</strong>-Zelle nicht<br />

gelingen, die große Kapazität der „bit“-Leitung hinreichend schnell umzuladen. Im<br />

Gegenteil: Wenn die „bit“-Leitung ein anderes Potential hat als das gespiecherte Bit_R<br />

im <strong>RAM</strong>, so würde bei Aktivierung der word-Leitung ein nicht gewollter<br />

Schreibvorgang stattfinden, weil sich das stärkere Signal auf der „bit“-Leitung<br />

durchsetzen würde.


Um diesen Effekt zu unterdrücken, lädt man vor dem eigentlichen Lesevorgang die<br />

„bit“-Leitung und die invertierte „bit“-Leitung auf das Potential der logischen 1 auf.<br />

Wenn jetzt die pass-Transistoren geöffnet werden, wird diese logische 1 auf einer Seite<br />

der <strong>RAM</strong>-Zelle bestätigt, auf der anderen Seite muss sie sich gegen die in der <strong>RAM</strong>-<br />

Zelle befindliche logische 0 durchsetzen. Die 0 verringert das Potential auf der<br />

jeweiligen „bit“-Leitung geringfügig.<br />

Diese Potentialdifferenz wird nun in einer gesonderten Schaltung erkannt und<br />

interpretiert. Diese Schaltung nennt man einen Differenzverstärker oder einen Differntial<br />

Sense Amplifier. Es muss also nicht die gesamte „bit“-Leitung (mit ihrer hohen<br />

Kapazität) umgeladen werden, sondern das Potential muss nur geringfügig verringert<br />

werden, um die Zelle auszulesen. Dieser gesamte Prozess ist auch für große <strong>RAM</strong>-<br />

Bausteine sehr schnell, da der Sense Amplifier eine vorhandene Potentialdifferenz in der<br />

Größenordnung von einer Nanosekunde detektieren kann.<br />

Der Sense Amplifier besteht aus zwei rückgekoppelten Inverterschaltungen, deren GND-<br />

Verbindung über einen Transistor abgekoppelt werden kann. Solange das „amplify“-<br />

Signal auf low ist, bilden sich auf den Eingängen die (sich geringfügig unterscheidenden)<br />

Potentiale der „bit“-Leitungen aus. Sobald dann das „amplify“-Signal auf high geht,<br />

werden die Inverter aktiv und eine 0 setzt sich dort durch, wo das Potential niedriger war<br />

und eine 1 dort, wo es höher war.


Differential Sense Amplifier (Differenzverstärker)<br />

amplify<br />

bit bit<br />

Vdd<br />

GND<br />

Data_out Data_out<br />

12


Ein Schreibvorgang auf einem S<strong>RAM</strong> besteht also aus folgenden Schritten:<br />

1. „bit“-Leitungen aufladen (eine invers zur anderen)<br />

2. Adresse an den Dekoder anlegen<br />

3. „word“-Leitung aktivieren (Bei getakteten Bausteinen wird dies durch den Takt<br />

ausgelöst)<br />

Die Schritte 1 und 2 passieren dabei in der Regel parallel zueinander.<br />

Der Lesevorgang ist etwas aufwendiger:<br />

1. „bit“-Leitungen mit logischer 1 vorladen (Precharge)<br />

2. Adresse an den Dekoder anlegen<br />

3. „word“-Leitungen aktivieren (Bei getakteten Bausteinen wird dies durch den Takt<br />

ausgelöst)<br />

4. „amplify“-Signal auf high legen<br />

5. Gespeicherten Bit-Wert nach kurzer Zeit an Data_out ablesen.<br />

Wiederum können die Schritte 1 und 2 parallel zueinander ablaufen.


<strong>Das</strong> dynamische <strong>RAM</strong> speichert alle Werte nur für eine kurze Zeit. Und zwar wird als<br />

Speichermedium die Kapazität eines Transistor-Gates (polykristallines Silizium)<br />

gegenüber der Source/Drain (Diffusion) ausgenutzt. Natürlich ist ein solcher Speicher<br />

flüchtig. Daher muß jedes Bit in einem dynamischen <strong>RAM</strong> von Zeit zu Zeit aufgefrischt<br />

(refresh) werden. <strong>Das</strong> geschieht, indem automatisch in festen Zeitabständen zeilenweise<br />

alle Bits im <strong>RAM</strong> einmal gelesen und unverändert wieder geschrieben werden. Ein<br />

typisches Zeitintervall für den Refresh-Zyklus bei heutigen D<strong>RAM</strong>s ist zwischen einer<br />

und 100 Millisekunden.<br />

S<strong>RAM</strong> ist schneller (kürzere Zugriffszeit) und teurer. Außerdem benötigt S<strong>RAM</strong> 6<br />

Transistoren pro gespeichertem Bit, während D<strong>RAM</strong> mit einem Transistor pro Bit<br />

auskommt. Daher hat D<strong>RAM</strong> eine höhere Speicherkapazität pro Chipfläche.<br />

Heutige Speicherchips sind quadratisch angeordnet. Es werden zwei Dekodierer<br />

verwendet, einen für die Zeile und einen für die Spalte. Zeilen- und Spaltenadresse sind<br />

dabei gleich lang. Auf diese Weise kann man mit der Hälfte der Adresspins auskommen,<br />

indem man die Adressleitungen im Zeitmultiplex verwendet. Immer wird zuerst die<br />

Zeilenadresse übertragen und dann über dieselben Pins die Spaltenadresse.


Aufbau einer 1-Transistor-D<strong>RAM</strong>-Zelle<br />

word<br />

bit<br />

GND<br />

21


Es gibt eine Reihe von Techniken, mit denen D<strong>RAM</strong>s schneller gemacht werden können.<br />

Z.B. handelt es sich bei einem SD<strong>RAM</strong> (synchronous D<strong>RAM</strong>) um D<strong>RAM</strong>, bei dem über<br />

eine externe Taktung die Synchronisation an die maximale Geschwindigkeit des<br />

Prozessor-Speicher-Busses erzwungen wird.<br />

<strong>RAM</strong>BUS ist eine vorwiegend für Intel-Prozessoren eingesetzte asynchrone<br />

Speichertechnik, bei der durch haargenaue Abstimmung der durch Kapazitäten,<br />

Induktivitäten, Widerstände verursachten Laufzeiten die Performance optimiert wurde.<br />

Diese Technologie ist aber gegenwärtig wieder auf dem Rückzug.<br />

CD<strong>RAM</strong> (Cache D<strong>RAM</strong>) ist eine Kombination aus S<strong>RAM</strong> und D<strong>RAM</strong>. Es handelt sich<br />

im Prinzip um D<strong>RAM</strong>, bei dem aber die Zeile, aus der zuletzt gelesen wurde in einem<br />

kleinen separaten S<strong>RAM</strong> (Cache) gehalten wird. Da beim Zugriff auf den Speicher<br />

häufig mehrmals hintereinander auf dieselbe Zeile zugegriffen wird, kann jeder Zugriff<br />

mit der Geschwindigkeit des S<strong>RAM</strong> bedient werden. Trotzdem kann die hohe<br />

Speicherdichte des D<strong>RAM</strong> ausgenutzt werden.


Block <strong>RAM</strong> im Spartan 3<br />

Am rechten und linken Rand des CLB-Feldes sowie in zwei Spalten in der Mitte gibt<br />

es in der Höhe von jeweils 4 CLBs ein so genanntes Block <strong>RAM</strong>, das als globaler<br />

Speicher für den gesamten FPGA genutzt werden kann. Jeder solche Block besteht<br />

aus 18.432 Bit <strong>RAM</strong>. Diese Zahl ergibt sich als Summe von 16384 und 2048 und<br />

besteht aus 2 14 Bits plus 2 11 Paritätsbits. Also jedes Byte kann durch ein Paritätsbit<br />

abgesichert werden. Die <strong>RAM</strong>-Blöcke können wahlweise in der Breite jeder<br />

Zweierpotenz zwischen 1 und 32 konfiguriert werden.<br />

Die folgende Tabelle zeigt die Abhängigkeit der Adressbreite von der gewünschten<br />

Wortbreite:<br />

Breite<br />

1<br />

2<br />

4<br />

8<br />

16<br />

32<br />

Bruttobreite Tiefe ADDR Bus Data Bus<br />

1 16384 ADDR DATA<br />

2 8192 ADDR DATA<br />

4 4096 ADDR DATA<br />

9 2048 ADDR DATA<br />

18 1024 ADDR DATA<br />

36 512 ADDR DATA<br />

28


Bezeichnung für<br />

Single- und<br />

Dual-Port<br />

Block <strong>RAM</strong>-<br />

Bausteine<br />

Aufruf Breite A Breite B<br />

<strong>RAM</strong>16_S1 1 -<br />

<strong>RAM</strong>16_S1_S1 1 1<br />

<strong>RAM</strong>16_S1_S2 1 2<br />

<strong>RAM</strong>16_S1_S4 1 4<br />

<strong>RAM</strong>16_S1_S8 1 8<br />

<strong>RAM</strong>16_S1_S16 1 16<br />

<strong>RAM</strong>16_S2_S1 2 1<br />

<strong>RAM</strong>16_S2_S2 2 2<br />

<strong>RAM</strong>16_S2_S4 2 4<br />

<strong>RAM</strong>16_S2_S8 2 8<br />

<strong>RAM</strong>16_S16_S1 16 1<br />

<strong>RAM</strong>16_S16_S2 16 2<br />

<strong>RAM</strong>16_S16_S4 16 4<br />

<strong>RAM</strong>16_S16_S8 16 8<br />

<strong>RAM</strong>16_S16_S16 16 16<br />

29


Benutzung des Block <strong>RAM</strong>:<br />

EN ist ein enable-Signal für Lesen, Schreiben und Reset. Nur wenn es gesetzt ist,<br />

kann das <strong>RAM</strong> etwas machen, ansonsten bleiben die DO-Pins und DOP-Pins in<br />

ihrem alten Zustand.<br />

CLK ist ein Takteingang für jeden Port des <strong>RAM</strong>. Beim Lesen wird die Adresse zur<br />

Taktzeit interpretiert und nach einer Zugriffszeit liegen die Daten am DO- (und DOP-)<br />

Ausgang an.<br />

Beim Schreiben werden bei der Taktflanke die Adresse und die Daten am DI-Eingang<br />

übernommen und nach der Zugriffszeit des <strong>RAM</strong> sind sie geschrieben. Ferner<br />

können beim Schreiben die überschriebenen Daten oder die neu geschriebenen<br />

Daten am DO-Bus gespiegelt werden. Dies geschieht durch setzten des sogenannten<br />

Attributs: Es gibt „READ_FIRST“, „WRITE_FIRST“ und „NO_CHANGE“<br />

Ob gelesen wird oder geschrieben bestimmt das WE (write enable) Signal. Wenn es<br />

gesetzt ist, wird geschreiben, wenn es ‘0‘ ist, wird gelesen.<br />

Der Reset-Eingang zwingt den DO-Ausgang auf 0. Im Speicher passiert dabei aber<br />

nichts.<br />

31


Single Port Timing:<br />

Auf dem Timing-Diagramm auf der folgenden Folie sehen wir drei aufeinander<br />

folgende Speicherzyklen in einem 1024x16-Bit Block <strong>RAM</strong>: <strong>RAM</strong>16_S16<br />

Im ersten Speicherzyklus wird bei der steigenden Flanke des Taktes aus der Adresse<br />

00 gelesen.<br />

Im zweiten Speicherzyklus wird in die Adresse 0F der Wert CCCC geschrieben.<br />

Im dritten Speicherzyklus wird wieder gelesen und zwar aus der Adresse 7E.<br />

32


WRITE_FIRST:<br />

Auf dem Timing-Diagramm auf der folgenden Folie sehen wir drei aufeinander<br />

folgende Speicherzyklen in einem 1024x16-Bit Block <strong>RAM</strong>: <strong>RAM</strong>16_S16<br />

Wenn gelesen wird, erscheint während des Lesezyklus der gelesene Wert auf den<br />

DO-Pins.<br />

Wenn geschrieben wird, erscheint der selbe Wert, der gerade geschrieben wird, auch<br />

am Ausgang der DO-Pins.<br />

34


READ_FIRST:<br />

Auf dem Timing-Diagramm auf der folgenden Folie sehen wir drei aufeinander<br />

folgende Speicherzyklen in einem 1024x16-Bit Block <strong>RAM</strong>: <strong>RAM</strong>16_S16<br />

Wenn gelesen wird, erscheint während des Lesezyklus der gelesene Wert auf den<br />

DO-Pins.<br />

Wenn geschrieben wird, erscheint der alte Wert, der gerade überschrieben wird, am<br />

Ausgang der DO-Pins.<br />

36


Dual Port Timing:<br />

Auf dem Timing-Diagramm auf der folgenden Folie sehen wir aufeinander folgende<br />

Speicherzyklen in einem 1024x16-Bit Dual-Port Block <strong>RAM</strong>: <strong>RAM</strong>16_S16_S16<br />

Die einzelnen Speicherzyklen verlaufen analog zum Single-Port-Fall. Allerdings gibt<br />

es einen write-write-Konflikt etwa in der Mitte des Diagramms: Beide Ports versuchen<br />

gleichzeitig schreibend auf die Adresse 0F zuzugreifen. Dadurch entsteht unter dieser<br />

Adresse ein undefinierter Wert, der im Folgetakt an beiden Ports ausgelesen wird.<br />

38


Konflikte im Block <strong>RAM</strong>:<br />

Bei einem Dual-Port <strong>RAM</strong> gibt es zwei Arten von möglichen Konflikten:<br />

Write-write Konflikt: Über beide Ports wird zum selben Zeitpunkt auf dieselbe <strong>RAM</strong>-<br />

Zelle geschrieben. Wenn das passiert, ist der Zustand der <strong>RAM</strong>-Zelle undefiniert<br />

Read-Write-Konflikt: Über einen Port wird lesend, über den anderen schreibend<br />

zugegriffen. In diesem Fall ist der Schreibvorgang erfolgreich, am DO-Ausgang des<br />

schreibenden Ports stehen die neu geschriebenen Daten, der DO-Ausgang des<br />

lesenden Ports ist undefiniert.<br />

Konflikte produzieren keine Schäden in der Hardware oder im übrigen Zustand des<br />

<strong>RAM</strong>.<br />

40


Einbinden des <strong>RAM</strong><br />

-- 4096x4 und 2048x8 Bit dual port Block Select<strong>RAM</strong><br />

component <strong>RAM</strong>16_S4_S8<br />

port (<br />

WEA : in std_logic; -- Write Enable für <strong>RAM</strong> A<br />

ENA : in std_logic; -- Enable: aktiviert die Komponente<br />

RSTA : in std_logic; -- Reset: setzt DOA auf Null<br />

CLKA : in std_logic; -- Clock: Systemtakt A<br />

ADDRA : in std_logic_vector(11 downto 0); -- Address Bus A<br />

DIA : in std_logic_vector(3 downto 0); -- Data in Bus A<br />

DOA : out std_logic_vector(3 downto 0) -- Data Output Bus A<br />

WEB : in std_logic; -- Write Enable für <strong>RAM</strong> B<br />

ENB : in std_logic; -- Enable: aktiviert die Komponente<br />

RSTB : in std_logic; -- Reset: setzt DOB auf Null<br />

CLKB : in std_logic; -- Clock: Systemtakt B<br />

ADDRB : in std_logic_vector(10 downto 0); -- Address Bus B<br />

DIB : in std_logic_vector(7 downto 0); -- Data in Bus B<br />

DOB : out std_logic_vector(7 downto 0) -- Data Output Bus B<br />

);<br />

end component;<br />

41


Beispiel: Entwurf eines Stack-Speichers<br />

Idee: Benutze das globale <strong>RAM</strong> und einen Stack-Pointer.<br />

Push-Operation: Hochzählen des Stack-Pointers und Speichern eines Wertes<br />

unter der dadurch erhaltenen neuen Adresse.<br />

Pop-Operation: Herunterzählen des Stack-Pointers und Auslesen des Wertes<br />

aus der Zelle mit der dadurch erhaltenen neuen Adresse.<br />

1. Ansatz: Verwende einen Aufwärts-/abwärtszähler als Stack-Pointer.<br />

Dieser wird durch push und pop inkrementiert bzw. dekrementiert.<br />

Der Zustand des Zählers wird an den Adresseingang des <strong>RAM</strong> gelegt.<br />

Problem: Zähler und <strong>RAM</strong> werden mit demselben Taktsignal gesteuert, d.h. ein<br />

Verändern des Stack-Pointers hat erst einen Takt später Auswirkung auf den<br />

Speicher.<br />

Dies Problem wird auf der folgenden Folie gezeigt.<br />

42


pop<br />

push<br />

CLK<br />

Data_in<br />

Counter<br />

ptr<br />

ADDR<br />

<strong>RAM</strong><br />

Data_out<br />

Wenn das push-Signal gesetzt ist und die positive Taktflanke kommt, wird ptr um 1<br />

erhöht. Gleichzeitig übernimmt das <strong>RAM</strong> den Wert an Data_in unter der bisherigen<br />

Adresse, die ja der alte Zählerstand ptr ist.<br />

Bei pop arbeitet der Stack richtig, denn der auszulesende Wert steht ja unter der<br />

aktuellen Adresse des Zählers.<br />

Nun könnte man natürlich einen zweiten Takt benutzen, der in der Phase geringfügig<br />

nach hinten verschoben ist, mit dem man das <strong>RAM</strong> betreibt. Hier wird allerdings eine<br />

einfachere Lösung erreicht, wie auf der folgenden Folie gezeigt:<br />

43<br />

WE


pop<br />

push<br />

CLK<br />

Data_in<br />

Counter<br />

ptr+1<br />

ptr<br />

A<br />

0 1<br />

A_<strong>RAM</strong><br />

ADDR<br />

WE<br />

<strong>RAM</strong><br />

Data_out<br />

Wenn das push-Signal gesetzt ist wird der um 1 erhöhte ptr-Wert verwendet, bei pop<br />

der normale ptr-Wert. Andernfalls wird ebenfalls der alte „Top of Stack“ an Data_out<br />

gezeigt.<br />

Nur bei push wird geschrieben, sonst gelesen.<br />

44


library IEEE;use IEEE.STD_LOGIC_1164.ALL;<br />

use IEEE.STD_LOGIC_ARITH.ALL;<br />

use IEEE.STD_LOGIC_UNSIGNED.ALLComponents.all;<br />

entity LIFO_PTR is -- Aufwärts-Abwärts-Zähler<br />

generic(<br />

WIDTH : positive := 8 ); -- Wortbreite des Zeiger-Vektors<br />

port(<br />

CLK : in std_logic; -- Systemtakt<br />

RST : in std_logic; -- asynchroner Reset (alles auf Null)<br />

INC : in std_logic; -- Zeiger inkrementieren<br />

DEC : in std_logic; -- Zeiger dekrementieren<br />

PTR : out std_logic_vector(WIDTH-1 downto 0) );<br />

architecture Behavioral of LIFO_PTR is<br />

signal PTR_buf : std_logic_vector(WIDTH-1 downto 0);<br />

begin<br />

Counter : process(CLK, RST)<br />

begin<br />

if RST='1' then<br />

PTR_buf '0');<br />

elsif CLK='1' and CLK'event then<br />

if INC='1' then<br />

PTR_buf


library IEEE;<br />

use IEEE.STD_LOGIC_1164.ALL;<br />

use IEEE.STD_LOGIC_ARITH.ALL;<br />

use IEEE.STD_LOGIC_UNSIGNED.ALL;<br />

entity LIFO is -- Gesamte Einheit<br />

port(<br />

CLK : in std_logic; -- Systemtakt<br />

CLEAR : in std_logic; -- Initialisieren: alles auf Null<br />

PUSH : in std_logic; -- Din eingefügen und LIFO inkrementieren<br />

POP : in std_logic; -- neues Dout und LIFO dekrementieren<br />

Din : in std_logic_vector (7 downto 0); -- Dateneingang<br />

Dout : out std_logic_vector (7 downto 0) -- Datenausgang<br />

);<br />

end LIFO;<br />

architecture Behavioral of LIFO is<br />

signal A, A_<strong>RAM</strong> : std_logic_vector(10 downto 0); -- lokaler Address-Zeiger<br />

signal PP : std_logic_vector(1 downto 0); -- Push und Pop<br />

46


-- Zeiger<br />

component LIFO_PTR<br />

generic(<br />

WIDTH : positive := 8 ); -- Wortbreite des Zeiger-Vektors<br />

port(<br />

CLK : in std_logic; -- Systemtakt<br />

RST : in std_logic; -- asynchroner Reset (alles auf Null)<br />

INC : in std_logic; -- Zeiger inkrementieren<br />

DEC : in std_logic; -- Zeiger dekrementieren<br />

PTR : out std_logic_vector(WIDTH-1 downto 0) );<br />

end component;<br />

-- 2048x8 Bit single port Block Select<strong>RAM</strong><br />

component <strong>RAM</strong>16_S8<br />

port (<br />

WE : in std_logic; -- Write: Enable: DI ins <strong>RAM</strong> schreiben<br />

EN : in std_logic; -- Enable: aktiviert die Komponente<br />

RST : in std_logic; -- Reset: setzt DO auf Null<br />

CLK : in std_logic; -- Clock: Systemtakt<br />

ADDR : in std_logic_vector(10 downto 0); -- Address Bus<br />

DI : in std_logic_vector(7 downto 0); -- Data in Bus<br />

DO : out std_logic_vector(7 downto 0) -- Data Output Bus<br />

);<br />

end component;<br />

47


egin<br />

-- zeigt auf aktuelle Adresse im <strong>RAM</strong><br />

LIFO_PTR0 : LIFO_PTR<br />

generic map(<br />

WIDTH => 8 )<br />

port map(<br />

CLK => CLK,<br />

RST => CLEAR,<br />

INC => PUSH,<br />

DEC => POP,<br />

PTR => A );<br />

-- 16K-Bit-<strong>RAM</strong> als 2048x8-Bit<br />

ram0: <strong>RAM</strong>16_S8<br />

port map (<br />

WE => PUSH,<br />

EN => '1',<br />

RST => '0',<br />

CLK => CLK,<br />

ADDR => A_<strong>RAM</strong>,<br />

DI => Din,<br />

DO => Dout );<br />

PP

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!