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