Hallo, ich habe gerade das Problem, das mir auf meinem FPGA, trotz identischer Ansteuerung, der Inhalt eines Block RAMs mit einem Takt Verzögerung ausgegeben wird, während die Daten des anderen Block RAMs genau richtig ausgegeben werden. Könnte es sein, dass das Synthesetool (iCEcube2) einfach ein Flip-Flop platziert, ohne das es in VHDL beschrieben wurde? Oder jemand vielleicht einen anderen Tip?
Stephan C. schrieb: > ich habe gerade das Problem, das mir auf meinem FPGA, trotz identischer > Ansteuerung, der Inhalt eines Block RAMs mit einem Takt Verzögerung > ausgegeben wird, während die Daten des anderen Block RAMs genau richtig > ausgegeben werden. Im log sollte stehen mit welchen Parametern (bsp Output FF-stages) der embedded RAM betrieben wird. Ferner zeigt das scope bild sicher nicht, wann die Signales aus dem FPGA-internen Ram purzeln, sondern wann sie aus den zum Debugging benutzen IO-Pins tröpfeln. Gut möglich das bei rausrouten der Signale die Verzögerung entsteht. Oder da die Signale nicht beschriftet sind, du dir selbst ins Knie schiesst und die falschen Signale miteinander vergleichst. Was sagt den die Simu der debug-pins ?
Hallo, Eine Simulation hatte ich noch nicht am Laufen, da ich auf eine Antwort von Lattice warte, weil die mitgelieferten Sourcen mit Fehlern kompilieren. Bei den Oszi-Bildern ist das obere Signal das Fsync, dann kommen die Daten, ADDR(1) und dann ADDR(0). Bei dem Bild TDM_ADR_ROM kann man sehr gut erkennen, dass beim Fsync-Impuls die Adresse 0 anliegt, die Daten, die fest im Block RAM definiert sind aber einen Takt verzögert augegeben werden. Bei dem I2S_ADR_ROM wird bei der Fsync-Flanke gleich das richtige Datenbit ausgegeben. Einen Unterschied gibt es doch, der Block RAM für I2S wird mit 3,072 MHz betrieben, während der Block RAM für TDM mit 6,144MHz betrieben wird. Wegen FF hinter Block RAM habe ich im Floor Planner geguckt und da ist z.B. ein SB_DFF Element drin, das auf den IO mit dem richtigen Timing führt.
Ist allerdings merkwürdig, dass wenn ich den IO anclicke, ein Airwire zum Block RAM und eins zum FF geht.
Noch eine Anmerkung: die Ausgangsports der Block RAMs habe ich zumindest im VHDL-Code direkt auf die Ausgänge gelegt.
Hast du die RAMs selbe erzeugt oder mit dem Wizard ? könnte es sein daß eine davon "registered" Ausgänge hat und die Andere nicht ?
Hallo, nein ich habe die RAM-Blöcke selber instantiiert. Die Signale der Readports führen direkt auf jeweils einen Ausgang. Eine weitere Sache ist auch noch interessant, wenn ich den Code so umstelle, dass in die RAMs reinschreibe, bevor ich sie auslese, dann werden die Daten mit einem weiteren Takt Verzögerung ausgelesen.
1 | Ram2048x2_inst_0 : SB_RAM2048x2NRNW |
2 | generic map ( |
3 | INIT_0 => X"0000000000000000000000000000000000000F0F0F0F0F0F00000F0F0F0F0F0F", |
4 | --INIT_0 => X"0000000000000000000000000000000000000000000000000000000000000000",
|
5 | INIT_1 => X"0000000000000000000000000000000000000000000000000000000000000000", |
6 | INIT_2 => X"0000000000000000000000000000000000000000000000000000000000000000", |
7 | INIT_3 => X"0000000000000000000000000000000000000000000000000000000000000000", |
8 | INIT_4 => X"0000000000000000000000000000000000000000000000000000000000000000", |
9 | INIT_5 => X"0000000000000000000000000000000000000000000000000000000000000000", |
10 | INIT_6 => X"0000000000000000000000000000000000000000000000000000000000000000", |
11 | INIT_7 => X"0000000000000000000000000000000000000000000000000000000000000000", |
12 | INIT_8 => X"0000000000000000000000000000000000000000000000000000000000000000", |
13 | INIT_9 => X"0000000000000000000000000000000000000000000000000000000000000000", |
14 | INIT_A => X"0000000000000000000000000000000000000000000000000000000000000000", |
15 | INIT_B => X"0000000000000000000000000000000000000000000000000000000000000000", |
16 | INIT_C => X"0000000000000000000000000000000000000000000000000000000000000000", |
17 | INIT_D => X"0000000000000000000000000000000000000000000000000000000000000000", |
18 | INIT_E => X"0000000000000000000000000000000000000000000000000000000000000000", |
19 | INIT_F => X"0000000000000000000000000000000000000000000000000000000000000000" |
20 | )
|
21 | port map ( |
22 | RDATA => TX_RD_DAT, |
23 | RADDR => I2S_ADR, |
24 | RCLKN => bclk_i2s_i, |
25 | RCLKE => const_one, |
26 | RE => const_one, |
27 | WADDR => TDM_ADR, |
28 | WCLKN => bclk_tdm_i, |
29 | WCLKE => const_one, |
30 | WDATA => TX_WR_DAT, |
31 | WE => const_zero |
32 | );
|
33 | |
34 | |
35 | Ram2048x2_inst_2 : SB_RAM2048x2NRNW |
36 | generic map ( |
37 | INIT_0 => X"0000000000000000000000000000000000000F0F0F0F0F0F00000F0F0F0F0F0F", |
38 | --INIT_0 => X"0000000000000000000000000000000000000000000000000000000000000000",
|
39 | INIT_1 => X"0000000000000000000000000000000000000000000000000000000000000000", |
40 | INIT_2 => X"0000000000000000000000000000000000000000000000000000000000000000", |
41 | INIT_3 => X"0000000000000000000000000000000000000000000000000000000000000000", |
42 | INIT_4 => X"0000000000000000000000000000000000000000000000000000000000000000", |
43 | INIT_5 => X"0000000000000000000000000000000000000000000000000000000000000000", |
44 | INIT_6 => X"0000000000000000000000000000000000000000000000000000000000000000", |
45 | INIT_7 => X"0000000000000000000000000000000000000000000000000000000000000000", |
46 | INIT_8 => X"0000000000000000000000000000000000000000000000000000000000000000", |
47 | INIT_9 => X"0000000000000000000000000000000000000000000000000000000000000000", |
48 | INIT_A => X"0000000000000000000000000000000000000000000000000000000000000000", |
49 | INIT_B => X"0000000000000000000000000000000000000000000000000000000000000000", |
50 | INIT_C => X"0000000000000000000000000000000000000000000000000000000000000000", |
51 | INIT_D => X"0000000000000000000000000000000000000000000000000000000000000000", |
52 | INIT_E => X"0000000000000000000000000000000000000000000000000000000000000000", |
53 | INIT_F => X"0000000000000000000000000000000000000000000000000000000000000000" |
54 | )
|
55 | port map ( |
56 | RDATA => RX_RD_DAT, |
57 | RADDR => TDM_ADR, |
58 | RCLKN => bclk_tdm_i, |
59 | RCLKE => const_one, |
60 | RE => const_one, |
61 | WADDR => I2S_ADR, |
62 | WCLKN => bclk_i2s_i, |
63 | WCLKE => const_one, |
64 | WDATA => RX_WR_DAT, |
65 | WE => const_zero |
66 | );
|
:
Bearbeitet durch User
Paar kleine Anmerkungen von mir, da ich erst mit den EBRs kämpfen durfte ... 1. Verwende Radiant für die ICE40UPxk (bessere IDE, Timing-Analyse ist besser) 2. Du kannst das RAM gleich in VHDL als array instanziieren:
1 | -- state memory
|
2 | type mem_type is array ((STACK_SIZE*128)-1 downto 0) of std_logic_vector(17 downto 0); |
3 | signal mem0 : mem_type; |
4 | |
5 | |
6 | attribute syn_ramstyle: string; |
7 | attribute syn_ramstyle of mem0: signal is "rw_check"; |
Das EBR wird von Radiant wunderbar erkannt. 3. zusätzliche Register hatte ich dann keine. Innerhalb eines States konnte ich einfach per mem0(addr) lesend und schreibend zugreifen. 4. Wenn man etwas macht, was EBRs nicht können, merkt man das nach dem mappen, wenn plötzlich ein Haufen Register mehr benötigt werden und dafür weniger EBRs.
:
Bearbeitet durch User
Hm, wenn ich es richtig verstehe, wird in keines der beiden Blöcke geschrieben, da das write enable WE auf '0' liegt. Oder ist es low active? Dann sehe ich da zwei verschiedenene Takte pro RAM. Verschiedenene Taktdomainen sind immer ein guter Grund für ein Tool zusätzlich FF zur synchronisation. einzubauen. Ob und was das Tool eingebaut hat, steht üblicherweise im Log-file, das sollte aussagekräftiger sein als das Code-schnipsel. Aus dem wird auch ersichtlich, ob und welche Generics auf default value sind und welche Wirkung das hat. Und es stellt sich die Frage nach der Phasenlage zwischen den beiden Referenztakten in den Scope-Bild. Mglw. vermeint man einen Unterschied zu sehen, wo keiner ist. Eine Simulation kann auch darüber mehr Klarheit verschaffen.
Hallo, @Mampf F.: ich habe aber ein iCE40 Ultra FPGA (iCE5LP). Soweit ich weiß, werden nur die iCE40 Ultra Plus FPGAs von Radiant unterstützt. Die iCE5LP reichen vom Speed und von der Funktionalität vollkommen aus und bei Bedarf kann man dort bei dem QFN-Package Bausteine mit mehr Logikzellen bestücken. Preislich sind sie auch ok. @C. A. Rotwang: ja bei dem Codeschnippsel habe ich den RAM als ROM betrieben, um sehen, wie die Daten aus dem RAM gelesen werden. Davon sind auch die Bilder ganz oben. Ich nehme ja extra einen Dual-Port-RAM, damit ich dort zwei unterschiedliche Takte anlegen kann. Im Grunde genommen, will ich mir aus einem TDM-Frame die ersten beiden Kanäle von vier herauspicken und über I2S ausgegeben. Die Fsync-Frame-Dauer bleibt dieselbe aber die I2S-Bitclock läuft nur halb so schnell, wie die TDM-Bitclock. Der zweite Block-RAM ist dazu da, einen I2S-Stream zwischenzuspeichern und ihn über TDM auszugeben. Theoretisch kann ich den RAM auch nur mit der TDM-Bitclock betreiben. Die I2S-Bitclock wird FPGA-intern sowieso aus der TDM-Bitclock erzeugt.
:
Bearbeitet durch User
Hab mal kurz in die Lattice BRAM Blöcke reingelesen, da scheint es tatsächlich nicht so viele Einstellungen wie anderswo zu geben. Bis auf die Taktsynchronisation zwischen den verschiedenen RAM-Ports und den debugports fällt mir daher keine Möglichkeit einer ungewollten FF-Verzögerung ein. Fall es nur um lineares ein und auslesen geht, könnte man auch ein FIFO Makro einsetzen, bei einem solchen kann man davon ausgehen, das nötige Verzögerungen fest. Alternative Debugmöglichkeiten neben den rauslegen von Steuerpins könnte man auch noch erwägen, beispielsweise in beide gleiches Muster einschreiben und ein Komperator am Ausgang.
Stephan C. schrieb: > Eine Simulation hatte ich noch nicht am Laufen, da ich auf eine Antwort > von Lattice warte, weil die mitgelieferten Sourcen mit Fehlern > kompilieren. Erwarte nicht zuviel vom Lattice-Support. Ich habe letztens eine Bug gemeldet (Ein Parallel-Seriell-Wandler lief falschrum. Die Simulation ging, LSE ging, aber Synplify baut Mist.) Die haben den nach einer Weile einfach kommentarlos zugemacht. Duke
Hallo, zwischenzeitlich hatte ich Kontakt mit dem Support. Vom Support habe ich ein paar Anregungen bekommen, eine wirkliche Hilfe waren die aber leider nicht. Was mir aber schon mal geholfen hat, war die Definition eines Clock-Timing-Constraints für die Synthese. Ich dachte vorher, dass ein Timing-Constraint für das P&R reichen würde. So konnte zumindest eine Verzögerung von einem Takt in beide Richtungen beseitigt werden. Leider blieb dann noch eine Verzögerung von einem Takt in eine Richtung übrig, die dann jetzt durch das Starten des Lesevorgangs bei Adresse '1' anstatt bei Adresse '0' beseitigt wurde. Vom Support bekam ich dazu noch den Tip, ein IO-Element selber zu instantiieren. Getestet habe ich das leider noch nicht.
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.