1

I am trying to simulate the following code for an asynchronous ram in verilog. But dout remains xxxx all the time. The first time I tried the code dout was equal to din for the time when write signal was 1.After that it was all xxxx.Can anyone tell me the problem?It'd be great if you could suggest a better code.

module ram(cs,wr,addr,din,dout);
parameter adds = 10, wsize =16, memsize =1024;
input cs,wr;
input [adds-1:0] addr;
 input [wsize-1 : 0]din;
 output [wsize-1:0]dout;
reg [wsize-1:0] mem [memsize-1:0];
assign dout = mem[addr];
always @(cs or wr)
begin
if(wr) mem[addr]= din;
end
endmodule

The test bench for the above code is :

module ramtest;

// Inputs
reg cs;
reg wr;
reg [9:0] addr;
reg [15:0] din;

// Outputs
wire [15:0] dout;
integer k,myseed;

// Instantiate the Unit Under Test (UUT)
ram uut (
    .cs(cs), 
    .wr(wr), 
    .addr(addr), 
    .din(din), 
    .dout(dout)
);

initial begin
for(k = 0; k<=1023; k = k+1)
 begin
 din = k % 256; wr = 1; cs= 1;addr= k ;
 end

repeat(20)
begin
#2 addr = $random(myseed) % 1024 ;
wr = 0; cs =1;
$display("Address = %5d, data = %4d",addr,dout);
end
end

initial myseed = 35 ; 

endmodule

2 Answers 2

1

Several errors:

  1. Your wr and cs do not change so the always @( cs or wr) is only entered once for write and once for read.
  2. Your 'write' code in the testbench for(k = 0; k<=1023; k = k+1) does not have a delay. So there is no time for the write to actually happen.

However the biggest danger is that you 'just' add the address to the sensitivity list and it all 'works':
always @(cs or wr or addr)

It would probably have helped you if you had first looked up a datasheet of an async RAM. They do not work the way you model it. There data is stored when the CS or Write goes away (which ever first). The data and address have to be stable a certain time before and after that.

In your model you change the address whilst keeping the WR and CS active. In real life the address does not change from one value to another instantaneous. It will go from for example 0000 to 000F but the bits will change one at a time: 0000 => 0004 => 0005 => 000D ==> 000F. Thus you could have messed up the contents of 5 different addresses.

Make a write signal from CS and WR: do_write = cs & wr; Do the actual write when that signal goes away: always @(negedge do_write) .....`.

Sign up to request clarification or add additional context in comments.

2 Comments

I tried doing this but the output still remains xxxx.
Do you pulse the wr or cs up and down? The write only happens on a falling edge!
0

It appears that you are trying to write an asynchronous RAM. In that case, you need to also add addr and din to your sensitivity list. Also, dout should get mem[addr] when cs is high and wr is low. In your testbench, you need to add a delay in your for loop before supplying the next input. One possible implementation is as follows:

module ram(oe, cs, wr, addr, din, dout);
  parameter adds = 6,
            wsize = 16, 
            memsize = 1 << adds;

  input cs, wr;
  input oe; // output enable
  input [adds-1:0] addr;
  input [wsize-1:0] din;
  output [wsize-1:0] dout;
  
  reg [wsize-1:0] dout;
  reg [wsize-1:0] mem [memsize-1:0];

always @(cs, wr, oe, addr, din)
  begin
    if (cs) begin
      if (wr) mem[addr] <= din;
      
      else if (oe) dout <= mem[addr];
    end
  end
endmodule

And corresponding testbench could be:

module ram_tb;
  parameter adds = 6,
            wsize = 16, 
            memsize = 1 << adds;
  
  reg cs, wr;
  reg oe; // output enable
  reg [adds-1:0] addr;
  reg [wsize-1:0] din;
  wire [wsize-1:0] dout;
  
  integer k, myseed;

  // Instantiate the Unit Under Test (UUT)
  ram uut (
      .cs(cs), 
      .wr(wr), 
      .oe(oe),
      .addr(addr), 
      .din(din), 
      .dout(dout)
  );
  initial myseed = 35; 
  
  initial begin
    for(k = 0; k < memsize; k = k+1) begin
      #2 
      din <= k % 256; 
      wr <= 1; 
      cs <= 1;
      addr <= k;
      oe <= 0;
    end
    
    repeat(20) begin
      #2 
      addr <= ($random(myseed)) % memsize ;
      wr <= 0; 
      cs <= 1;
      oe <= 1;
      $display("Address = %5d, data = %4d", addr, dout);
    end
    
    #10 $finish;
  end
 
endmodule

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.