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
> 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).
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?
> 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.
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.
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; |
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...
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...
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.
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...
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ß
Ich würde die inistialisierung alerdings fest eincodieren... das wird dir später den Zugriff aufs BRAM erleichtern...
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?
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?"
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?
Wenn das der Fall sein sollte, was müsste ich ändern, damit ich wirklich BRam erhalte?
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.
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"?
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?
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.