Electrical – implementation on write-first single-port ram


Following shows a single-port RAM in write-first mode.

module raminfr (clk, we, en, addr, di, do);
        input        clk;
        input        we;
        input        en;
        input  [4:0] addr;
        input  [3:0] di;
        output [3:0] do;
        reg    [3:0] RAM [31:0];
        reg    [4:0] read_addr;
        always @(posedge clk)
           if (en) begin
              if (we) 
             RAM[addr] <= di;
                  read_addr <= addr;
           assign do = RAM[read_addr];

Here, how can we assure that output do is changed after RAM[addr] <= di; is executed?

If the logic does write-first mode, data has to be written first and then read has to happen. But, as we know, RAM[addr] <= di; and read_addr <= addr; are executed concurrently. However, it seems that we cannot guarantee that output do is changed after writing.

Why this code works?

Following are my exepctation:

assumption: addr[10] = 5, addr[20] = 15;

previous addr: 10, current addr:10, en: 1, we: 0 => do = 5

previous addr: 10, current addr:20, en: 1, we: 1, di: 12 =>
do will be changed because of RAM[read_addr] will be changed as 15. But, how can we assure that do will be 12 instead of 15 (write-first mode)?

Also, is the reg read_addr necessary? If it is, why?

Best Answer

Here, how can we assure that output do is changed after RAM[addr] <= di; is executed?

Because assign do = RAM[read_addr]; will be executed when any of its signals change. Thus it will be called when either read_addr changes or if RAM changes. This makes that the do output follows both the address but also reflect any writes which happen.

The reg read_addr makes sure that the data of the last read stays on the output if addr changes. That is needed because addr must be ignored if there is no enable and if there is no clock.

The whole code builds a memory with a certain behavior. It may just not be the behavior you where expecting.

I hope the code formatting is not the original one. It is very sloppy. Also nowadays you should use modern port definitions:

module raminfr (
   input clk, // Memory synchronous clock
   input we,  // Write enable
   input en,  // Enable for both read and write

Adding the comment makes clear what each signal does. Thus it tells the user that the en is required for read and write. Otherwise she/he has to go working through the code to find out.

Final remark: just because you find some code which works don't assume it is the best there is.