www.mikrocontroller.net

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


Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

entity coprocessor is
  generic 
  (
    bram_addr_width  : natural := 8;
    bram_data_width  : natural := 32
   );
        
  port 
  (
    FSL_Clk        : in  std_logic;
    FSL_Rst        : in  std_logic;
    FSL0_S_CLK      : out  std_logic;
    FSL0_S_READ      : out  std_logic;
    FSL0_S_DATA      : in  std_logic_vector(0 to 31);
    FSL0_S_CONTROL    : in  std_logic;
    FSL0_S_EXISTS    : in  std_logic;
    FSL0_M_CLK      : out  std_logic;
    FSL0_M_WRITE    : out  std_logic;
    FSL0_M_DATA      : out  std_logic_vector(0 to 31);
    FSL0_M_CONTROL    : out  std_logic;
    FSL0_M_FULL      : in  std_logic
    );
);

architecture EXAMPLE of coprocessor is

   type STATE_TYPE is (Idle, Read_Inputs, Write_Outputs);
   signal state        : STATE_TYPE;
  
  -- BRAM
  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;
  signal bram_addr : std_logic_vector (bram_data_width-1 downto 0) := x"00000000";
  signal bram_data : std_logic_vector (bram_data_width-1 downto 0) := x"00000000";

begin
   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';
  
   FSL0_M_Data <= bram_data;

   The_SW_accelerator : process (FSL_Clk) is
   begin  -- process The_SW_accelerator
    if FSL_Clk'event and FSL_Clk = '1' then     -- Rising clock edge
      if FSL_Rst = '1' then               -- Synchronous reset (active high)
        -- CAUTION: make sure your reset polarity is consistent with the
        -- system reset polarity
      
      -- BRAM Init
      if bram_addr < 2**bram_addr_width then  
        BRAM(to_integer(unsigned(bram_addr))) <= bram_addr;
       bram_addr <= bram_addr + 1;
        end if;

        state        <= Idle;
      else
        case state is
          when Idle =>
            if (FSL0_S_Exists = '1') then
              state       <= Read_Inputs;
            end if;

          when Read_Inputs =>
            if (FSL0_S_Exists = '1') then
          --
          bram_data <= BRAM(conv_integer(FSL0_S_Data));
          --
              state <= Write_Outputs;
            end if;

          when Write_Outputs =>
            if (FSL0_M_Full = '0') then
          state <= Idle;
            end if;
        end case;
      end if;
    end if;
   end process The_SW_accelerator;
end architecture EXAMPLE;

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

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

Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal eine allgemeine Frage zum BRam und VHDL.

Mit:
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;

signal bram_num   : std_logic_vector (0 to bram_addr_width);
definiere ich mein Ram.
Momentan kann ich leider nur mit:
BRAM(conv_integer(bram_num)) <= x"0F0F0F0F";
oder
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?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?"

Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: ChrisB (Gast)
Datum:

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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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"?

Autor: ChrisB (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: ChrisB (Gast)
Datum:

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.