verilogsystem-verilogiverilog

The output I'm getting is wrong


It is not reading the data_in inputs in sequence when I tried to display the output of RAM. The RAM output starts from B as on the 000 address however I'm trying to write A on 000 address and so on Here is the design block code

  module task (
  input [2:0] address_ram,
  input [7:0] data_in,
  output [(DATA_WIDTH-1):0] q_ram,
  input clk,
  input rst,
  input we
);

  parameter DATA_WIDTH = 8;
  parameter ADDR_WIDTH = 8;
  // RAM content
  reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
  reg [ADDR_WIDTH-1:0] addr_r;

  always @(posedge clk or negedge rst) begin
    if (rst) begin
      // Reset condition
      addr_r <= 8'b0;
    end else begin
      // WRITE to RAM
      if (we) begin
        ram[addr_r] <= data_in;
      end

      // READ from RAM
      addr_r <= address_ram;
    end
  end
  assign   q_ram = ram[address_ram];
endmodule

this is the testbench

// Code your testbench here
// or browse Examples
module task_tb;

  // Parameters
  parameter DATA_WIDTH = 8;
  parameter ADDR_WIDTH = 8;

  // Inputs and Outputs
  reg clk, rst, we;
  reg [DATA_WIDTH-1:0] data_in;
  reg [2:0] address_ram;
  wire [(DATA_WIDTH-1):0] q_ram_out;

  // Instantiate the home_task module
  home_task uut (
    .clk(clk),
    .rst(rst),
    .we(we),
    .address_ram(address_ram),
    .data_in(data_in),
    .q_ram(q_ram_out)
  );

  // Clock Generation
  always begin
    #5 clk = ~clk; // Toggle the clock every 5 time units
  end

  // Initial Block
  initial begin
    clk = 0;
    rst = 0; // Assert reset initially
    we = 0;
    data_in = 8'b01000001;
    address_ram = 3'b000;
    result = 1;

    // Apply reset for some time
    #10 rst = 0;
    #10;

    // Write data to RAM
    we = 1;
    address_ram = 3'b000;
    data_in = 8'b01000001; // 'A'
    #10;

    we = 1;
    address_ram = 3'b001;
    data_in = 8'b01000010; // 'B'
    #10;

    we = 1;
    address_ram = 3'b010;
    data_in = 8'b01000011; // 'C'
    #10;

    we = 1;
    address_ram = 3'b011;
    data_in = 8'b01000100; // 'D'
    #10;

    we = 1;
    address_ram = 3'b100;
    data_in = 8'b01000101; // 'E'
    #10;

    we = 1;
    address_ram = 3'b101;
    data_in = 8'b01000110; // 'F'
    #10;

    we = 1;
    address_ram = 3'b110;
    data_in = 8'b01000111; // 'G'
    #10;

    we = 1;
    address_ram = 3'b111;
    data_in = 8'b01001000; // 'H'
    #10;


     address_ram = 3'b000;
    repeat (2**3) begin
     
  
      $display("Read Data from RAM at address %b: %c", address_ram, q_ram_out);
      #10;
      address_ram = address_ram + 1;
    end
    // Add more stimulus as needed
    #100 $finish;
  end

endmodule

I am writing to the RAM ABCDEFGH But the output shows that it started 000 as B, 001 as C and so on... But I want the result to be A as 000 B as 001 and so on.


Solution

  • I think the problem is in the reset. always statement looks for a negedge rst but the if (rst) checks for rst=1'b1 to reset the design.

    Also, one thing to point is that you are using a registered version of the ram_address i.e. addr_r to write into the RAM. So, the first wren from testbench is going to use the reset value of addr_r for writing. But your design's reset condition is wrong.

    First of all, release reset from your testbench, I noticed rst stays 0. But also, if you are using a registered ram_address for writing, you should also register we and data_in in the code, so that all the signals align properly.

    I would rewrite the code as follows:

    module task (
      input [2:0] address_ram,
      input [7:0] data_in,
      output [(DATA_WIDTH-1):0] q_ram,
      input clk,
      input rst,
      input we
    );
    
      parameter DATA_WIDTH = 8;
      parameter ADDR_WIDTH = 8;
      // RAM content
      reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
      reg [ADDR_WIDTH-1:0] addr_r;
      reg [DATA_WIDTH-1:0] data_in_r;
      reg we_r;
    
      always @(posedge clk or negedge rst) begin
        if (rst == 1'b0) begin
          addr_r <= {ADDR_WIDTH{1'b0}};
          data_in_r <= {DATA_WIDTH{1'b0}};
          we_r <= 1'b0;
        end else begin
          addr_r <= address_ram;
          data_in_r <= data_in;
          we_r <= we;
        end
      end
    
      always @(posedge clk) begin
        if (we_r) begin
          ram[addr_r] <= data_in_r;
        end
      end
      assign   q_ram = ram[addr_r];
    endmodule
    

    By separating the always blocks, that code is much cleaner. And now, the addr_r, data_in, and we are all one clock cycle registered. And your read condition is also using a registered version of ram_address

    In your testbench, the rst should go from 0 to 1 for properly resetting the design. It should work.