register file in verilog

R

rekz

Guest
I am asked to implement a register file with 2 read ports and 1 read
ports, the read ports are each 5-bits. The data is 32 bits. What
components do I need to implement this? I think I need a d-flip flop
to store the bits and as well as a mux, what else do I need?
 
rekz wrote:
I am asked to implement a register file with 2 read ports and 1 read
ports, the read ports are each 5-bits. The data is 32 bits. What
components do I need to implement this? I think I need a d-flip flop
to store the bits and as well as a mux, what else do I need?
A text editor and simulator.
Leave the flops and muxes to synthesis.

-- Mike Treseler
 
rekz wrote:

So that's it? I am just confused on how they will be connected to each
other....
Synthesis tools have an RTL viewer
to see the LUTs flops and wires.

-- Mike Treseler
 
On Jan 25, 11:16 pm, Mike Treseler <mtrese...@gmail.com> wrote:
rekz wrote:
I am asked to implement a register file with 2 read ports and 1 read
ports, the read ports are each 5-bits. The data is 32 bits. What
components do I need to implement this? I think I need a d-flip flop
to store the bits and as well as a mux, what else do I need?

A text editor and simulator.
Leave the flops and muxes to synthesis.

    -- Mike Treseler
So that's it? I am just confused on how they will be connected to each
other....
 
On Jan 26, 9:57 am, Mike Treseler <mtrese...@gmail.com> wrote:
rekz wrote:
So that's it? I am just confused on how they will be connected to each
other....

Synthesis tools have an RTL viewer
to see the LUTs flops and wires.

     -- Mike Treseler
What Mike is trying to say, is focus first on how you want the
register file to behave, on a clock cycle by cycle basis. Code that
using a clocked always block (assuming all ports use the same clock),
then take a look at the RTL viewer to see what the synthesizer thinks
you need. Hint: you will probably want to use an array to describe
storing the data.

I assume you meant "2 read ports and 1 write port"? When you said the
data is 32 bits, is that the width of the write port? Are all three
ports independent and simultaneously usable? These are all questions
which must be answered before you can describe the behavior.

Andy
 
On Jan 26, 9:41 am, Andy <jonesa...@comcast.net> wrote:
On Jan 26, 9:57 am, Mike Treseler <mtrese...@gmail.com> wrote:

rekz wrote:
So that's it? I am just confused on how they will be connected to each
other....

Synthesis tools have an RTL viewer
to see the LUTs flops and wires.

     -- Mike Treseler

What Mike is trying to say, is focus first on how you want the
register file to behave, on a clock cycle by cycle basis. Code that
using a clocked always block (assuming all ports use the same clock),
then take a look at the RTL viewer to see what the synthesizer thinks
you need. Hint: you will probably want to use an array to describe
storing the data.

I assume you meant "2 read ports and 1 write port"? When you said the
data is 32 bits, is that the width of the write port? Are all three
ports independent and simultaneously usable? These are all questions
which must be answered before you can describe the behavior.

Andy
There is a write data which is 32 bit.
 
On Jan 26, 12:34 pm, rekz <aditya15...@gmail.com> wrote:
On Jan 26, 9:41 am, Andy <jonesa...@comcast.net> wrote:



On Jan 26, 9:57 am, Mike Treseler <mtrese...@gmail.com> wrote:

rekz wrote:
So that's it? I am just confused on how they will be connected to each
other....

Synthesis tools have an RTL viewer
to see the LUTs flops and wires.

     -- Mike Treseler

What Mike is trying to say, is focus first on how you want the
register file to behave, on a clock cycle by cycle basis. Code that
using a clocked always block (assuming all ports use the same clock),
then take a look at the RTL viewer to see what the synthesizer thinks
you need. Hint: you will probably want to use an array to describe
storing the data.

I assume you meant "2 read ports and 1 write port"? When you said the
data is 32 bits, is that the width of the write port? Are all three
ports independent and simultaneously usable? These are all questions
which must be answered before you can describe the behavior.

Andy

There is a write data which is 32 bit.
Is it just like this:

reg [31:0] A;
wire [31:0] b;
always @(posedge clock) A <= b;
module registerfi le (Read1,Read2,WriteReg,WriteData,RegWrite,
Data1,Data2,clock);
input [5:0] Read1,Read2,WriteReg; // the register numbers
to read or write
input [31:0] WriteData; // data to write
input RegWrite, // the write control
clock; // the clock to trigger write
output [31:0] Data1, Data2; // the register values read
reg [31:0] RF [31:0]; // 32 registers each 32 bits long
assign Data1 = RF[Read1];
assign Data2 = RF[Read2];
always begin
// write the register with new value if Regwrite is
high
@(posedge clock) if (RegWrite) RF[WriteReg] <WriteData;
end
endmodule
 
