register file in verilog

On Mon, 1 Feb 2010 10:00:24 -0800 (PST), rekz wrote:

With that taken care of, how could I design the
test bench for this module?

anyone care to help me out?
well, I can't speak for anyone else but I have to admit
that I for one am rather weary of the way you post a
problem, get a variety of useful and/or thought-provoking
answers, and then come right back with another little
bit of your problem drip-fed to us. It would have
been more congenial had you laid out the overall scope
of what you're trying to do, and given us an idea
of which parts you'd completed and which parts you
were finding troublesome.

Writing testbenches is, near enough, what I do for a
living these days. I've been doing it for quite a
while and I've spent most of that time learning stuff,
for there is much to learn. You can do some simple
things rather easily, but any testbench worthy of the
name will cost you serious thought, planning and
coding effort.

In a nutshell:
1. Write a module to represent the testbench.
2. In that module, create an instance of your
design-under-test (DUT) and all the signals
needed to connect to its ports.
3. Use one or more "initial" blocks to stimulate
the DUT's inputs with interesting, realistic
activity that will exercise the functionality
you wish to test.
4. Write one or more further "initial" blocks to
observe the relationship between the DUT's
inputs and outputs, continually checking that
those relationships are appropriate and
raising an error indication if not.
5. Write further code to keep account of what
tests your code has performed, so that - when
you are lucky enough to get a test that runs
without errors - you can measure confidently
what features of the DUT you have tested.

Of those five tasks, (1) and (2) are rather easy,
although they can be tedious if the DUT has many
ports; (3) is straightforward if your ambitions
are sufficiently modest, but can be difficult if
you wish to model complex and realistic scenarios;
(4) and (5) generally are rather challenging
to do well.

For more detail, try any half-decent textbook with
"Testbench" in its name.
--
Jonathan Bromley
 
On Jan 29, 10:56 am, rekz <aditya15...@gmail.com> wrote:
On Jan 29, 10:29 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com
wrote:





On Fri, 29 Jan 2010 08:43:10 -0800 (PST), rekz wrote:
oops, I think that this resolves the issue:

output [31:0] ReadData1, ReadData2;
reg [31:0] ReadData1, ReadData2;
reg [31:0] RF [31:0];

always begin
// write the register with new value if Regwrite is high

@(negedge Clk) begin
   ReadData1 = RF[ReadRegister1];
   ReadData2 = RF[ReadRegister2];
end

Spot-on.

The executive summary:

If a thing is given its value by procedural assignment
(i.e. THING=expression  or THING<=expression
in the body of an always or initial block, or in a
task or function) then the thing must be a variable
such as reg or integer.

If a thing is given its value by any other means,
the thing must be a net (wire etc).

That's it.

"Any other means"?  That's...
- continuous assignment usinsg the assign keyword,
  at the top level of a module
- being driven across a module boundary: for example,
  the input port of a module is driven from the outside
  signal connected to that port, so the signal INSIDE
  the module must be a net - there are many other such
  situations.

That is the WHOLE story about how to choose whether to
declare something as a net or a variable, in conventional
Verilog.  The rules of the game change somewhat in
SystemVerilog, but that need not concern you right now.

Someone will probably pop up and tell you "wires are
structural, regs are behavioural" but you should take
no notice; that statement is pointing in the right
direction, but it's not the whole story.
--
Jonathan Bromley

With that taken care of, how could I design the test bench for this
module?- Hide quoted text -

- Show quoted text -
anyone care to help me out?
 
On Feb 1, 11:29 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Mon, 1 Feb 2010 10:00:24 -0800 (PST), rekz wrote:
With that taken care of, how could I design the
test bench for this module?
anyone care to help me out?

well, I can't speak for anyone else but I have to admit
that I for one am rather weary of the way you post a
problem, get a variety of useful and/or thought-provoking
answers, and then come right back with another little
bit of your problem drip-fed to us.  It would have
been more congenial had you laid out the overall scope
of what you're trying to do, and given us an idea
of which parts you'd completed and which parts you
were finding troublesome.

