Frage zum Coding Style eines normalen RAMs mit Initialisierung

OP #3783038
Lesenswert?

Hallo zusammen,

ich versuche immer noch die LM32-CPU auf einem Altera FPGA zu portieren
wo auch das Debugging mit dem JTAG später möglich sein soll.

Im original Source wird z.B. ein Monitor RAM (lm32_monitor_ram.v) 
erwendet:
1
lm32_monitor_ram ram (
2
    // ----- Inputs -------
3
    .ClockA             (clk_i),
4
    .ClockB             (clk_i),
5
    .ResetA             (rst_i),
6
    .ResetB             (rst_i),
7
    .ClockEnA           (`TRUE),
8
    .ClockEnB           (`FALSE),
9
    .AddressA           (MON_ADR_I[10:2]),
10
    .AddressB           (9'b0),
11
    .DataInA            (write_data),
12
    .DataInB            (32'b0),
13
    .WrA                (write_enable),
14
    .WrB                (`FALSE),
15
    // ----- Outputs -------
16
    .QA                 (data),
17
    .QB                 (dataB)
18
    );

Weiterhin sind die Parameter wie folgt gesetzt:

CSDECODE_B   = "0b000" ;
CSDECODE_A   = "0b000" ;
WRITEMODE_B  = "NORMAL" ;
WRITEMODE_A  = "NORMAL" ;
GSR          = "ENABLED" ;
RESETMODE    = "SYNC" ;
REGMODE_B    = "NOREG" ;
REGMODE_A    = "NOREG" ;
DATA_WIDTH_B = 9 ;
DATA_WIDTH_A = 9 ;

Intern wird dies auf ein DP8KC Primitive abgebildet, 8K True Dual Port 
Block RAM. Für mich sieht das jetzt aber so aus als wenn hier die Dual
Port Funktion nicht verwendet wird, sondern nur ein einfaches RAM, kann
das sein?

Bei den Altera Beispielen habe ich die Möglichkeit
"Old Data Read-During-Write Behavior" oder
"New Data Read-During-Write Behavior" zu verwenden.

Old Data Read-During-Write Behavior
1
module single_clk_ram(
2
   output reg [7:0] q,
3
   input [7:0] d,
4
   input [6:0] write_address, read_address,
5
   input we, clk
6
);
7

8
reg [7:0] mem [127:0];
9
always @ (posedge clk) begin
10
   if (we)
11
      mem[write_address] <= d;
12
   q <= mem[read_address]; // q doesn't get d in this clock cycle
13
end
14

15
endmodule

New Data Read-During-Write Behavior
1
module single_clock_wr_ram(
2
   output reg [7:0] q,
3
   input [7:0] d,
4
   input [6:0] write_address, read_address,
5
   input we, clk
6
);
7

8
reg [7:0] mem [127:0];
9
always @ (posedge clk) begin
10
   if (we)
11
      mem[write_address] = d;
12
   q = mem[read_address]; // q does get d in this clock cycle if
13
                          // we is high
14
end
15

16
endmodule

Was ist hier nun die richtige Version?
Und das andere Problem, wie kann man das RAM vorher mit Daten 
initialisieren (siehe Anhang original lm32_monitor_ram)?

Viele Grüße,
Michael
Angehängte Dateien:
Gast #3783206
Lesenswert?

Michael Fischer schrieb:
> Für mich sieht das jetzt aber so aus als wenn hier die Dual
> Port Funktion nicht verwendet wird, sondern nur ein einfaches RAM, kann
> das sein?
Ja. Der Port B wird hier nicht verwendet.

> Was ist hier nun die richtige Version?
http://www.latticesemi.com/~/media/Documents/UserManuals/EI/FPGALibrariesReferenceGuide31.pdf
Auf Seite 192 unten, sieht man die Möglichkeiten für WRITEMODE. Im 
Orignal wird "NORMAL" verwendet. Es gibt noch "WRITETHROUGH" und 
"READBEFORE". Dazu hast Du ja die Pendants für Altera schon gefunden.
Mir ist hier auch nicht klar, welches Verhalten für Lattice 'normal' 
ist.

Dieser Punkt spielt aber nur eine Rolle, wenn man auf einer Adresse 
gleichzeitig schreibt und liest. Dieser Fall ist mir bisher noch nicht 
begegnet.

Die dritte Frage hat sich ja schon erledigt.

Daniel
Gast #3783352
Lesenswert?

Daniel schrieb:

> Mir ist hier auch nicht klar, welches Verhalten für Lattice 'normal'
> ist.
>

Aus dem ECP3 Handbuch:

In NORMAL mode, the output data does not change or get updated, during 
the write operation. This mode is supported for all data widths.

In WRITETHROUGH mode, the output data is updated with the input data 
during the write cycle. This mode is supported for all data widths.

In READBEFOREWRITE mode, the output data port is updated with the 
existing data stored in the write address, during a write cycle. This 
mode is supported for x9, x18 and x36 data widths.
OP #3783564
Lesenswert?

Hallo,

Danke für die Info.

Was mir noch gefehlt hat war das lm32_monitor.mem File. Irgendwie habe
ich nicht verstanden wie ich das aus dem lm32_monitor_ram.v extrahieren
oder wieder herstellen kann.

Also habe ich es mal anderes versucht, und den Bereich 0x0 - 0x800 von
einem Lattice Evalboard ausgelesen. Dies wurde jetzt als
lm32_monitor.mem verwendet. Es sieht so aus als würde es immer noch
beim Original funktionieren. Mich wundert es aber schon etwas das der
ausgelesene Bereich fast voll ist. In der original Datei 
lm32_monitor_ram.v sieht es aber nicht so aus.

Gruß,
Michael
Gast #3783598
Lesenswert?

Michael Fischer schrieb:
> Hallo,
>
> Danke für die Info.
>
> Was mir noch gefehlt hat war das lm32_monitor.mem File. Irgendwie habe
> ich nicht verstanden wie ich das aus dem lm32_monitor_ram.v extrahieren
> oder wieder herstellen kann.

Ist auch nicht einfach, da das Mapping vom INIT_VAL zu den einzelnen 
Bits im RAM in den verschiedenen Konfigurationen nicht dokumentiert ist, 
zumindesten habe eine Docu besiher nicht gefunden :-(
Gast #3783654
Lesenswert?

Michael Fischer schrieb:
> lm32_monitor.mem
Das sind 512 * 4 Byte = 2048 Byte

In lm32_monitor_ram.v sind Varianten für alle Lattice-Chips drin.
Wenn man sich z.B. auf den MachXO2 beschränkt, sieht man das da
12 Zeilen á 40 Byte +
 1 Zeile mit 22 Byte
und das ganze 4 Mal gefüllt sind: (12 * 40 + 22) * 4 = 2008 Byte

stimmt also ganz gut überein (da sind ja auch ein paar Nullen am Ende).

Interessant wäre der .asm oder .c-Quelltext, um sich das mem-File selbst 
zu erzeugen bzw. um Anpassungen vornehmen zu können.

Daniel

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren