Da ich ein günstiges Spartan 6 Board bekommen habe Beitrag "XC6SLX16 Spartan 6 Entwicklungsboard" möchte ich zur Übung die minimalistische CPU von Tim implementieren https://github.com/cpldcpu/MCPU Als erstes brauche ich aber ein Blockram als Modul. Lothar Miller hat hier eine sehr schöne Erkärung http://www.lothar-miller.de/s9y/archives/20-RAM.html#extended aber es fehlt leider die Testbench. Hat jemand eine Testbench für das SRAM?
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 | WAIT FOR TbPeriod; |
4 | a<="000000"; |
5 | d<="00000000"; |
6 | we<='1'; |
7 | WAIT FOR TbPeriod; |
8 | reset <= '0'; |
9 | WAIT FOR TbPeriod; |
10 | reset <= '1'; |
11 | WAIT FOR TbPeriod; |
12 | a<="000000"; |
13 | d<="00000000"; |
14 | we<='0'; |
15 | WAIT FOR TbPeriod; |
16 | we<='1'; |
17 | WAIT FOR TbPeriod; |
18 | a<="000000"; |
19 | d<="01010101"; |
20 | we<='0'; |
21 | WAIT FOR TbPeriod; |
22 | we<='1'; |
23 | |
24 | end process; |
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?
:
Bearbeitet durch User
>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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.