Writing testbenches is, near enough, what I do for a
living these days.  I've been doing it for quite a
while and I've spent most of that time learning stuff,
for there is much to learn.  You can do some simple
things rather easily, but any testbench worthy of the
name will cost you serious thought, planning and
coding effort.

In a nutshell:
1. Write a module to represent the testbench.
2. In that module, create an instance of your
  design-under-test (DUT) and all the signals
  needed to connect to its ports.
3. Use one or more "initial" blocks to stimulate
  the DUT's inputs with interesting, realistic
  activity that will exercise the functionality
  you wish to test.
4. Write one or more further "initial" blocks to
  observe the relationship between the DUT's
  inputs and outputs, continually checking that
  those relationships are appropriate and
  raising an error indication if not.
5. Write further code to keep account of what
  tests your code has performed, so that - when
  you are lucky enough to get a test that runs
  without errors - you can measure confidently
  what features of the DUT you have tested.

Of those five tasks, (1) and (2) are rather easy,
although they can be tedious if the DUT has many
ports; (3) is straightforward if your ambitions
are sufficiently modest, but can be difficult if
you wish to model complex and realistic scenarios;
(4) and (5) generally are rather challenging
to do well.

For more detail, try any half-decent textbook with
"Testbench" in its name.
--
Jonathan Bromley
I don't quite understand some of the concepts that you said above, but
here's what I did to test my register file.
I first wrote several values into several address in the register
(around 4 to 8). Then I tried to read from those registers that I
wrote
first place. Does this seems sufficient enough?
 
On Feb 1, 4:18 pm, rekz <aditya15...@gmail.com> wrote:
Does this seems sufficient enough?
Wow, now there's a question: "When am I done with verification?"

Google "memory test" and see what you get. Tests like "walking ones",
"walking zeroes", "address test" etc. are a good place to start.
However, remember you are testing a design, not hardware. Design
faults are what you are trying to find, not hardware failures.

Andy
 
On Mon, 1 Feb 2010 14:18:50 -0800 (PST), rekz wrote:

I don't quite understand some of the concepts that you said above, but
here's what I did to test my register file.
I first wrote several values into several address in the register
(around 4 to 8). Then I tried to read from those registers that I
wrote first place. Does this seems sufficient enough?
Well, it sounds as though you've covered several of
the ideas I suggested :)

As Andy pointed out, you're trying to verify the functional
correctness of your design. This is a rather different
problem than testing all the transistors and connections
in a piece of hardware. So, for example, it is probably
NOT necessary to test every single location in your
modelled memory, since the same lines of code model
data storage and retrieval regardless of which location
you are accessing.

However, you do need to be careful about the nature of
possible coding errors. For example, one very common
error when writing a memory model is to get the size of
the internal storage wrong. Here's how..

