Was ist falsch an diesem Versuch eines SDR-RAM in Verilog?

Ich habe ein Spartan-6-FPGA, das mit der AEMIF-Speicherschnittstelle auf einem TI DaVinci DM365-SoC verbunden ist, das ich steuere. Das AEMIF ist im Select Strobe-Modus eingerichtet. Ich versuche, das Lesen/Schreiben des Speichers auf dem FPGA über diese Schnittstelle zu implementieren, aber es funktioniert nicht. Die Hardware funktioniert und diese Funktionalität hat funktioniert, bevor sie in VHDL geschrieben wurde (nicht von mir geschrieben). Ich bin neu bei HDLs, also ist hier vielleicht etwas offensichtlich falsch.

Es ist schwer zu sagen, was tatsächlich vor sich geht, da der Takt 60 MHz beträgt und mein Oszilloskop/Logikanalysator Schwierigkeiten hat, so schnell zu gehen.

Bearbeiten: Ich habe das inzwischen zum Laufen gebracht. Das Setzen von drive_data auf kombinatorische Weise bedeutete, dass beim Lesen der alte Speicherwert auf dem Datenbus ausgegeben wurde, und später würde die sequentielle Logik die neue Adresse aufnehmen und die Daten während des Zyklus ändern.

module main(
    input EM_A_3,
    input EM_A_7,
    input EM_CLK,
    inout [15:0] EM_D,
    input EM_nCE1,
    input EM_nOE,
    input EM_nWE
    );

wire [1:0] em_addr;
/* temporary storage for emif "registers" */
reg [15:0] mem [0:3];
reg [15:0] em_outdata;

supply0 rst;        // reset always 0 for now
wire drive_data;

initial
begin: FOO
    integer i;
    for (i = 0; i < 4; i = i + 1) begin
        mem[i] = 8'b0;
    end
    em_outdata = 8'b1;
end

// drive EM_D when CE1, OE are low, and WE is high
assign drive_data = !EM_nCE1 && !EM_nOE && EM_nWE;
assign EM_D = drive_data ? em_outdata : 8'bz;
assign em_addr = {EM_A_7, EM_A_3};

// clocked version (not working yet)
always @ (posedge EM_CLK)
begin
    if (!EM_nCE1 && !EM_nWE) begin
        mem[em_addr] <= EM_D;
    end
    if (!EM_nCE1 && !EM_nOE && EM_nWE) begin
        em_outdata <= mem[em_addr];
    end
end

endmodule
Ein paar mehr Details wären hilfreich: Welcher SoC? Welche Art von Erinnerung versuchst du zu emulieren? Welche Art von "funktioniert nicht" macht es? Entfernen Sie auch den auskommentierten Code, da dies nur eine Ablenkung für diejenigen von uns ist, die versuchen, ihn zu lesen.
@MartinThompson - Ich habe den auskommentierten Code entfernt. Es ist in der Revisionsgeschichte, wenn jemand graben möchte. An Blueshift: Wenn Sie versuchen möchten, die asynchrone Version zu debuggen, können Sie die getaktete Version bearbeiten und durch die asynchrone Version ersetzen.
Fand dies nach 10 Jahren Arbeit mit FPGAs wieder. Wow! :)

Antworten (3)

Ich habe das zum Laufen gebracht, mit einer bestimmten Änderung, obwohl, um ehrlich zu sein, einige andere Änderungen auch geholfen haben könnten.

Ich habe darüber nachgedacht, wie drive_data mit kombinatorischer Logik eingerichtet wird, aber das Outdata-Register ist getaktet. Bestätigt durch Verhaltenssimulation bedeutet dies, dass veraltete Daten während des ersten Teils eines Lesezyklus ausgegeben werden, bevor die Adresse zwischengespeichert wird.

Ich habe dies "behoben", indem ich den Always-Block geändert habe, der outdata so bei jedem Takt einstellt, was bedeutet, dass die richtigen Daten während der Einrichtungsphase dort eingehen, während die Adresse auf dem Bus gültig ist, bevor der OE-Strobe kommt.