That should work, at least on a functional level. You'll likely get
flip-flops and muxes/decoders, intead of distributed RAMs (if xilinx).
You may have to manually duplicate the register array (always writing
same data to both), one array for each read port, in order to get
distributed dual port rams. If you want block rams, you need to
register the read addresses (synchronous read). Try it and see.

Andy
 
On Jan 26, 1:58 pm, Andy <jonesa...@comcast.net> wrote:
That should work, at least on a functional level. You'll likely get
flip-flops and muxes/decoders, intead of distributed RAMs (if xilinx).
You may have to manually duplicate the register array (always writing
same data to both), one array for each read port, in order to get
distributed dual port rams. If you want block rams, you need to
register the read addresses (synchronous read). Try it and see.

Andy
What do you mean by duplicate the register array? You mean not puting
Data1, Data2 not on the same line?
Also because this will be synthesized, why is it better to have the
design structurally? As the one I have above is behaviorly
 
On Tue, 26 Jan 2010 13:50:25 -0800 (PST), rekz wrote:

On Jan 26, 1:58 pm, Andy <jonesa...@comcast.net> wrote:
That should work, at least on a functional level.
I think the addresses should be only 5 bits wide, not 6.
Otherwise, yes. I'm not sure what this piece of code
was about, though...

reg [31:0] A;
wire [31:0] b;
always @(posedge clock) A <= b;

One of the greatest skills any engineer, or student
of engineering, must develop is that of carefully
choosing the colleague whose code you plan to
steal; you need to find someone who is neither
incompetent nor litigious. This can be tricky.

What do you mean by duplicate the register array?
If your target device includes some kind of RAM
structure that has one write and one read port,
it is probably impossible to read from two different
addresses at the same time. The usual solution is
to create two copies of the memory, having exactly
the same write address and write data. The two
copies then have exactly the same contents, and you
can get one read port from one of them and the other
read port from the second.

In practice this is probably irrelevant. You
described RAM with asynchronous read. In most
FPGAs this can't be done in the built-in RAM
blocks, which are fully synchronous. It *can*
be done in LUT-based (distributed) RAM, but that
usually has only one address input to serve both
read and write addresses.

The result is that your memory will be implemented
as ordinary registers; reading is then achieved
using multiplexers, and there is no fundamental
limit to the number of independent read ports -
each read port will be implemented as a 32-way
multiplexer. So it is likely that the registers
will not be duplicated.

Also because this will be synthesized, why is it
better to have the design structurally?
It isn't better. Who told you that?

However, it IS better - much, much better - to
design RAM whose behaviour matches the resources
available on your target FPGA.
--
Jonathan Bromley
 
On Jan 27, 2:30 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Tue, 26 Jan 2010 13:50:25 -0800 (PST), rekz wrote:
On Jan 26, 1:58 pm, Andy <jonesa...@comcast.net> wrote:
That should work, at least on a functional level.

I think the addresses should be only 5 bits wide, not 6.
Otherwise, yes.  I'm not sure what this piece of code
was about, though...

  reg [31:0] A;
  wire [31:0] b;
  always @(posedge clock) A <= b;

One of the greatest skills any engineer, or student
of engineering, must develop is that of carefully
choosing the colleague whose code you plan to
steal; you need to find someone who is neither
incompetent nor litigious.  This can be tricky.

What do you mean by duplicate the register array?

If your target device includes some kind of RAM
structure that has one write and one read port,
it is probably impossible to read from two different
addresses at the same time.  The usual solution is
to create two copies of the memory, having exactly
the same write address and write data.  The two
copies then have exactly the same contents, and you
can get one read port from one of them and the other
read port from the second.

In practice this is probably irrelevant.  You
described RAM with asynchronous read.  In most
FPGAs this can't be done in the built-in RAM
blocks, which are fully synchronous.  It *can*
be done in LUT-based (distributed) RAM, but that
usually has only one address input to serve both
read and write addresses.

The result is that your memory will be implemented
as ordinary registers; reading is then achieved
using multiplexers, and there is no fundamental
limit to the number of independent read ports -
each read port will be implemented as a 32-way
multiplexer.  So it is likely that the registers
will not be duplicated.

Also because this will be synthesized, why is it
better to have the design structurally?

It isn't better.  Who told you that?

