Forum: FPGA, VHDL & Co. 32Bit Zähler in SRAM


von Gustl B. (-gb-)


Lesenswert?

Hallo!

Da der andere Thread wohl ein irreführendes Topic hat frage ich hier 
nochmal.

Also ich habe das Nexys2 mit SDRAM von Micron der sich auch als SRAM 
betreiben lässt. 
http://download.micron.com/pdf/datasheets/psram/128mb_burst_cr1_5_p26z.pdf

Und da ich ein Spektrum im SRAM speichere will ich auch gleich in den 
einzelnen Kanälen des Spektrum im SRAM hochzählen.
Nun ist jedoch jeder Kanal 4Bytes groß und braucht so 2 Addressen im Ram 
an denen jeweis dann 16 Bits stehen.

Wenn ich also in einem Kanal um eines nach oben zählen möchte, dann lese 
ich zunächst beide Addressen in eine 32Bit Variable, erhöhe diese, und 
schreibe danach diese Variable wieder in den RAM.

Das ist ein Leseteil der an einer Addresse 16 Bit liest:
1
if c = 0 then --c ist ein zähler der von der clock hochgezählt wird
2
    ce <= '0'; --chipenable
3
    oe <= '0'; --outputenable
4
    wr <= '1'; --writeenable
5
   elsif c = 1 then
6
    ce <= '1';
7
    oe <= '1';
8
    wr <= '1';
9
    addr <= "00000000000000000010000"; --hier noch mit einer festen addresse
10
    buff(15 downto 0) <= data; --daten werden in buff gelesen

Und das geht auch, da wird nach je 10000 Takten an der Speicheraddresse 
um eines hochgezählt:
1
process begin
2
    wait until rising_edge(clock);
3
   if c < 10000 then
4
    c <= c + 1;
5
   elsif c = 10000 then
6
     c <= 0;
7
   end if;
8
    
9
   if c = 0 then
10
    ce <= '0';
11
    oe <= '0';
12
    wr <= '1';
13
   elsif c = 1 then
14
    ce <= '1';
15
    oe <= '1';
16
    wr <= '1';
17
    addr <= "00000000000000000010000";
18
    buff(15 downto 0) <= data;
19
    
20
   elsif c = 5 then
21
    buff <= buff + 1; --buff und send sind 32bit lang
22
    
23
   elsif c = 9 then
24
    send <= buff; --zum debuggen, send geht an leds
25
    ce <= '0';
26
    wr <= '0';
27
   elsif c = 10 then
28
    ce <= '1';
29
    wr <= '1';
30
    addr <= "00000000000000000010000";
31
    data <= buff(15 downto 0);
32
   elsif c = 11 then
33
    buff <= "00000000000000000000000000000000"; --buff 0 setzen
34
   end if;
35
end process;

Jedoch wenn ich jetzt jeweils zwei Lese und Schreibzugriffe mache, dann 
ist in buff(31 downto 16) und in buff(15 downto 0) immer dasselbe 
drinnen?! Bzw. was ich mir angucke also in send(31 downto 16) und in 
send(15 downto 0).
1
process begin
2
    wait until rising_edge(clock);
3
   if c < 10000 then
4
    c <= c + 1;
5
   elsif c = 10000 then
6
     c <= 0;
7
   end if;
8
    
9
   if c = 0 then
10
    ce <= '0';
11
    oe <= '0';
12
    wr <= '1';
13
   elsif c = 1 then
14
    ce <= '1';
15
    oe <= '1';
16
    wr <= '1';
17
    addr <= "00000000000000000010000";
18
    buff(15 downto 0) <= data;
19
   elsif c = 2 then
20
    ce <= '0';
21
    oe <= '0';
22
    wr <= '1';
23
   elsif c = 3 then
24
    ce <= '1';
25
    oe <= '1';
26
    wr <= '1';
27
    addr <= "00000000000000000001000";
28
     buff(31 downto 16) <= data;
29
    
30
   elsif c = 5 then
31
    buff <= buff + 1; --buff und send sind 32bit lang
32
    
33
   elsif c = 7 then
34
    send <= buff; --zum debuggen
35
    ce <= '0';
36
    wr <= '0';
37
   elsif c = 8 then
