Modelsim - Seltsames Überprüfungsproblem mit DDR und Xilinx UNISIM

Ich verifiziere die VHDL-Komponente mit OVM und bin auf ernsthafte Probleme gestoßen. Ich habe festgestellt, dass das Problem in einer bestimmten Komponente liegt und eine Umgebung speziell dafür erstellt hat. Es handelt sich um einen RGMII-zu-internen Schnittstellenkonverter (von DDR zu SDR), der Xilinx UNISIM-Komponenten verwendet, um das spezielle Verhalten von FPGA-Chipteilen zu simulieren.

BUFG_inst : BUFG
port map (
    O => INTERNAL_CLK,
    I => RGMII_CLK
);

IDDRDATA0_inst: IDDR
generic map (
    DDR_CLK_EDGE => "SAME_EDGE_PIPELINED",
    INIT_Q1 => '0',
    INIT_Q2 => '0',
    SRTYPE  => "SYNC"
)
port map (
    Q1 => data(0),
    Q2 => data(4),
    C  => INTERNAL_CLK,
    CE => CE,
    D  => RGMII_DATA(0),
    R  => RST,
    S  => '0'
);
-- several more instantiations

Ich erzeuge Transaktionen und sende sie mit dem Treiber an das DUT:

forever
begin
my_transaction tx;

@(posedge dut_vi.clock); 
seq_item_port.get(tx);

dut_vi.ctl   = tx.ctl;
dut_vi.reset = tx.reset;
dut_vi.data  = tx.data;

@(negedge dut_vi.clock); 
seq_item_port.get(tx);

dut_vi.ctl   = tx.ctl;
dut_vi.reset = tx.reset;
dut_vi.data  = tx.data;
end

In Modelsim Wave ist diese Eingabe (Beobachten von DUT-Eingangsports) in Ordnung. Intern nimmt sie jedoch den vorherigen Datenwert an - zum Beispiel war der vorherige Wert von CTL 0, bei steigender Flanke ist es 1, aber DUT tastet mit steigender Flanke diesen vorherigen ab 0, da es in Modelsim nicht aktualisiert wurde.

Ich habe versucht, "kleinen Hack" zu verwenden:

TMP_CLK <= RGMII_CLK after 1ps;

BUFG_inst : BUFG
port map (
    O => INTERNAL_CLK,
    I => TMP_CLK
);

Es hat das Problem (teilweise) gelöst. DUT hat jetzt korrekte Werte abgetastet. Aber es hat Probleme mit Ausgabe und Monitor verursacht. Jetzt ist alles in Wave korrekt, aber Monitor sieht falsche Werte (aber nur manchmal - meist mit Paketanfang - gültiges Signal von 0 auf 1 gewechselt). Es ist also ein ähnliches Problem wie bei der Eingabe. Mein Monitor sieht so aus:

forever
begin
dut_out_transaction tx;

@(posedge dut_out_vi.clock);          
tx = dut_out_transaction::type_id::create("tx");

tx.dv    = dut_out_vi.dv;
tx.err   = dut_out_vi.err;
tx.sof   = dut_out_vi.sof;
tx.eof   = dut_out_vi.eof;
tx.data  = dut_out_vi.data;

$display("DUT_OUT EOF: %b", dut_out_vi.eof);

if (dut_out_vi.eof == 1)  // this never happens
    ovm_report_info("out_monitor", "EOF");

aport.write(tx);
end

Da es sich um einen ähnlichen Fehler handelt, habe ich einen ähnlichen Hack ausprobiert - ich habe #1ps direkt nach @(posedge dut_out_vi.clock) hinzugefügt; und es hat wirklich geholfen.. Aber es ist ein neues Problem aufgetreten - jetzt sieht der Monitor nie ein EOF-Signal in 1, obwohl es sich mehrmals in 1 in Welle befindet.

Ich verwende Modelsim 10.5 mit einer Auflösung von 1ps. Irgendwelche Ideen, was es verursachen könnte oder wie man es beheben kann?

Vielleicht möchten Sie versuchen, Ihrer Schnittstelle einen Clocking-Block ( IEEE1800-2012 § 14 Clocking Blocks ) hinzuzufügen. Dadurch können Sie steuern, wie weit links von der Uhr Ihr Abtastwert betrachtet wird.
@Greg Interessant .. Ich werde es mir ansehen. Inzwischen habe ich es mit wait behoben - ich werde die Antwort posten.

Antworten (1)

Ich habe es endlich gelöst - das Problem war in der Xilinx-Unisim-Bibliothek. Aus irgendeinem Grund gibt es in IDDR eine Verzögerung von 100 ps (was in der Verhaltenssimulation nicht sein sollte). Die Lösung besteht also darin, im Monitor zu warten (ich habe tatsächlich zwei - für die Eingabe und Ausgabe des DUT):

forever
begin
  my_transaction tx;

  @(posedge dut_vi.clock);
  #1ps
  tx = my_transaction::type_id::create("tx");

  tx.ctl   = dut_vi.ctl;
  tx.reset = dut_vi.reset;
  tx.data  = dut_vi.data;

  aport.write(tx);

  @(negedge dut_vi.clock);
  #1ps
  tx = my_transaction::type_id::create("tx");

  tx.ctl   = dut_vi.ctl;
  tx.reset = dut_vi.reset;
  tx.data  = dut_vi.data;

  aport.write(tx);
end

und zweite:

forever
begin
  dut_out_transaction tx;

  @(posedge dut_out_vi.clock);
  #101ps   // simulation hack
  tx = dut_out_transaction::type_id::create("tx");

  tx.dv    = dut_out_vi.dv;
  tx.err   = dut_out_vi.err;
  tx.sof   = dut_out_vi.sof;
  tx.eof   = dut_out_vi.eof;
  tx.data  = dut_out_vi.data;
end

Im Eingangsmonitor muss ich 1 ps warten (habe nicht herausgefunden, warum) und im Ausgang muss ich 101 ps warten, da es zu Verzögerungen im IDDR kommt (ich habe den Code überprüft). Auf diese Weise erhält die Anzeigetafel korrekte Daten.