Forum: FPGA, VHDL & Co. BRam im eigenen IP Core initialisieren


von ChrisB (Gast)


Lesenswert?

Hallo an Alle,

ich gerade dabei einen eigenen IP Core zu erstellen, der mit mehr als 
einem Microblaze per FSL kommunizieren können soll.
Mehrere FSL Busse habe ich inzwischen in den IP Core reinbekommen, sogar 
so, dass man die Anzahl per GUI einstellen kann.
Der nächste Schritt wäre nun Block RAM zu verwenden.
Um Block Ram zu instanzieren habe ich folgendes gemacht:

type bram_type is array ((2**bram_addr_width)-1 downto 0) of 
std_logic_vector(bram_data_width-1 downto 0);

signal BRAM : bram_type;

Bevor ich das Block Ram nun benutze würde ich dieses gerne 
initialisieren. Das Problem dabei: Ich möchte es nicht beim Laden des 
FPGA's mit initialisieren, sondern immer dann, wenn das reset-Signal 
meines IP-Cores auf '1' geht. Da tut sich mir die Frage auf, ob das 
überhaupt möglich ist, da es ja eine bestimmte Zeit dauern würde, bis 
das BRam komplett initialisiert ist und ich nicht sicherstellen kann, 
dass das reset-Signal mindestens diese Zeit auf '1' bleibt.

Für die Initialisierung habe ich folgendes versucht:

The_SW_accelerator : process (FSL_Clk) is
   begin  -- process The_SW_accelerator
    if FSL_Clk'event and FSL_Clk = '1' then
      if FSL_Rst = '1' then
        for i in 0 to (2**mbx_addr_width)-1 loop
          BRAM(to_integer(unsigned(i))) <= i;
        end loop;
      end if;
    end if;
end process;

Dies ist ein verkürzter Abschnitt des VHDL-Codes. Leider kommt dabei 
folgender Fehler, der sich auf die zeile des BRam Zugriffs bezieht:
ERROR:HDLParsers:854 - The expression can not be converted to type 
unsigned.

Mache ich da etwas falsch? Ich verstehe das Problem an der Stelle nicht 
so ganz.

Ist es überhaupt möglich per reset-Signal das BRam mit 0, 1, 2, 3, 4... 
usw. zu belegen?

Wenn es da eine Möglichkeit gibt wäre ich euch sehr dankbar, mir ein 
paar Tips zu geben.

lg,
ChrisB

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


Lesenswert?

> Da tut sich mir die Frage auf, ob das
> überhaupt möglich ist, da es ja eine bestimmte Zeit dauern würde, bis
> das BRam komplett initialisiert ist und ich nicht sicherstellen kann,
> dass das reset-Signal mindestens diese Zeit auf '1' bleibt.
Dann mußt du hergehen und mit dem Reset die Initialisierung starten. 
allerdings solltest du erst dann auf das BRAM zugreifen, wenn di 
Initialisierung beendet ist. Wie willst du übrigens dann später mal 
irgendwas anderes in das BRAM bekommen?

> The expression can not be converted to type unsigned.
Ja, klar: i ist ein integer....
Du solltest es also eher so machen:

BRAM(i) <= std_logic_vector(to_unsigned(i,bram_data_width));

