1
\$\begingroup\$

I have created an 8x8 memory module. Currently, I have the following:

  • Bitcell - takes in signals sel (if its selected), rw (read = 0, write = 1) and input. If sel=0, output is high impedance. If sel=1, it either reads, or writes (and outputs the written value).
  • word_8 - Collection of 8 bitcells that also take in sel and rw (forwarded to each cell individually). 8 input and 8 output wires to each bitcell.
  • decoder_3to8 - decoder that's supposed to take in an address, and select the word which is supposed to be read.
  • memory_8x8: 8 word_8, where the sel signals for every of them is designed using the decoder.

I run a simple test bench, where I:

  1. write 0x00 (0000 0000) into cell 0.
  2. wrote 0x10 (0001 0001) into cell 1.
  3. read from cell 0
  4. read from cell 1

Code for the testbench is:

`timescale 1ns / 1ps

module memory_8x8_tb;

  reg [2:0] addr;
  reg [7:0] inp;
  reg op;
  reg select;

  wire [7:0] outp;
  reg [7:0] expected_outp;

  // Instantiate the memory_8x8 module
  memory_8x8 uut (
    .addr(addr),
    .inp(inp),
    .op(op),
    .select(select),
    .outp(outp)
  );

  initial begin
    $dumpfile("test_stage0.vcd");
    $dumpvars();

    // Initialize inputs
    select = 0;
    op = 0;
    addr = 3'b000;
    inp = 8'b00000000;
    expected_outp = 8'bXXXXXXXX;

    #10;

    // Write 0x00 to cell 0
    select = 1;
    op = 1;  // Write operation
    addr = 3'b000;
    inp = 8'h00;
    expected_outp = inp;
    #10;

    // Verify the write to cell 0
    if (outp !== expected_outp) begin
      $display("Write to cell 0 FAILED: Expected %h, Got %h", expected_outp, outp);
    end else begin
      $display("Write to cell 0 PASSED: Data %h", outp);
    end

    // Deselect and wait
    select = 0;
    #10;

    // Write 0x11 to cell 1
    select = 1;
    addr = 3'b001;
    inp = 8'h11;
    expected_outp = inp;
    #10;

    // Verify the write to cell 1
    if (outp !== expected_outp) begin
      $display("Write to cell 1 FAILED: Expected %h, Got %h", expected_outp, outp);
    end else begin
      $display("Write to cell 1 PASSED: Data %h", outp);
    end

    // Deselect and wait
    select = 0;
    #10;

    // Read cell 0
    select = 1;
    op = 0;  // Read operation
    addr = 3'b000;
    expected_outp = 8'h00;
    #10;

    // Verify the read from cell 0
    if (outp !== expected_outp) begin
      $display("Read cell 0 FAILED: Expected %h, Got %h", expected_outp, outp);
    end else begin
      $display("Read cell 0 PASSED: Data %h", outp);
    end

    // Read cell 1
    select = 1;
    addr = 3'b001;
    expected_outp = 8'h11;
    #10;

    // Verify the read from cell 1
    if (outp !== expected_outp) begin
      $display("Read cell 1 FAILED: Expected %h, Got %h", expected_outp, outp);
    end else begin
      $display("Read cell 1 PASSED: Data %h", outp);
    end

    // End simulation
    $finish;
  end

endmodule

Now to the problem: when cell 1 is written in in step 2, the value also seems to fill cell 0, even though it is deselected.

I have dumped the test into GTKWave, and get the following:

Circuit test in GTKWave

This is a wave pattern analysis of the circuit. The upper values are for the whole memory circuit where:

  • sel - selected bitcell (each bit corresponds to cell 0-7)
  • addr - address (which selects the sel singal)
  • sel - is any of the bitcells selected?
  • op - read(0) or write(1)

The middle values are values inside of word[0], bitcell[0], and the lower ones are word1, bitcell[0].

The read areas showcase my problem. That is the moment where the selection is changed from cell 0 to cell 1, and 1 is written into the bitcell in cell 1. As one can see, sel=0 for cell 0 there. Both S and R values stay at 0, as expected. I'm using a NOR SR-latch, so this should mean the values shouldn't change. However, if you see at the Q signal, a 1 is for some reason getting written there. The output value outp still seems to be in a high impedance state as expected, but Q is getting overwritten.

The code for the bitcell is the following:

module bitcell (
    input sel, // Bitcell selected
    input rw, // 1 - write, 0 - read
    input inp,
    output outp
);

wire S, R;

wire inp_NOT;
wire rw_NOT;
wire sel_NOT;

not(inp_NOT, inp);
not(rw_NOT, rw);
not(sel_NOT, sel);

// S and R signals for NAND latch
nor s_generator(S, sel_NOT, rw_NOT, inp_NOT);
nor r_generator(R, sel_NOT, rw_NOT, inp);

// Latch
wire Q, Q_not;

nor latch_upper(Q, Q_not, R);
nor latch_lower(Q_not, Q, S);

// wire EN;
// and(EN, sel, rw_NOT);

bufif1 enable_buffer(outp, Q, sel);
    
endmodule

My memory_8x8:

/*
    Represents the finished 8x8 memory cell.

    Consists of 8 words of 8 bytes (word_8), selectable through 3 bit address
*/

module memory_8x8 (
    input[2:0] addr,
    input[7:0] inp,
    input op,
    input select,
    output[7:0] outp
);

wire[7:0] selected_cell;

decoder_3to8 decoder(
    .valid(select),
    .addr(addr),
    .sel(selected_cell)
);

genvar i;
generate
    for (i = 0; i < 8; i = i + 1) begin
        word_8 word_instance(
            .sel(selected_cell[i]),
            .rw(op),
            .inp(inp),
            .outp(outp)
        );
    end
endgenerate

endmodule

And word_8:

module word_8 (
    input sel,
    input rw,
    input[7:0] inp,
    output[7:0] outp
);


genvar i;
generate
    for (i = 0; i < 8; i = i + 1) begin : BITCELLS
        bitcell bitcell_instance(
            .sel(sel),
            .rw(rw),
            .inp(inp[i]),
            .outp(outp[i])
        );
    end
endgenerate
    
endmodule

I have now been trying for several hours to fix this, but I have no idea what might be wrong. Any ideas?

\$\endgroup\$
0

2 Answers 2

1
\$\begingroup\$

The fundamental problem is that you have been lead down the wrong path with your approach to Verilog modeling. You should always write Verilog code at the highest level of abstraction. You are trying to model a simple memory with very low-level gate instances. This is the incorrect way to model this logic, which is why you are encountering many problems.

You need to model memories, latches and flip-flops using behavioral modeling. Here is a trivial behavioral model based on our development of your previous question:

module bitcell (
    input sel,
    input rw,
    input inp,
    output outp
);

reg mem;

assign outp = (sel) ? mem : 1'bz;

always @* begin
    if (sel && rw) begin
        mem = inp;
    end        
end
endmodule

This might more closely match the high-level behavior you are trying to achieve. There are several advantages to this style:

  • Shorter code which is easier to read
  • Clearly shows the intended behavior of the logic
  • There are no instance port connections to debug when things don't behave as expected

Refer also to synthesizable constructs should you ever intend to synthesize the code.

See this answer for a further explanation.

And this answer, too

\$\endgroup\$
5
  • \$\begingroup\$ One of the requirement for the project are to use only gate level CMOS. I am therefore limited to only using logic gate abstraction. \$\endgroup\$
    – Gronnmann
    Commented Nov 16 at 16:44
  • \$\begingroup\$ @Gronnmann: The person who has set this requirement for you either did not communicate it properly or is unaware of the limitations of trying to model an SR latch with gates in Verilog. Verilog is used to describe abstract logic, not transistor-level circuits. \$\endgroup\$
    – toolic
    Commented Nov 16 at 16:52
  • \$\begingroup\$ @Gronnmann: I updated the answer with a link. \$\endgroup\$
    – toolic
    Commented Nov 17 at 12:34
  • \$\begingroup\$ While I agree I would prefer to use behavioural modeling, one would expect that gate level logic work correctly in Verilog as it's a defined feature. \$\endgroup\$
    – Gronnmann
    Commented Nov 17 at 14:04
  • 1
    \$\begingroup\$ @Gronnmann: Yes, gate level logic is supported, and yes it is a clearly defined feature in the IEEE Std. But, for these feedback circuits, there is never a technical reason to use gate modeling; behavioral modeling is recommended to avoid the types of issues you are encountering (and will continue to encounter). Always challenge artificial requirements like this. \$\endgroup\$
    – toolic
    Commented Nov 18 at 13:09
0
\$\begingroup\$

The problem appeared to be caused by some problems with the SR latch. After adding a little delay on one of the NOR-gates, it seems to work perfectly.

Fix is the #1 in:

nor #1 latch_upper(Q, Q_not, R);
nor latch_lower(Q_not, Q, S);

Seems to work when I set it for any of the gates.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.