Ich habe auch mein Speicherbus-Handling in ein Submodul umgestaltet (Invertieren der Steuersignale).

module emif(
    input clk,
    input [1:0] addr,
    inout [15:0] data,
    input ce,           // note these signals are active high
    input we,           // (opposite to the PCB signals)
    input oe
    );

wire drive_data;
reg [15:0] mem [0:3];
reg [15:0] em_outdata;

assign drive_data = ce && oe && !we;
assign data = drive_data ? em_outdata : 16'bz;

// writes data to small mem
always @ (posedge clk)
begin
    if (ce && we) begin
        mem[addr] <= data;
    end
end

// reads data from small mem
always @ (posedge clk)
begin
    em_outdata <= mem[addr];
end

endmodule

Ich bin mir der genauen SDRAM-Timings nicht sicher, aber wenn ich nur Ihren Verilog-Stil kommentiere, könnten ein paar Dinge helfen. Sie müssen anfangen, in Hardware zu denken. Dies ist möglicherweise einfacher zu verstehen.

assign EM_D = drive_data ? em_outdata : 16'bz;
assign drive_data = !EM_nCE1 & !EM_nOE & EM_nWE;

// writes data to small mem
always @ (posedge EM_CLK)
begin
    if (!EM_nCE1 && !EM_nWE) begin
        mem[em_addr] <= EM_D;
    end
end

// reads data from small mem
always @ (posedge EM_CLK)
begin
    if (!EM_nCE1 && !EM_nOE && EM_nWE) begin
        em_outdata <= mem[em_addr];
    end
end

// see any problem? please change this logic. it doesn't seem to go anywhere.
always @ (posedge EM_CLK)
begin
    if (!EM_nCE1 && !EM_nWE) begin
        outbit <= 1;
    end else if (!EM_nCE1 && !EM_nOE && EM_nWE) begin
        outbit <= 0;
    end else
        outbit <= X; // *** Not sure what's the default/reset cond is.
end

Außerdem möchten Sie möglicherweise Ihren Anfangsblock aus dieser Datei verschieben, da es sich normalerweise um ein Simulationskonstrukt handelt und in diesem Fall sowieso nicht synthetisiert werden kann. Normalerweise ist es besser, Ihre Simulationskonstrukte von Ihren synthetisierbaren Konstrukten zu trennen.

Wenn Sie den RAM-Inhalt zurücksetzen möchten, können Sie entweder das FPGA-Tool verwenden, um den anfänglichen RAM-Inhalt festzulegen, oder einen kleinen Block entwerfen, der den RAM beim Einschalten zurücksetzt.

Viel Glück. Und lass mich wissen, ob es hilft. :)

Tatsächlich initialkönnen Blöcke für FPGAs synthetisiert werden. Sie teilen dem Compiler mit, welchen Zustand die Dinge am Ende der Konfiguration haben sollen, was nicht dasselbe ist wie Reset.
Danke! Das "Outbit" war ein Ablenkungsmanöver, nur eine Debug-Ausgabe, die ich versehentlich hinterlassen habe. Und Sie haben Recht, der Anfangsblock funktioniert nicht, um den Speicher zu initialisieren.

Es ist schwer zu sagen, was tatsächlich vor sich geht, da der Takt 60 MHz beträgt und mein Oszilloskop/Logikanalysator Schwierigkeiten hat, so schnell zu gehen.

Verwenden Sie ChipScope (Xilinx) oder SignalTap (Altera). Es ist großartig dafür und kann Ihnen viel Breite, wenn nicht Tiefe geben.

Ich sehe, das ist eine Altera-Sache und ChipScope ist anscheinend das Xilinx-Äquivalent. Klingt interessant, aber ich habe im Moment kein JTAG (nicht fragen). Werde es mir für die Zukunft merken, danke.