However, it IS better - much, much better - to
design RAM whose behaviour matches the resources
available on your target FPGA.
--
Jonathan Bromley
If I would like to change this code behaviorly then the code would be
pretty long, right? I would need a d flip flop for the registers and a
mux for the read schema and then I would need a
to use a decoder for the write and put them into one
 
On Jan 27, 3:30 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
In practice this is probably irrelevant.  You
described RAM with asynchronous read.  In most
FPGAs this can't be done in the built-in RAM
blocks, which are fully synchronous.  It *can*
be done in LUT-based (distributed) RAM, but that
usually has only one address input to serve both
read and write addresses.
Xilinx has distributed rams (lut based, w/async reads) in both single
port and dual port versions. The dual port version shares the write
port address with one of the read ports, so you have one read/write
port and another read port. If you want separate, completely
independent read (2) and write (1) ports, you will need two rams, and
store every write in both of them. You can code this behavior with two
identical arrays, and store the written data in both, but I've heard
that some synthesizers will automatically do this for you, so try it
first by reading data from two addresses from the same array and see
what happens.

Also because this will be synthesized, why is it
better to have the design structurally?

It isn't better.  Who told you that?
I absolutely agree! A behavioral (cycle based) description from which
your synthesis tool can create an acceptable (speed/area/power/??)
implementation is almost always preferable to a structural
implementation. A behavioral descripion is easier to design, write,
read, review, understand, simulate, debug, reuse and port to different
target architectures.

Sometimes you just can't describe the behavior in a way that the
synthesis tool will create an acceptable implementation, and then (and
only then) you will have to create a structural description.

Andy
 
On Jan 27, 2:30 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Tue, 26 Jan 2010 13:50:25 -0800 (PST), rekz wrote:
On Jan 26, 1:58 pm, Andy <jonesa...@comcast.net> wrote:
That should work, at least on a functional level.

I think the addresses should be only 5 bits wide, not 6.
Otherwise, yes.  I'm not sure what this piece of code
was about, though...

  reg [31:0] A;
  wire [31:0] b;
  always @(posedge clock) A <= b;

One of the greatest skills any engineer, or student
of engineering, must develop is that of carefully
choosing the colleague whose code you plan to
steal; you need to find someone who is neither
incompetent nor litigious.  This can be tricky.

What do you mean by duplicate the register array?

If your target device includes some kind of RAM
structure that has one write and one read port,
it is probably impossible to read from two different
addresses at the same time.  The usual solution is
to create two copies of the memory, having exactly
the same write address and write data.  The two
copies then have exactly the same contents, and you
can get one read port from one of them and the other
read port from the second.

In practice this is probably irrelevant.  You
described RAM with asynchronous read.  In most
FPGAs this can't be done in the built-in RAM
blocks, which are fully synchronous.  It *can*
be done in LUT-based (distributed) RAM, but that
usually has only one address input to serve both
read and write addresses.

The result is that your memory will be implemented
as ordinary registers; reading is then achieved
using multiplexers, and there is no fundamental
limit to the number of independent read ports -
each read port will be implemented as a 32-way
multiplexer.  So it is likely that the registers
will not be duplicated.

Also because this will be synthesized, why is it
better to have the design structurally?

It isn't better.  Who told you that?

However, it IS better - much, much better - to
design RAM whose behaviour matches the resources
available on your target FPGA.
--
Jonathan Bromley
If I were just doing this for a testbench and not synthesis it, it
would work right?
 
On Jan 27, 9:45 am, rekz <aditya15...@gmail.com> wrote:
On Jan 27, 2:30 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com
wrote:



On Tue, 26 Jan 2010 13:50:25 -0800 (PST), rekz wrote:
On Jan 26, 1:58 pm, Andy <jonesa...@comcast.net> wrote:
That should work, at least on a functional level.

I think the addresses should be only 5 bits wide, not 6.
Otherwise, yes.  I'm not sure what this piece of code
was about, though...

  reg [31:0] A;
  wire [31:0] b;
  always @(posedge clock) A <= b;

One of the greatest skills any engineer, or student
of engineering, must develop is that of carefully
choosing the colleague whose code you plan to
steal; you need to find someone who is neither
incompetent nor litigious.  This can be tricky.

What do you mean by duplicate the register array?

If your target device includes some kind of RAM
structure that has one write and one read port,
it is probably impossible to read from two different
addresses at the same time.  The usual solution is
to create two copies of the memory, having exactly
the same write address and write data.  The two
copies then have exactly the same contents, and you
can get one read port from one of them and the other
read port from the second.

In practice this is probably irrelevant.  You
described RAM with asynchronous read.  In most
FPGAs this can't be done in the built-in RAM
blocks, which are fully synchronous.  It *can*
be done in LUT-based (distributed) RAM, but that
usually has only one address input to serve both
read and write addresses.