38
    ce <= '1';
39
    wr <= '1';
40
    addr <= "00000000000000000001000";
41
    data <= buff(31 downto 16);
42
   elsif c = 9 then
43
    ce <= '0';
44
    wr <= '0';
45
   elsif c = 10 then
46
    ce <= '1';
47
    wr <= '1';
48
    addr <= "00000000000000000010000";
49
    data <= buff(15 downto 0);
50
   elsif c = 11 then
51
    buff <= "00000000000000000000000000000000";
52
   end if;
53
end process;

Das ist der Code der nicht geht - man kann es vielleicht auch so sehen, 
dass in jeder der beiden Speicheraddressen synchron hochgezählt wird - 
aber warum? Was mache ich falsch? Oder spreche ich den RAM falsch an? 
Aber das mache ich eigentlich wie in dem PDF auf Seite 11 und es klappt 
ja auch für jeweils einen Zugriff.

von Duke Scarring (Gast)


Lesenswert?

Gustl Buheitel schrieb:
> Das ist der Code der nicht geht

Hast Du auch eine Testbench dazu?

Duke

von Gustl B. (-gb-)


Lesenswert?

Nein - was ist das überhaupt? Bzw. ja vermutlich etwas wo man das dann 
simuliert, das ging mit Altera Quartus recht einfach aber jetzt mit ISE 
stehe ich da ziemlich ratlos in der Landschaft. Das Meiste geht zum 
Glück ja auch so irgendwie.

Kann man denn so eine Testbench einfach machen oder ist das ein großer 
Aufwand?

Edit:

Was hat es eigentlich mit inout zu tun? Bei mir sind die Daten zum und 
vom RAM inout. Die werden beim Schreiben auch mit data <= buff(15 downto 
0);
zugewiesen - muss man das vor dem Lesen irgendwie wieder Rückgängig 
machen?
Denn scheinbar wird immer nur genau das gelesen (unabhängig der 
Speicheraddresse) was ich zuletzt in den RAM geschrieben habe.

Gustl Buheitel

von Morin (Gast)


Lesenswert?

> Was hat es eigentlich mit inout zu tun? Bei mir sind die Daten zum und
> vom RAM inout. Die werden beim Schreiben auch mit data <= buff(15 downto
> 0); zugewiesen - muss man das vor dem Lesen irgendwie wieder Rückgängig
> machen?
> Denn scheinbar wird immer nur genau das gelesen (unabhängig der
> Speicheraddresse) was ich zuletzt in den RAM geschrieben habe.

Uiuiui.... ja, das MUSS man unbedingt machen, und zwar indem man einen 
dem Port einen Vektor von 16 z-Werten zuweist (z = "tristate", nur bei 
inout gültig und bedeutet soviel wie "nichts ausgeben, sondern 
reinlesen").

Machst du das nicht, dann gibtst du Werte auf die externe Leitung 
während der RAM das auch macht. Intern im FPGA "siehst" du dann die 
Werte, die du selbst ausgibst, genau wie du es beschreibst. Aber außen 
raucht's: Wenn der FPGA und der RAM versuchen, auf einer Leitung 
verschiedene Werte auszugeben (z.B. der FPGA eine 1, der RAM eine 0), 
dann ist das ein elektrischer Kurzschluss, nur beschränkt durch den 
Widerstand der Leitung und die Limits der I/O-Treiber.

Ich würde sagen: Prüf mal, ob die Chips dabei heiß werden. "Würde", wenn 
ich dir nicht dringend davon abraten würde, die Schaltung so nochmal 
anzuwerfen ;)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Gustl Buheitel schrieb:
> Nein - was ist das überhaupt? Bzw. ja vermutlich etwas wo man das dann
> simuliert,
Eine Testbench ist ein VHDL-Modul, das keinen Port nach aussen hat. In 
dieses VHDL-Modul wird deine VHDL-Beschreibung als Komponenten 
eingebunden. Und dann kannst du den Simulator laufen lassen und dir im 
einfachsten Fall die Waveform ansehen.