module memory #(parameter Abits = 8, Dbits = 8)
(input [Abits-1:0] A, input [Dbits-1:0 WrData, ...);
...
reg [Dbits-1:0] storage [0:Abits-1]; // OOOOPS!

Here, as you can see, we parameterized the model for
address bus width, but got the storage array size wrong;
it should be [0:(1<<Abits)-1]. A test that exercises
only the first few locations of the memory would not
find this error.

Also, if you do any manipulation whatsoever on the
address or data lines, that could be a source of error.
Examples might be using one or more upper address bits
as block selects, or using partial words of a wide
memory to store narrow data words. All these operations
could have errors, and must be verified.

An interesting way to check your testbench: try
deliberately introducing an error in your design
code. Then run the testbench again, and see if
it detects the error. If it doesn't, then your
testbench clearly is not sufficiently thorough.
Don't forget to take the error out of your design
again before you start to use it! Typical errors
might be: flip one bit of the data when reading;
don't do a read operation for certain address
values; ....

Note that some "errors" may not actually cause
any error at all. For example, if you perform
some simple operation (like logical-NOT) on the
address every time you use it, the only effect
is to rearrange the memory locations within your
storage array. The overall read/write behaviour
of the memory would be unaffected. So you should
not expect your testbench to find that "bug".

Finally, be aware that Verilog testbenches can
make access to memory "by the back door". You can
pre-load your memory with known contents from the
testbench, and then read out those contents through
the usual read mechanisms; similarly you could write
locations in the usual way and then get the testbench
to look directly at the memory array and check that
the values had been correctly written. Here's an
example that is very incomplete but nevertheless shows
you a bunch of good tricks. Reading this code carefully
and trying to identify its (many) limitations would be
a useful exercise for you, I suspect.

Of course, my usual licence terms apply: this code
is free for any kind of commercial use, but attracts
a one-time fee of $2000 if used in whole or part in
the solution to any academic assignment (fee increased
to $3000 if such solution receives an A grade).

////////////////////////////////////////////////////////////////

module memory (input [3:0] WA, input [7:0] WD,
input [3:0] RA, output [7:0] RD,
input clock, input WrEn);
reg [7:0] storage [0:15];
always @(posedge clock) begin
RD <= storage[RA];
// You could inject an error by something like
// RD <= storage[RA] & 8'hFE; // force LSB to zero
if (WrEn) storage[WA] = WD;
// Other error injection possibilities:
// modify WrEn by XORing it with an address bit?
// modify WA or WD before this operation?
end
endmodule

////////////////////////////////////////////////////////////////

module test_mem;
wire [7:0] RD;
reg [3:0] WA, RA;
reg [7:0] WD;
reg clock, WrEn;

memory DUT (WA, WD, RA, RD, clock, WrEn);

// This task does everything needed to make
// one access to the memory.
task doCycle(
input [3:0] WrAdrs,
input [3:0] RdAdrs,
input [7:0] WrData,
input Write,
output [7:0] RdData
);
begin
clock = 0;
// Set up read address.
RA = RdAdrs;
// Set up write data and address. Trash
// them if it's not really a write cycle.
WrEn = Write;
if (Write) begin
WA = WrAdrs;
WD = WrData;
end else begin
WA = 4'bx;
WD = 8'bx;
end
// Do posedge of clock after some setup time
#5 clock = 1;
// Get the read data after some settling time
#5 RdData = RD;
end
endtask

initial begin : SimpleTest
integer i;
reg [7:0] readData;
integer goodRead, goodWrite;
// Fill the memory storage array by the back door,
// using 100-address as the data in each location
for (i=0; i<16; i=i+1)
DUT.storage = 100-i;
// Check all those locations are right using the
// standard read mechanism. At the same time,
// use the standard write mechanism to put a
// different value into each location.
goodRead = 0;
for (i=0; i<16; i=i+1) begin
doCycle(
i, // write to address
i, // and read from address i
30+i, // write data is (30+1)
1, // enable a write on this cycle
readData // put read data into this variable
);
if (readData !== 100-i)
$display("bad read data 8'b%b at [%0d]",
readData, i);
else
goodRead = goodRead + 1;
$display("read test completed with %0d good", goodRead);
// Finally, use back-door access to check that the write
// operations were successful
goodWrite = 0;
for (i=0; i<16; i=i+1)
if (DUT.storage !== 30+i)
$display("bad written data 8'b%b at [%0d]",
DUT.storage, i);
else
goodWrite = goodWrite + 1;
$display("write test completed with %0d good", goodWrite);
end

endmodule

////////////////////////////////////////////////////////////////
--
Jonathan Bromley
 
On Tue, 02 Feb 2010 10:47:08 +0100, Jonathan Bromley wrote:


Sorry, two typos in the code:

(1) missing 'reg' keyword:
WD,
input [3:0] RA, output [7:0] RD,
should be input [3:0] RA, output reg [7:0] RD,

(2) missing 'end':
else
goodRead = goodRead + 1;
end // inserted
$display("read test completed with %0d good", goodRead);
Otherwise OK.
--
Jonathan Bromley
 

Welcome to EDABoard.com

Sponsor

Back
Top