Ein testbench für das RAM ?.... warum ? warum nicht ein testbench für
CPU+RAM/ROM ?
was ich normalerweise mache ist folgendes, ich schreibe ein Testprogramm
mit dem Befehlen die ich testen will und dann lasse den Takt laufen...
dann gucke mir die Signalen mit dem GTKview.
für ein Sync RAM würde ich so was machen:
1
wait for 10ns;
2
we <= '1';
3
data <= X"A5";
4
wait for 10ns;
5
we <= '0';
und dann die Signalen mit GTKWave anschauen... könntest du auch die
Werte vergleichen und dann mit dem textio Modul was auf die Console
schreiben...
Hi Ale,
da ich nach ein paar Monaten immer den Syntax vergesse, wenn ich länger
nichts mehr gemacht habe, brauche ich ein paar einfach VHDL Beispiele.
Deshalb wollte ich mit einem einfachen RAM und der zugehörigen Testbench
anfangen.
Ich brauche erst mal 3 Module: Ein RAM, die CPU und einen Clk-Teiler für
die CPU, damit ich sie runter bremsen kann und ein einfaches blinky
läuft.
Du willst für 64 Bytes ein ganzen BRAM opfern? Bei Xilinx passen da 2
kBytes rein.
Und wieso willst du asynchron lesen? Bei Xilinx wird automatisch ein
BRAM verwendet wenn die Leseadresse getaktet ist.
process(clk, we, a, d)
d und we sind da überflüssig. Weil ja noch nichts passiert wenn sich
diese ändern, sondern erst zur Taktflanke.
Ich würde aber trotzdem versuchen wenn möglich alles getaktet zu bauen
und zwar mit nur einem Takt.
1
CLOCK_CLK:process
2
begin
3
WAITFORTbPeriod;
4
a<="000000";
5
d<="00000000";
6
we<='1';
7
WAITFORTbPeriod;
8
reset<='0';
9
WAITFORTbPeriod;
10
reset<='1';
11
WAITFORTbPeriod;
12
a<="000000";
13
d<="00000000";
14
we<='0';
15
WAITFORTbPeriod;
16
we<='1';
17
WAITFORTbPeriod;
18
a<="000000";
19
d<="01010101";
20
we<='0';
21
WAITFORTbPeriod;
22
we<='1';
23
24
endprocess;
Wo hast du das denn her? Such dir mal eine andere Quelle.
a wird dreimal exakt der gleiche Wert zugewiesen. Dann gibt es viele
Signale ohne Defaultwerte. Gerade in der Testbench würde ich
Defaultwerte verwenden. Z. B. für dein reset. Oh, was macht der Reset
überhaupt?
>Du willst für 64 Bytes ein ganzen BRAM opfern? Bei Xilinx passen da 2>kBytes rein.
Naja, die CPU hat nur 64 Bytes Addresraum ( Bild ). Ich habe mal den
Datenpfad von inout auf getrennte Datenpfade umgestellt.
>Ich würde aber trotzdem versuchen wenn möglich alles getaktet zu bauen>und zwar mit nur einem Takt.
Zeig mal ein Beispiel.
>Wo hast du das denn her? Such dir mal eine andere Quelle.
Der Reset ist noch ein Überbleibsel des Autogenerators:
http://vhdl.lapinoo.net
Der bei der MCPU verwendete Speicher ist ein distributed SRAM ohne Takt.
Wenn man das durch ein Block-RAM ersetzt, dann kommen die Daten beim
Lesezugriff erst einen Takt später und nicht sofort, wie bei distributed
RAM. Entweder die CPU selbst muss geändert werden (mehr States) oder man
nimmt beim RAM die negative Taktflanke zum Zugriff. Das funktioniert
zwar in diesem Fall, da die Laufzeiten in der CPU sehr kurz sind, ist
aber kein schönes Design. Wenn man die CPU umbaut, so dass man ein
Block-RAM verwenden kann, gibt es das nächste Problem. In der
State-Machine werden die einzelnen States so codiert, dass Fetch und die
einzelnen Befehle die jeweiligen States sind. Ich finde die
State_Machine bei der MCPU etwas unübersichtlich, das ist aber nur meine
Meinung und wenn Du damit zurechtkommst, dann lasse das so. Wenn man das
sauber machen will (Fetch/WaitForMemory/Execute), dann wird die MCPU
deutlich größer. Alternativ kann man für das Warten aus den Speicher ein
FF nehmen, was weniger Aufwand ist.
Also: Im ersten Schritt würde ich das fertige Modul sram64k8.vhd nehmen,
Das kann man leicht ändern, so dass nur 64 Speicherplätze verwendet
werden. Im nächsten Schritt würde ich eine Eingabe über Schalter und
eine Ausgabe über Leds einbauen. Dazu kann man eine Speicheradresse
(z.B. 63) zweckentfremden. Sobald das funktioniert, kann man an den
Einbau eines Block-RAMs denken.
Wenn man mehr Speicher oder Befehle braucht, dann kann man die
Wortbreite von 8 Bit auf z.B. 12 Bit erhöhen.
Viel Spass dabei!
LG
Alexander
Zitat von hier
https://forums.xilinx.com/t5/Virtex-Family-FPGAs-Archived/Using-asynchronous-Addr-and-Din-Block-RAM-inputs/td-p/43068
The BlockRAM is 100% synchronous, the only input timing parameters that
must be met is the setup and hold times relative to the CLK pin. If you
want to connect a write enable to the CLK pin you can do it, but this
doesn't make it an asynschronous RAM. All of the addr and data pins
still need to meet the same setup and hold times to the CLK pin
regardless of what net is driving it.
Und weiter unten:
The BlockRAM will not perform a read or a write operation unless there
is a rising transition on the CLK pin.
Also verwende einen BlockRAM und schreibe die CPU so um, dass sie da
getaktet daraus liest.
Oder verwende keinen BlockRAM. Bei 64 Bytes würde ich distributed RAM
verwenden, der geht ohne Takt.
Vielen Dank für eure Antworten.
Eigentlich wollte ich in der finalen Version das Ram einfach als Block
gegen das On-Board-Ram
Beitrag "Re: XC6SLX16 Spartan 6 Entwicklungsboard"
austauschen.
>von Alexander D. (abadu)>27.12.2019 10:45>Der bei der MCPU verwendete Speicher ist ein distributed SRAM ohne Takt.>Wenn man das durch ein Block-RAM ersetzt, dann kommen die Daten beim>Lesezugriff erst einen Takt später und nicht sofort, wie bei distributed>RAM. Entweder die CPU selbst muss geändert werden (mehr States) oder man>nimmt beim RAM die negative Taktflanke zum Zugriff.
Die einfachste Lösung wäre vielleicht, die CPU einfach mit dem halben
Takt des Ram zu versorgen.
Bei 50MHz würde ich dann eine Befehlsfrequenz von 50MHz/4 erwarten.
>> Die einfachste Lösung wäre vielleicht, die CPU einfach mit dem halben>> Takt des Ram zu versorgen.>> Bei 50MHz würde ich dann eine Befehlsfrequenz von 50MHz/4 erwarten.
... in anderen Wörter, könntest du eine Zustandsmachine mit 2 Zustände
realisieren, dann wäre es Übersichtlicher:
- Adresse für Fetch
- Fetch & Decode & Execute, und neuer PC Berechnung oder Speicher
Lese/Schreiben
Carl schrieb:> Eigentlich wollte ich in der finalen Version das Ram einfach als Block> gegen das On-Board-Ram>> Beitrag "Re: XC6SLX16 Spartan 6 Entwicklungsboard">> austauschen.
Dein Board hat den SDRAM-Speicher MT48LC16M16A2. Google sagt, dass ISE
nur DDR-Speicher über den fertigen IP-Core ansprechen kann, aber ich
kann das momentan nicht überprüfen, da ich ISE nicht installiert habe.
Auch mit fertiger IP ist das Ansteuern des SDRAMs deutlich komplexer als
die Verwendung von distributed Ram oder Block-Ram.
Carl schrieb:> Die einfachste Lösung wäre vielleicht, die CPU einfach mit dem halben> Takt des Ram zu versorgen.
Wie willst Du diese zwei Takte generieren? Ein Clock-Teiler führt nur zu
Problemen und die Erzeugung über eine PLL ist auch deutlich aufwendiger.
Wenn Du das unbedingt machen willst, dann kannst Du die CPU bei der
steigende Taktflanke loslaufen lassen und das Block-Ram bei der
fallenden Flanke. Allerdings würde ich das nicht machen, da das kein
sauberes Design ist. Bei Opencores findet man das Projekt pdp8l, dort
wird der Speicherzugriff so gemacht.
Fang deshalb mit dem distributed Ram an und wenn das sauber läuft,
kannst Du mit dem Block-Ram beginnen und danach mit dem SDRAM
weitermachen.
LG
Alexander
Geändert: Ug388 sagt, dass nur DDR/DDR2/DDR3/LPDDR Speicher über den MIG
angesprochen werden kann.
Man kann RAM natürlich auch ohne MIG verwenden. Bei SRAM geht das sehr
einfach, bei DRAM muss man sich um viele Dinge kümmern und wenn es dann
noch schnell werden soll sollte möglichst in bursts lesen und schreiben.
Aber es passt eben nicht, dass er jetzt einen asynchronen RAM ohne Takt
haben will und dann auf SDRAM der überhaupt nicht asynchron ist wechseln
will. Auch einen BRAM durch einen SDRAM ersetzen geht nicht so einfach.
Auf einen BRAM kann man zugreifen wann immer man will. Ein SDRAM braucht
Pausen für Refresh.
von Alexander D. (abadu)
>Dein Board hat den SDRAM-Speicher MT48LC16M16A2. Google sagt, dass ISE>nur DDR-Speicher über den fertigen IP-Core ansprechen kann, aber ich>kann das momentan nicht überprüfen, da ich ISE nicht installiert habe.>Auch mit fertiger IP ist das Ansteuern des SDRAMs deutlich komplexer als>die Verwendung von distributed Ram oder Block-Ram.
Ich glaube, es geht ganz ohne den IP-Core von Xilinx. Das Beispiel
befindet sich hier:
Beitrag "Re: XC6SLX16 Spartan 6 Entwicklungsboard"
Das Interface dieses RAM-Controllers hat leider noch ein paar
Ready-Synchronisationssignale für das Schreiben und Lesen, was mir die
Sache zu verkomplizieren scheint.
Um VHDL-Code zu schreiben, der zwischen den Herstellern austauschbar
ist, nimmt man wahrscheinlich am besten diesen Controller.
Vielleicht würde es Sinn machen, ein kleines Blockram hinter diesem
Interface zu verstecken, damit man den Code auf Boards ohne externes
SDRAM auch ausprobieren kann.
chris schrieb:> Ich glaube, es geht ganz ohne den IP-Core von Xilinx. Das Beispiel> befindet sich hier:> Beitrag "Re: XC6SLX16 Spartan 6 Entwicklungsboard"
Der RAM-Controller schaut wirklich einfach aus. Wieder etwas gelernt.
LG
Alexander