Gustl Buheitel schrieb:
> Kann man denn so eine Testbench einfach machen oder ist das ein großer
> Aufwand?
Unter ISE ist das simpel:
Rechtsclick in den Project-Baum
dann "New Source" --> Testbench
und dann wird dir das Gerüst der TB schon mal angelegt.
Sieh dir dazu mal das an:
http://www.lothar-miller.de/s9y/archives/60-RS232-IO.html#extended
Darin findest du eine simple RS232-IO und die Testbench dazu. Damit 
dürfte die Idee klar werden. Das schöne an der TB:
da darfst du endlich mal alle Sprachelemente von VHDL verwenden. 
Insbesondere das "wait for xx ns"... ;-)

> z = "tristate"
Gerade hier ist VHDL ziemlich penibel und beharrt auf das große 'Z', 
denn genauso ist der Typ std_logic definiert:
type STD_ LOGIC is  (
         'U',      -- Uninitialized
         'X',      -- Forcing Unknown
         '0',      -- Forcing   0
         '1',      -- Forcing   1
         'Z',      -- High Impedance
         'W',      -- Weak     Unknown
         'L',      -- Weak     0
         'H',      -- Weak     1
         '-'       -- don’t care
        );


Das dürfte dir evtl. weiterhelfen:
Beitrag "Wie erstelle ich in VHDL Bidirektionalen Datenbus?"

von Gustl B. (-gb-)


Lesenswert?

Vielen Dank erstmal, das mit dem Z ist einleuchtend und die 
verschiedenen Zustände von STD_LOGIC kannte ich überhaupt nicht.

Diese Testbench also wie man die aufmacht und so habe ich jetzt auch 
geschafft, allerdings kann er bei mir nicht simulieren und stolpert über 
Dinge die sonst super funktionieren. Gibt es denn einen Trick wie ich 
nur eine Entity simulieren kann? Also ohne dass die anderen überhaupt 
angeguckt werden?

Genauer bricht er bei
x <= to_integer(unsigned(input));
ab - was allerdings sonst funktioniert.

Gustl Buheitel

von Gustl B. (-gb-)


Lesenswert?

Ähm ... muss ich mich eigentlich genau an das halten was hier 
http://download.micron.com/pdf/datasheets/psram/128mb_burst_cr1_5_p26z.pdf 
auf den Seiten 42/51 steht? weil ich hab das jetzt so wie auf Seite 11, 
und da gibt es doch große Unterschiede.

Gustl Buheitel

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Gustl Buheitel schrieb:
> Genauer bricht er bei
> x <= to_integer(unsigned(input));
> ab - was allerdings sonst funktioniert.
Was stört ihn daran?
Hast du die numeric.std nicht eingebunden?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Gustl Buheitel schrieb:
> Ähm ... muss ich mich eigentlich genau an das halten was hier
> http://download.micron.com/pdf/datasheets/psram/12...
> auf den Seiten 42/51 steht? weil ich hab das jetzt so wie auf Seite 11,
> und da gibt es doch große Unterschiede.
Nein, eigentlich sind da keine Unterschiede.
Nur fehlt auf der Seite 11 jeglicher exakte Zeitbezug. Das ist quasi ein 
"Übersichtsplan" für den Zugriff. Du solltest einfach mal die 
Timingwerte genauer anschauen und du wirst sehen, dass die Seite 11 
einfach nur idealisiert (und vereinfacht) dargestellt ist.

> Ähm ... muss ich mich eigentlich genau an das halten was hier
> http://download.micron.com/pdf/datasheets/psram/12...
> auf den Seiten 42/51 steht?
Ja.

von Gustl B. (-gb-)


Lesenswert?

Er schreibst:

Multiple declarations of unsigned included via multiple use clauses; 
none are made directly visible

und ok gut ... dann wird das doch aufwändiger. Aber man kann das schon 
so machen dass man das so seriell abarbeitet, also in 50 Takten oder so 
und dann in jedem Takt genau schreibt was an den RAM geht?

Ist nur doof, weil ein Takt der 50MHZ Clock ist 20ns lang, und wenn ich 
da jetzt Timing Sachen habe die drunter liegen, dann geht das nicht, und 
auch, dass in der Timing Grafik das Wait vorkommt und UB/LB einmal '1' 
sein muss finde ich komisch, aber ok, werde ich einbauen.