> Ist es überhaupt möglich per reset-Signal das BRam mit 0, 1, 2, 3, 4...
> usw. zu belegen?
Nicht so ohne weiteres, du mußt jede Zelle per Handschlag auf den Wert 
setzen.
Eine Möglichkeit wäre eine komplette Neuinitialisierung des FPGAs (via 
PROG_B) und die Verwendung von Defaultwerten (wie dort in der 
Sinus-Tabelle: http://www.lothar-miller.de/s9y/categories/31-DDFS).

von ChrisB (Gast)


Lesenswert?

Danke für deine Antwort.

Ja, so habe ich es auch gerade gelöst. Mit dem Reset wird die 
Initialisierung gestartet und nach Fertigstellung setze ich ein Signal, 
welches ich nach außen führe, auf '1'. An Hand dieses Signals wissen die 
angeschlossenen Microblazes dann, ab wann diese auf meinen IP Core 
zugreifen dürfen.

Wie meinst du das, wie ich später mal was anderes ins BRam bekommen 
will?
Nach der Initialisierung soll dann per FSL was ins BRam geschrieben 
werden können. Sollte doch gehen oder?

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


Lesenswert?

> Wie meinst du das, wie ich später mal was anderes ins BRam bekommen will?
Du hast derzeit einen "Reset-Schreibzugriff":
BRAM(i) <= std_logic_vector(to_unsigned(i,bram_data_width));
Hier mußt du noch eine Möglichkeit einbauen, um mit deiner Adresse und 
deinen Daten an das BRAM zu kommen.

von ChrisB (Gast)


Lesenswert?

Ja, ich hatte vor dass der weitere Zugriff in einer State-Machine 
abläuft, sobald das reset-Signal auf '0' ist und die Initialisierung 
abgeschlossen ist.

Zunächst möchte ich dann (aus der Sicht meines IP Cores) die über den 
Slave empfangenen Daten als Adresse des BRams verwenden und den Inhalt 
des BRams an den Master FSL raus zu schicken.

Das wäre so mein erster Test um zu gucken, ob ich das BRam auslesen 
kann.
Danach würde ich versuchen auch auf das BRam zu schreiben, aber das ist 
erst der nächste Schritt.

von ChrisB (Gast)


Lesenswert?

Leider habe ich folgendes Problem bezüglich meines IP Cores:
Der angeschlossene Microblaze macht immer ein put-Befehl, um die Adresse 
zu übermitteln, wartet bis fsl_isinvalid '0' liefert, macht dann solange 
get-Befehle bis fsl_isinvalid '0' liefert.
Das Ganze mache ich in einer Schleife mit nem Delay von ner halben 
Sekunde und gebe dem put-Befehl einen Zählerwert mit.
Leider kommt beim Get Befehl 16 mal 0 zurück und danach hängt er sich 
auf, da fsl_isinvalid nicht mehr 0 wird.
Vermutlich ist nach 16 Put-Befehlen der 16-stufige Fifo voll, mein IP 
Core arbeitet nicht richtig, da die Daten nicht abgeholt werden.
Hat jemand eine Idee, was falsch sein könnte?
1
entity coprocessor is
2
  generic 
3
  (
4
    bram_addr_width  : natural := 8;
5
    bram_data_width  : natural := 32
6
   );
7
        
8
  port 
9
  (
10
    FSL_Clk        : in  std_logic;
11
    FSL_Rst        : in  std_logic;
12
    FSL0_S_CLK      : out  std_logic;
13
    FSL0_S_READ      : out  std_logic;
14
    FSL0_S_DATA      : in  std_logic_vector(0 to 31);
15
    FSL0_S_CONTROL    : in  std_logic;
16
    FSL0_S_EXISTS    : in  std_logic;
17
    FSL0_M_CLK      : out  std_logic;
18
    FSL0_M_WRITE    : out  std_logic;
19
    FSL0_M_DATA      : out  std_logic_vector(0 to 31);
20
    FSL0_M_CONTROL    : out  std_logic;
21
    FSL0_M_FULL      : in  std_logic
22
    );
23
);
24
25
architecture EXAMPLE of coprocessor is
26
27
   type STATE_TYPE is (Idle, Read_Inputs, Write_Outputs);
28
   signal state        : STATE_TYPE;
29
  
30
  -- BRAM
31
  type bram_type is array ((2**bram_addr_width)-1 downto 0) of std_logic_vector(bram_data_width-1 downto 0);
32
  signal BRAM : bram_type;
33
  signal bram_addr : std_logic_vector (bram_data_width-1 downto 0) := x"00000000";
34
  signal bram_data : std_logic_vector (bram_data_width-1 downto 0) := x"00000000";
35
36
begin
37
   FSL0_S_Read  <= FSL0_S_Exists   when state = Read_Inputs   else '0';
38
   FSL0_M_Write <= not FSL0_M_Full when state = Write_Outputs else '0';
39
  
40
   FSL0_M_Data <= bram_data;
41
42
   The_SW_accelerator : process (FSL_Clk) is
43
   begin  -- process The_SW_accelerator
44
    if FSL_Clk'event and FSL_Clk = '1' then     -- Rising clock edge
45
      if FSL_Rst = '1' then               -- Synchronous reset (active high)
46
        -- CAUTION: make sure your reset polarity is consistent with the
47
        -- system reset polarity
48
      
49
      -- BRAM Init
50
      if bram_addr < 2**bram_addr_width then  
51
        BRAM(to_integer(unsigned(bram_addr))) <= bram_addr;
52
       bram_addr <= bram_addr + 1;
53
        end if;
54
55
        state        <= Idle;
56
      else
57
        case state is
58
          when Idle =>
59
            if (FSL0_S_Exists = '1') then
60
              state       <= Read_Inputs;
61
            end if;
62
63
          when Read_Inputs =>
64
            if (FSL0_S_Exists = '1') then
65
          --
66
          bram_data <= BRAM(conv_integer(FSL0_S_Data));
67
          --
68
              state <= Write_Outputs;
69
            end if;
70
71
          when Write_Outputs =>
72
            if (FSL0_M_Full = '0') then
73
          state <= Idle;
74
            end if;
75
        end case;
76
      end if;
77
    end if;
78
   end process The_SW_accelerator;
79
end architecture EXAMPLE;

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

FSL_READ und FSL_WRITE müssen bedient werden damit der FSL Bus "weiss" 
das was geschrieben/gelesen werden soll/kann... da muß man nix 
signalisieren oder so...

von ChrisB (Gast)


Lesenswert?

Ja wird das denn nicht an folgender Stelle gemacht:

[vhdl]

FSL0_S_Read  <= FSL0_S_Exists   when state = Read_Inputs   else '0';
FSL0_M_Write <= not FSL0_M_Full when state = Write_Outputs else '0';

[\vhdl]

Das habe ich aus dem Beispiel übernommen, das Xilinx generiert, wenn man 
den Coprocessor-Wizard benutzt.

