mikrocontroller.net

Forum: FPGA, VHDL & Co. Lattice iCE40 Ultra Block RAM Problem


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Stephan C. (stephan_c)
Datum:
Angehängte Dateien:

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

Autor: KristalKugelSchwarzSeher (Gast)
Datum:

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

Autor: Stephan C. (stephan_c)
Datum:

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

Autor: Stephan C. (stephan_c)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist allerdings merkwürdig, dass wenn ich den IO anclicke, ein Airwire 
zum Block RAM und eins zum FF geht.

Autor: Stephan C. (stephan_c)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch eine Anmerkung: die Ausgangsports der Block RAMs habe ich zumindest 
im VHDL-Code direkt auf die Ausgänge gelegt.

Autor: Ale (Gast)
Datum:

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

Autor: Stephan C. (stephan_c)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
Ram2048x2_inst_0 : SB_RAM2048x2NRNW  
generic map (
INIT_0 => X"0000000000000000000000000000000000000F0F0F0F0F0F00000F0F0F0F0F0F",
--INIT_0 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_1 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_2 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_3 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_4 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_5 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_6 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_7 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_8 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_9 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_A => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_B => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_C => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_D => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_E => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_F => X"0000000000000000000000000000000000000000000000000000000000000000"
)
port map (
     RDATA     => TX_RD_DAT,
     RADDR     => I2S_ADR,
     RCLKN     => bclk_i2s_i,
     RCLKE     => const_one,
     RE        => const_one,
     WADDR     => TDM_ADR,
     WCLKN     => bclk_tdm_i,
     WCLKE     => const_one,
     WDATA     => TX_WR_DAT,
     WE        => const_zero
);


Ram2048x2_inst_2 : SB_RAM2048x2NRNW   
generic map (
INIT_0 => X"0000000000000000000000000000000000000F0F0F0F0F0F00000F0F0F0F0F0F",
--INIT_0 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_1 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_2 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_3 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_4 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_5 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_6 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_7 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_8 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_9 => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_A => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_B => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_C => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_D => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_E => X"0000000000000000000000000000000000000000000000000000000000000000",
INIT_F => X"0000000000000000000000000000000000000000000000000000000000000000"
)
port map (
     RDATA     => RX_RD_DAT,
     RADDR     => TDM_ADR,
     RCLKN     => bclk_tdm_i,
     RCLKE     => const_one,
     RE        => const_one,
     WADDR     => I2S_ADR, 
     WCLKN     => bclk_i2s_i,
     WCLKE     => const_one,
     WDATA     => RX_WR_DAT,
     WE        => const_zero
);


: Bearbeitet durch User
Autor: Mampf F. (mampf) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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:
-- state memory
type mem_type is array ((STACK_SIZE*128)-1 downto 0) of std_logic_vector(17 downto 0);
signal mem0 : mem_type;

 
attribute syn_ramstyle: string;
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
Autor: C. A. Rotwang (Gast)
Datum:

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

Autor: Stephan C. (stephan_c)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
Autor: C. A. Rotwang (Gast)
Datum:

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

Autor: Duke Scarring (Gast)
Datum:

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

Autor: Stephan C. (stephan_c)
Datum:

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

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.

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