Gustl Buheitel

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Gustl Buheitel schrieb:
> Multiple declarations of unsigned included via multiple use clauses;
> none are made directly visible
Welche libs sind am Anfang der TB eingebunden?
Da würde mich der Code der TB schon interessieren...

von Gustl B. (-gb-)


Lesenswert?

Ah! Ok also ich hatte bei der TB das ganze Projekt ausgewählt. Jetzt hab 
ich mal nur die Entity RAM genommen und da geht es dann ... wunderbar! 
Dann versuche ich also hier genau das Timingdiagramm nachzubilden.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Gustl Buheitel schrieb:
> Dann versuche ich also hier genau das Timingdiagramm nachzubilden.
Nein, du solltest das nicht nachbilden sondern einfach nur 
verstehen...
Bei manchen Signalen ist es schlicht egal, wann sie kommen, das siehst 
du aber nicht in irgendeinem Bild, sondern nur, wenn du die 
Zahlenwerte mit einbeziehst.

von Gustl B. (-gb-)


Lesenswert?

Ja ... aber ich will doch mit dem RAM reden können?! Klar dass manche 
Signale Spielraum haben oder auch dauerhaft '0' sein können, aber 
zumindest ungefähr muss ich das doch so nachbauen - die Toleranz gibt es 
ja in der Timingtabelle. Oder geht das ganze deutlich einfacher? Also 
so, dass man nur sehr wenig beachten muss?

Diese Simulation ist auch sowas, da sehe ich zwar jetzt die ganzen 
Signale, aber die bleiben immer gleich weil sich meine Clock da nie 
ändert?! Muss ich da irgendwie selbst einen Takt reinmalen oder wie 
funktioniert das?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Gustl Buheitel schrieb:
> Muss ich da irgendwie selbst einen Takt reinmalen oder wie
> funktioniert das?
Nein, du mußt in der Testbench einen Takt generieren. Der Link vom 
Beitrag "Re: 32Bit Zähler in SRAM" zeigt dir wie das 
geht. Z.B. so:
1
   signal clk : std_logic := '0';
2
  :
3
  :
4
   clk <= not clk after 20 ns; -- f = 50MHz

von Gustl B. (-gb-)


Lesenswert?

Ok Danke! Also eigentlich sollte es simulieren, jedoch schnappt sich der 
ISim erstmal recht schnell den kompletten RAM (2gb) und dann über eine 
Stunde hinweg noch noch allmählich weitere 300MB und kratzt auf der 
Platte rum wie verrückt um mir jetzt zu präsentieren:

The simulator has terminated in an unexpected manner.

Immerhin geht das SRAM anprechen so halbwegs, ich weiss zwar noch nicht 
wie ich das richtig mache, aber mit vielen Schreib und Lesefehlern kann 
man jetzt erkennen, dass da eine 32Bit Zahl hochzehählt wird (weil es 
auf den niedrigeren Bits deutlich schneller blinkt wie auf den oberen).

von Gustl B. (-gb-)


Lesenswert?

So also es geht alles wie es soll.

Zuerst hate ich ja noch keinen RAM. Da hatte ich das Spektrum im FPGA 
als Array und das war mangels Platz auch kleiner und ich konnte das über 
RS232 rausschieben. Das war 4KByte und ich hatte erstmal Probleme das 
komplett über RS232 rauszubekommen - bis ich dann das Board nicht über 
USB sondern über Netzteil angeschlossen hatte.

So da war der RS232 am Rechner (weil der Laptop kein RS232 hat) ein USB 
Adapter (USB-Serial CH340). Und mit dem hat das auch bei 4KBytes gut 
geklappt.

Jetzt ist mein Spektrum größer (16Kbytes und nochmal 4Mbytes), der Code 
für RS232 ist gleich geblieben. Und es ging nicht mehr, es fehlen dann 
einfach einzelne Bytes.
Wenn ich das aber hier an einen alten Dell Optiplex Tower Rechner 
anschließe mit richtiger RS232, dann geht alles super - auch 4MBytes 
(dauert aber 8 Minuten).
Also wenn Jemand Probleme mit RS232 und vielen Daten hat dann kann auch 
so ein USB Adapter schuld sein.

Gustl

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
Noch kein Account? Hier anmelden.