Im übrigen muss ich mich korrigieren. Hatte nen kleinen Fehler im 
C-Code. Es ist so, dass ich den put-Befehl mache, daraufhin dne 
get-Befehl wie oben beschrieben, aber dass sich schon beim ersten 
Durchlauf nichts mehr tut, da das fsl_isinvalid liefert nach dem 
get-Befehl immer eine '1'. Also siehts so aus, als würde mein IP Core 
nichts auf den bus schreiben...

von ChrisB (Gast)


Lesenswert?

Ich glaube das Problem hat sich gerade gelöst... es lag an der falsch 
polarisierten Reset-Leitung, auf die man extra achten sollte. Trotzdem 
danke für eure Hilfe.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

ChrisB schrieb:
> C-Code. Es ist so, dass ich den put-Befehl mache, daraufhin den
Zeig mal den Code... wichtig ist u.A. das du erst einmal was schreibst 
und dann liest, sonst lauft deine Statemachine nicht weiter.
Das invalid, ist mein ich auch nur bei non_blocking interessant.
Ich würde auch erstmal konstante Werte geben nicht das das Problem an 
deinem BRAM Code liegt...

von ChrisB (Gast)


Lesenswert?

Ja, das war mein erster Fehler... Jetzt läuft alles rund. Ich lege eine 
Adresse mit put an und mit get bekomme ich den vorinitialisierten Wert 
aus dem BRam.
Soweit so gut, dann kanns jetzt weitergehn.

Danke nochmal!

Gruß

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Ich würde die inistialisierung alerdings fest eincodieren... das wird 
dir später den Zugriff aufs BRAM erleichtern...

von ChrisB (Gast)


Lesenswert?

Mal eine allgemeine Frage zum BRam und VHDL.

Mit:
1
type bram_type is array ((2**bram_addr_width)-1 downto 0) of std_logic_vector(bram_data_width-1 downto 0);
2
signal BRAM : bram_type;
3
4
signal bram_num   : std_logic_vector (0 to bram_addr_width);
definiere ich mein Ram.
Momentan kann ich leider nur mit:
1
BRAM(conv_integer(bram_num)) <= x"0F0F0F0F";
oder
1
BRAM(to_integer(unsigned(bram_num))) <= x"0F0F0F0F";
auf das BRam zugreifen, da bram_num vom Typ std_logic_vector ist.
Welches der beiden Möglichkeiten ist die bessere, bzw. eventuell 
einfacher und platzsparender im Design? Hat die Konvertierung von 
std_logic_vector zu integer überhaupt einfluss auf das Design?
Gibt es eine Möglichkeit das BRam direkt durch einen std_logic_vector zu 
adressieren, anstatt eines integers?

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


Lesenswert?

Nimm die zweite mit den numeric_std Lib.
Die andere ist von der uralten STD_LOGIC_ARITH Lib von Synopsis 
abhängig.
Siehe auch den Beitrag "Redundanz in den IEEE Libs / Welche kann ich weg lassen?"

von ChrisB (Gast)


Lesenswert?

Alles klar, danke.

Noch eine andere Frage die sich mir gerade auftut: Im EDK sehe ich in 
der Design Summary, dass für mein coprozessor ein Haufen FlipFlops und 
LUT's benutzt werden, jedoch kein BRam.
Wird mein bram aus dem obigen Beispiel tatsächlich aus FlipFlop's und 
LUT's aufgebaut anstatt aus wirklichem BRam?

von ChrisB (Gast)


Lesenswert?

Wenn das der Fall sein sollte, was müsste ich ändern, damit ich wirklich 
BRam erhalte?

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


Lesenswert?

Lies das im XST.pdf nach.
Als Tipp: die Leseadresse muß registriert werden.

> Wird mein bram aus dem obigen Beispiel tatsächlich aus FlipFlop's und
> LUT's aufgebaut anstatt aus wirklichem BRam?
Ja, sowas nennt sich Distributed RAM.

von ChrisB (Gast)


Lesenswert?

Ich bin eigentlich der Meinung, dass ich es gemacht habe, wie es im 
xst.pfd steht. Was meinst du mit "die Leseadresse muss registriert 
werden"?

von ChrisB (Gast)


Lesenswert?

Meinst du damit, dass ich die Leseadresse bei einem Takt erst in ein 
Register schreiben muss und erst beim nächsten Takt mit der Adresse aus 
diesem Register auf das BRam zugreifen kann?
Muss das beim Schreiben nicht gemacht werden?

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


Lesenswert?

Auf das Lesen kommt es an. Dort siehst du die Unterschiede:
http://www.lothar-miller.de/s9y/archives/20-RAM.html

EDIT:
> Meinst du damit, dass ich die Leseadresse bei einem Takt erst in ein
> Register schreiben muss und erst beim nächsten Takt mit der Adresse aus
> diesem Register auf das BRam zugreifen kann?
Richtig.
> Muss das beim Schreiben nicht gemacht werden?
Nein, das Schreiben ist sowieso schon synchron.

von ChrisB (Gast)


Lesenswert?

Oha, ich glaube das macht mein Code doch etwas komplexer als ich 
dachte... naja ich werds mal versuchen. Danke für deine Hilfe.

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.