The result is that your memory will be implemented
as ordinary registers; reading is then achieved
using multiplexers, and there is no fundamental
limit to the number of independent read ports -
each read port will be implemented as a 32-way
multiplexer.  So it is likely that the registers
will not be duplicated.

Also because this will be synthesized, why is it
better to have the design structurally?

It isn't better.  Who told you that?

However, it IS better - much, much better - to
design RAM whose behaviour matches the resources
available on your target FPGA.
--
Jonathan Bromley

If I were just doing this for a testbench and not synthesis it, it
would work right?
If I want the outputs of registers specified by Read1 and Read2 are
written into output registers Data1 and Data2 at the falling edge of
the clock, then I would change the following to my code

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

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

@(posedge Clk)
if (RegWrite)
RF[WriteRegister] <= WriteData;

end

why doesn't this work?
 
On Thu, 28 Jan 2010 11:11:05 -0800 (PST), rekz wrote:

If I want the outputs of registers specified by Read1 and Read2 are
written into output registers Data1 and Data2 at the falling edge of
the clock, then I would change the following to my code

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

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

@(posedge Clk)
if (RegWrite)
RF[WriteRegister] <= WriteData;

end

why doesn't this work?
Because you used the "assign" keyword in procedural
code (the begin...end body of your always block).
It is legal syntax, but does not do what you want.
Until you know a lot more about Verilog, please
do NOT use the "assign" keyword for any purpose
except continuous assignment to a net, at the top
level of a module and NOT inside an always block
or any other procedural code.

You probably want nonblocking assignment to
ReadData1 and ReadData2:

always @(negedge Clk) begin
ReadData1 <= RF[address1];
ReadData2 <= RF[address2];
end

--
Jonathan Bromley
 
On Fri, 29 Jan 2010 06:54:25 -0800 (PST), rekz wrote:

You probably want nonblocking assignment to
ReadData1 and ReadData2:

  always @(negedge Clk) begin
    ReadData1 <= RF[address1];
    ReadData2 <= RF[address2];
  end

I tried that too, but it gives me this error now:

ERROR:HDLCompilers:247 - "RegisterFile.v" line 33 Reference to vector
wire 'ReadData1' is not a legal reg or variable lvalue

ReadData1 = RF[ReadRegister1];
How familiar are you with the difference between
variables (reg) and nets (wire) in Verilog? I suggest
that should be your next topic for study.
--
Jonathan Bromley
 
On Jan 29, 2:08 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Thu, 28 Jan 2010 11:11:05 -0800 (PST), rekz wrote:
If I want the outputs of registers specified by Read1 and Read2 are
written into output registers Data1 and Data2 at the falling edge of
the clock, then I would change the following to my code

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

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

@(posedge Clk)
if (RegWrite)
   RF[WriteRegister] <= WriteData;

end

why doesn't this work?

Because you used the "assign" keyword in procedural
code (the begin...end body of your always block).
It is legal syntax, but does not do what you want.
Until you know a lot more about Verilog, please
do NOT use the "assign" keyword for any purpose
except continuous assignment to a net, at the top
level of a module and NOT inside an always block
or any other procedural code.

You probably want nonblocking assignment to
ReadData1 and ReadData2:

  always @(negedge Clk) begin
    ReadData1 <= RF[address1];
    ReadData2 <= RF[address2];
  end

--
Jonathan Bromley
I tried that too, but it gives me this error now:

ERROR:HDLCompilers:247 - "RegisterFile.v" line 33 Reference to vector
wire 'ReadData1' is not a legal reg or variable lvalue

ReadData1 = RF[ReadRegister1];
 
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
 
On Jan 29, 8:43 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Fri, 29 Jan 2010 06:54:25 -0800 (PST), rekz wrote:
You probably want nonblocking assignment to
ReadData1 and ReadData2:

  always @(negedge Clk) begin
    ReadData1 <= RF[address1];
    ReadData2 <= RF[address2];
  end
I tried that too, but it gives me this error now:

ERROR:HDLCompilers:247 - "RegisterFile.v" line 33 Reference to vector
wire 'ReadData1' is not a legal reg or variable lvalue

ReadData1 = RF[ReadRegister1];

How familiar are you with the difference between
variables (reg) and nets (wire) in Verilog?  I suggest
that should be your next topic for study.
--
Jonathan Bromley
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

@(posedge Clk)
if (RegWrite)
RF[WriteRegister] <= WriteData;

end
 
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?
 

Welcome to EDABoard.com

Sponsor

Back
Top