cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Adventurer
Adventurer
19,302 Views
Registered: ‎01-13-2012

Multi ported RAM in FPGA

Hi, I am a final year student doing a project titled Multi ported memory in FPGA. I have a small query regarding the conventional techniques of multi porting memories. I am aware of replication and multi-pumping to increase the number of read and write ports. However I am still confused about the concept of banking. For instance, if I have a single port BLOCK RAM and replicate it to form 1W/2R memory and bank this with another replicated block RAM, will I have 4 memory locations shared between the two writ ports? Please do solve this doubt of mine. If there is any information on the internet, please do let me know as I have found none. Thanks
Tags (2)
0 Kudos
33 Replies
Highlighted
Instructor
Instructor
19,294 Views
Registered: ‎07-21-2009

The term "bank" is a flexible and imprecise term.  Please describe what "bank" means with more detail.

 

Or you can describe what you wish to accomplish.  Do you seek a 1W/2R memory?  If so, the simplest design is two BRAMs -- duplicate copies of a single memory -- with the WRITE port connected together (shared WRITE address and WRITE data) while the two READ ports remain independently addressed and accessed.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
19,272 Views
Registered: ‎01-13-2012

Thank you Mr. Bob for your explaination. 

 

But what you explained is the process of replication. 1W/ 2R memory. According to some literature which I gathered from some papers, there are three conventional techniques for multiporting memories in FPGA viz. replication, multi pumping and banking.

 

I plan to design a 4W/8R multi ported memory module. I wish to incorporate replication and banking. 

 

With a simple example consider I am designing a 2W/2R memory module. First I take a dual port memory BRAM and then  with replication I design a 1W/2R memory module. I take another dual port BRAM and do the same process of replication. Now, if I have to bank these two modules, how will the memory be divided? WIll the write ports write to any memory address now that it is a banked module?

 

Thanks

0 Kudos
Highlighted
Adventurer
Adventurer
19,271 Views
Registered: ‎01-13-2012

www.eecg.toronto.edu/~steffan/papers/laforest_fpga10.pdf is a paper I am using as base for my project. I hope this helps
0 Kudos
Highlighted
Instructor
Instructor
19,268 Views
Registered: ‎07-21-2009

But what you explained is the process of replication. 1W/ 2R memory.

 

Yes.  This is the simplest implementation, if multiple read ports are needed.

 

According to some literature which I gathered from some papers, there are three conventional techniques for multiporting memories in FPGA viz. replication, multi pumping and banking.

 

The paper you linked explains the meaning of "banking".  I am familiar with this approach being called "address segmentation", rather than "banking".

 

I plan to design a 4W/8R multi ported memory module. I wish to incorporate replication and banking.

 

With a simple example consider I am designing a 2W/2R memory module. First I take a dual port memory BRAM and then  with replication I design a 1W/2R memory module. I take another dual port BRAM and do the same process of replication. Now, if I have to bank these two modules, how will the memory be divided?

 

The limitations of such banking schemes must be considered.  If the limitations compromise the rest of your design, then perhaps the rest of your design and/or your multi-porting scheme should be modified.  This is a tradeoff you must make based on your requirements, of which we (forum readers) are almost entirely ignorant.  This is where you, as the designer, may apply any available and possible cleverness which may be at your disposal.

 

WIll the write ports write to any memory address now that it is a banked module?

 

In its pure form, "banking" requires that a write to any single address can be completed in only one of the multiple memory banks.  In other words, there is no freedom to direct a write transaction to any of the banked modules.

 

The paper you linked omits at least two additional memory port multiplication schemes:

  • Write port replication, with scoreboarding to track which copy holds the valid (latest) data
  • Posted writes, where actual write bandwidth need be no greater than sustained longterm average write activity.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
19,233 Views
Registered: ‎01-13-2012

Thank you Mr. Bob for your advise.

 

I tried simulating a 2w/4r banked structure made from true dual port BRAMs. 

 

The RTL synthesis shows no anomalies and the instantiation seems correct. However no output on my output ports. 

 

Can you shed some light on any mistake I might have made on the code.

 

The code for the banked structure is as below:

 

module banked_memory_2w4r(clock, write_en,addr_0,addr_1,addr_2,addr_3,write_data_0,write_data_1,read_data_0,

read_data_1,read_data_2,read_data_3
);

input clock;

input write_en;

input [7:0]  addr_0;

input [7:0]  addr_1;

input [7:0]  addr_2;

input [7:0]  addr_3;

 

input [31:0] write_data_0;

input [31:0] write_data_1;

 

output [31:0] read_data_0;

output [31:0] read_data_1;

output [31:0] read_data_2;

output [31:0] read_data_3;


reg [7:0] muxed_addr_0;
reg [7:0] muxed_addr_1;


try1 bank_0 (
.clock(clock), 
.we_0(write_en),
.we_1(write_en),
.addr_0(addr_0),
.addr_1(addr_1),
.data_0(write_data_0),
.data_1(write_data_1),
.read_data0(read_data_0),
.read_data1(read_data_1)
);

try1 bank_1 (
.clock(clock), 
.we_0(write_en),
.we_1(write_en),
.addr_0(muxed_addr_0),
.addr_1(muxed_addr_1),
.data_0(write_data_0),
.data_1(write_data_1),
.read_data0(read_data_2),
.read_data1(read_data_3)
);

 

 

always @(write_en) begin
case(write_en)

1'b1: begin
muxed_addr_0 <= addr_0;
muxed_addr_1 <= addr_1;
end

1'b0: begin
muxed_addr_0 <= addr_2;
muxed_addr_1 <= addr_3; 
end

default: begin
muxed_addr_0 <= addr_2;
muxed_addr_1 <= addr_3;
end

endcase
end


endmodule

 

Below is the code of true dual port memory in Write First mode

 

module try1(clock, we_0,we_1, data_0,data_1, addr_0,addr_1, read_data0, read_data1
);

input clock;
input we_0;
input we_1;
input [7:0] addr_0;
input [7:0] addr_1;
input [31:0] data_0;
input [31:0] data_1;

output reg [31:0] read_data0;
output reg [31:0] read_data1;

reg [31:0] ram [0:1023];

always @(posedge clock)
begin
if (we_0) begin
ram[addr_0] <= data_0; 
read_data0 <= data_0;
end
else
read_data0 <= ram[addr_0];
end

always @(posedge clock)
begin
if (we_1) begin
ram[addr_1] <= data_1;
read_data1 <= data_1;
end
else
read_data1 <= ram[addr_1];
end


endmodule

 

Attached is the screenshot of the testbench results.

screenshot.bmp
0 Kudos
Highlighted
Instructor
Instructor
19,226 Views
Registered: ‎07-21-2009

It appears from your simulation that the write enable is never asserted  when needed (on positive edge of the clock).

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
19,221 Views
Registered: ‎01-13-2012

I changed the sensitivity list to include posedge clock. But still I am not able to see any output on my read_ports. 

 

If you would like to view the testbench, it is given below.

 

module testering;

// Inputs
reg clock;
reg write_en;
reg [7:0] addr_0;
reg [7:0] addr_1;
reg [7:0] addr_2;
reg [7:0] addr_3;
reg [31:0] write_data_0;
reg [31:0] write_data_1;

// Outputs
wire [31:0] read_data_0;
wire [31:0] read_data_1;
wire [31:0] read_data_2;
wire [31:0] read_data_3;

// Instantiate the Unit Under Test (UUT)
banked_memory_2w4r uut (
.clock(clock),
.write_en(write_en),
.addr_0(addr_0),
.addr_1(addr_1),
.addr_2(addr_2),
.addr_3(addr_3),
.write_data_0(write_data_0),
.write_data_1(write_data_1),
.read_data_0(read_data_0),
.read_data_1(read_data_1),
.read_data_2(read_data_2),
.read_data_3(read_data_3)
);

initial
clock = 1'b0;

always

#50 clock = ~clock;

initial
#100000 $finish;

initial begin

#60 write_en = 1'b1;
#20 addr_0 = 8'b10101010; write_data_0 = 32'd56;
        addr_1 = 8'b11001100; write_data_1 = 32'd44;

#40 write_en = 1'b0;
#20 addr_0 = 8'b11001100;

#40 write_en = 1'b1;
#20 addr_2 = 8'b10101010; write_data_0 = 32'd77;

#20 write_en = 1'b0;
#20 addr_0 = 8'b11001100; addr_2 = 8'b10101010; 
end

endmodule

0 Kudos
Highlighted
Instructor
Instructor
19,218 Views
Registered: ‎07-21-2009

I changed the sensitivity list to include posedge clock. But still I am not able to see any output on my read_ports.

 

Yes, you are seeing output on your read ports.  The output is "U" (undefined).

 

Your design won't write data to a register unless the write enable is asserted at the positive edge of the RAM/register array clock.  You should know this already, since you wrote the code you posted.  So update your testbench code to provide wider write enable pulses.  If you are going to use the clock construct to generate the write enable input signal, the write enable pulse width should be twice as wide as the clock pulse.

 

Please, as a favour to everyone reading your posts, format your code in the fixed-pitch COURIER font or use the code button (second icon left of the smiley face in the toolbar).  This will make your posts much more readable, with less effort.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
19,197 Views
Registered: ‎01-13-2012

I realized my mistake in the testbench. Thanks for pointing it out. 

 

The design works perfect.  However I have expanded this design to make a 4w/8r memory using true dual BRAMs.

 

When I synthesize my design I get the following error:

 

ERROR:Xst:3232 - You are apparently trying to describe a RAM with several write ports for signal <Mram_ram>. This RAM cannot be implemented using distributed resources.

 

In the process properties window, the RAM inference is set to Block mode. Then why the above error?? I have explicitly defined its inference.

 

I could post the code, but its too big and has too many modules. If you still need the code I could send it immediately. 

0 Kudos
Highlighted
Teacher
Teacher
15,537 Views
Registered: ‎09-09-2010

What FPGA are you targetting?
What version of tools?

------------------------------------------
"If it don't work in simulation, it won't work on the board."
0 Kudos
Highlighted
Adventurer
Adventurer
15,530 Views
Registered: ‎01-13-2012

I no longer getting that error.

 

I am targetting the design on VIRTEX 5 and I am using Xilinx ISE v13.

 

In my previous posts about designing the banked memory structure, I am viewing another anamoly in my design. The testbench is attached with this. 

 

I am writing data into address 0 using write_data_0 and I would like to read from the same address. However on doing that, I am getting two outputs, one from read_data_0 of bank0 and read_data_0 of bank1( which is read_data_2 of enitre banked structure). y RTL schematic shows the proper routing of address signals and mux working. What am I doing wrong?

screenshot.bmp
0 Kudos
Highlighted
Instructor
Instructor
15,517 Views
Registered: ‎07-21-2009

In your code, please consider the highlighted lines and comments:

 

module try1(clock, we_0,we_1, data_0,data_1, addr_0,addr_1, read_data0, read_data1);

input clock;
input we_0;
input we_1;
input [7:0] addr_0;  // 8 address bits implies 256-word (deep) RAM
input [7:0] addr_1;  // 8 address bits implies 256-word (deep) RAM
input [31:0] data_0;
input [31:0] data_1;

output reg [31:0] read_data0;
output reg [31:0] read_data1;


reg [31:0] ram [0:1023];  // this infers a 32-bit wide, 1K deep RAM

 

always @(posedge clock)
  begin
    if (we_0) begin
      ram[addr_0] <= data_0; // addressing a 1K deep RAM with only 8-bit address
      read_data0 <= data_0;
      end
    else
      read_data0 <= ram[addr_0]; // addressing a 1K deep RAM with only 8-bit address
  end


always @(posedge clock)
  begin
    if (we_1) begin
      ram[addr_1] <= data_1; // addressing a 1K deep RAM with only 8-bit address
      read_data1 <= data_1;
      end
    else
      read_data1 <= ram[addr_1]; // addressing a 1K deep RAM with only 8-bit address
  end


endmodule

 

Note the mismatch in RAM depth (1K, a 10bit address space) vs. addresses (8-bit, or 256-deep memory)

 

Also, it is not permitted to assign values to a single register (or RAM) in two different processes.  You must combine the memory assignments into a single process, or instantiate separate memories for each process.  UPDATE:  Please ignore this warning, it is incorrect.  See post #15 in this thread for details.

 

I am writing data into address 0 using write_data_0 and I would like to read from the same address. However on doing that, I am getting two outputs, one from read_data_0 of bank0 and read_data_0 of bank1( which is read_data_2 of enitre banked structure). y RTL schematic shows the proper routing of address signals and mux working. What am I doing wrong?

 

Please post your updated code.  Comments in your code would be helpful as well.

 

Please, as a favour to everyone reading your posts, format your code in the fixed-pitch COURIER font or use the code button (second icon left of the smiley face in the toolbar).  This will make your posts much more readable, with less effort.

 

Are any warning or error messages reported when you synthesise your design?  There are likely some valuable clues in the warning messages.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
15,502 Views
Registered: ‎01-13-2012

The updated code for my banked memory module:

 

module memory_2w8r(clock, write_en, addr_0, addr_1, addr_2, addr_3, addr_4, addr_5, addr_6, addr_7, write_data_0, write_data_1,
read_data_0, read_data_1, read_data_2, read_data_3, read_data_4, read_data_5, read_data_6, read_data_7);
    

input clock;
input write_en;

input [7:0] addr_0;
input [7:0] addr_1;
input [7:0] addr_2;
input [7:0] addr_3;
input [7:0] addr_4;
input [7:0] addr_5;
input [7:0] addr_6;
input [7:0] addr_7;

input [31:0] write_data_0;
input [31:0] write_data_1;

output [31:0] read_data_0;
output [31:0] read_data_1;
output [31:0] read_data_2;
output [31:0] read_data_3;
output [31:0] read_data_4;
output [31:0] read_data_5;
output [31:0] read_data_6;
output [31:0] read_data_7;

reg [7:0] muxed_addr_0;
reg [7:0] muxed_addr_1;
reg [7:0] muxed_addr_2;
reg [7:0] muxed_addr_3;
reg [7:0] muxed_addr_4;
reg [7:0] muxed_addr_5;


true_dual bank0 (
    .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(addr_0),
    .addr_1(addr_1),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_0),
    .read_data1(read_data_1)
);

true_dual bank_1 (
     .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(muxed_addr_0),
    .addr_1(muxed_addr_1),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_2),
    .read_data1(read_data_3)
);


true_dual bank_2 (
     .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(muxed_addr_2),
    .addr_1(muxed_addr_3),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_4),
    .read_data1(read_data_5)
);


true_dual bank_3 (
     .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(muxed_addr_4),
    .addr_1(muxed_addr_5),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_6),
    .read_data1(read_data_7)
);

    always @(*) begin
    case(write_en)

        1'b1: begin
          muxed_addr_0 <= addr_0;
	       muxed_addr_1 <= addr_1;
	       muxed_addr_2 <= addr_0;
          muxed_addr_3 <= addr_1;
          muxed_addr_4 <= addr_0;
          muxed_addr_5 <= addr_1;
        end

        1'b0: begin
	muxed_addr_0 <= addr_2;
        muxed_addr_1 <= addr_3;
	muxed_addr_2 <= addr_4;
	muxed_addr_3 <= addr_5;
	muxed_addr_4 <= addr_6;
	muxed_addr_5 <= addr_7;
	end
    endcase

end


endmodule

 The verilog code for the true dual port memory is below:

module true_dual(clock, we_0,we_1, data_0,data_1, addr_0,addr_1, read_data0, read_data1
    );

input clock;
input we_0;
input we_1;
input [7:0] addr_0;
input [7:0] addr_1;
input [31:0] data_0;
input [31:0] data_1;

output reg [31:0] read_data0;
output reg [31:0] read_data1;

reg [31:0] ram [0:255];

always @(posedge clock)
begin
    if (we_0) 
	   ram[addr_0] <= data_0; 
		
	   read_data0 <= ram[addr_0] ;
	end
	
	
always @(posedge clock)
begin
    if (we_1) 
	   ram[addr_1] <= data_1; 
		
	   read_data1 <= ram[addr_1] ;
	end
	
endmodule

 There are no warnings or errors. 

 

Also, could you explain the below statement:

 

Also, it is not permitted to assign values to a single register (or RAM) in two different processes.  You must combine the memory assignments into a single process, or instantiate separate memories for each process.

 

Does this mean I cannot write data into address 8'b10101010 at different clock cycles? Why?

 

Thank you

0 Kudos
Highlighted
Instructor
Instructor
15,500 Views
Registered: ‎07-21-2009

This is complicated...  Please read this all the way through to the end...

 

Also, could you explain the below statement:

 

Also, it is not permitted to assign values to a single register (or RAM) in two different processes.  You must combine the memory assignments into a single process, or instantiate separate memories for each process.

 

Hardware and software are different.  In software you can write to a register in any line of code, or in any code module.  In HDL (Verilog or VHDL) describing hardware, the description of any hardware register must be contained within a single process.

 

Here is one process:

always @(posedge clock)
  begin

    if (we_0) ram[addr_0] <= data_0;

    read_data0 <= ram[addr_0] ;
  end


Here is another process:

always @(posedge clock)
  begin
    if (we_1) ram[addr_1] <= data_1;

    read_data1 <= ram[addr_1] ;
  end

 

The same RAM cannot be described twice, in two different processes.  As a self-identified guru of everything (I am being sarcastic, and you will see why in the next few lines), this cannot synthesise correctly, and the two processes must be combined into a single process.

 

But...  it does synthesise and it does "build" under XST, and the mighty "guru of everything" (referring to me) is quite wrong.  The RAM array is recognised by XST as a dual-port RAM with two independent write ports.  This makes complete sense.  There is no "legal" way to infer a dual-port RAM with independent clocks in a single process -- because a single process is limited to a single clock.

 

And this is the reason for my self-mocking as "guru of everything".  It turns out that something I understood with complete confidence apparently has an exception which is entirely useful and reasonable in the context of Xilinx FPGA design.  I "knew" something I didn't actually know, in other words.

 

If you tried to do the same thing (infer a register in multiple processes) with a single register (rather than RAM), synthesis would fail and report a "multiple drivers" error.

 

Summary:  After explaining in moderate detail why I must be right, it turns out that I am wrong ...  in the case of a dual-port RAM with independent clocks.  So, please ignore my warning.

 

Does this mean I cannot write data into address 8'b10101010 at different clock cycles? Why?

 

No, please ignore my warning.  I was mistaken.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Instructor
Instructor
15,494 Views
Registered: ‎07-21-2009

Your updated code looks good, to me.  Have the simulation results changed?

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
15,491 Views
Registered: ‎01-13-2012

Thank you Mr Bob for clarifying ,my doubt.

 

I was able to understand the error but I am not able to understand why it occurs. I will explain it along with the attached screenshot of my testbench results.

 

Initially, I write data into two address ports when write_en is high. Later I read from address port 0 and address port 7 when write_en goes low.

 

Now, if you have a look at the screenshot, you will observe outputs from read_data_0 and read_data_1 and a clock cycle later you will observe output from read_data_7 which is the same value as from read_data_1. 

 

In other words, it takes one clock cycle extra for the multiplier to change addresses depending on the write_en signal.

 

However my coding has non blocking statements and I am not able to understand the one clock cycle delay. Is there any coding alternative to rectify this clock delay?

 

Thanks and regards

imp.bmp
0 Kudos
Highlighted
Instructor
Instructor
15,486 Views
Registered: ‎07-21-2009

You should add the muxed_addr_n signals to your simulation trace.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
15,478 Views
Registered: ‎01-13-2012

The complete code for my multiported design is as follows

module my_multipumped_memory(clock, write_en, write_data_0, write_data_1, write_data_2, write_data_3, 
write_addr2, write_addr3, addr_0, addr_1, addr_2, addr_3, addr_4, addr_5, addr_6, addr_7, read_data_0, read_data_1, read_data_2,
read_data_3, read_data_4, read_data_5, read_data_6, read_data_7);
 
input clock;
input write_en;

input [7:0] addr_0;
input [7:0] addr_1;
input [7:0] addr_2;
input [7:0] addr_3;
input [7:0] addr_4;
input [7:0] addr_5;
input [7:0] addr_6;
input [7:0] addr_7;
input [7:0] write_addr2;
input [7:0] write_addr3;

input [31:0] write_data_0;
input [31:0] write_data_1;
input [31:0] write_data_2;
input [31:0] write_data_3;

output  [31:0] read_data_0;
output  [31:0] read_data_1;
output  [31:0] read_data_2;
output  [31:0] read_data_3;
output  [31:0] read_data_4;
output  [31:0] read_data_5;
output  [31:0] read_data_6;
output  [31:0] read_data_7; 

wire [31:0] read_data_0_0;
wire [31:0] read_data_0_1;
wire [31:0] read_data_0_2;
wire [31:0] read_data_0_3;
wire [31:0] read_data_0_4;
wire [31:0] read_data_0_5;
wire [31:0] read_data_0_6;
wire [31:0] read_data_0_7;

wire [31:0] read_data_1_0;
wire [31:0] read_data_1_1;
wire [31:0] read_data_1_2;
wire [31:0] read_data_1_3;
wire [31:0] read_data_1_4;
wire [31:0] read_data_1_5;
wire [31:0] read_data_1_6;
wire [31:0] read_data_1_7;

reg [7:0] muxeaddr_2;
reg [7:0] muxeaddr_3;

wire read_0;
wire read_1;
wire read_2;
wire read_3;
wire read_4;
wire read_5;
wire read_6;
wire read_7;

always @(*) begin

if(write_en == 1'b1) begin
muxeaddr_2 <= write_addr2;
muxeaddr_3 <= write_addr3;
end

else begin
muxeaddr_2 <= addr_0;
muxeaddr_3 <= addr_1;
end

end

lvt_4w8r lvt(
.clock(clock),
.enable(write_en),
.write_address_0(addr_0),
.write_address_1(addr_1),
.write_address_2(muxeaddr_2),
.write_address_3(muxeaddr_3),
.read_addr_4(addr_4),
.read_addr_5(addr_5),
.read_addr_6(addr_6),
.read_addr_7(addr_7),
.read_addr_tag_0(read_0),
.read_addr_tag_1(read_1),
.read_addr_tag_2(read_2),
.read_addr_tag_3(read_3),
.read_addr_tag_4(read_4),
.read_addr_tag_5(read_5),
.read_addr_tag_6(read_6),
.read_addr_tag_7(read_7)
);


memory_2w8r mem0 (
.clock(clock),
.write_en(write_en),
.write_data_0(write_data_0),
.write_data_1(write_data_1),
.addr_0(addr_0),
.addr_1(addr_1),
.addr_2(addr_2),
.addr_3(addr_3),
.addr_4(addr_4),
.addr_5(addr_5),
.addr_6(addr_6),
.addr_7(addr_7),
.read_data_0(read_data_0_0),
.read_data_1(read_data_0_1),
.read_data_2(read_data_0_2),
.read_data_3(read_data_0_3),
.read_data_4(read_data_0_4),
.read_data_5(read_data_0_5),
.read_data_6(read_data_0_6),
.read_data_7(read_data_0_7)
);

memory_2w8r mem1 (
.clock(clock),
.write_en(write_en),
.write_data_0(write_data_2),
.write_data_1(write_data_3),
.addr_0(muxeaddr_2),
.addr_1(muxeaddr_3),
.addr_2(addr_2),
.addr_3(addr_3),
.addr_4(addr_4),
.addr_5(addr_5),
.addr_6(addr_6),
.addr_7(addr_7),
.read_data_0(read_data_1_0),
.read_data_1(read_data_1_1),
.read_data_2(read_data_1_2),
.read_data_3(read_data_1_3),
.read_data_4(read_data_1_4),
.read_data_5(read_data_1_5),
.read_data_6(read_data_1_6),
.read_data_7(read_data_1_7)
);

MUX_data_2to1 m0(
.clock(clock),
.selector(read_0),
.data_0(read_data_0_0),
.data_1(read_data_1_0),
.output_data(read_data_0)
);


MUX_data_2to1 m1(
.clock(clock),
.selector(read_1),
.data_0(read_data_0_1),
.data_1(read_data_1_1),
.output_data(read_data_1)
);


MUX_data_2to1 m2(
.clock(clock),
.selector(read_2),
.data_0(read_data_0_2),
.data_1(read_data_1_2),
.output_data(read_data_2)
);


MUX_data_2to1 m3(
.clock(clock),
.selector(read_3),
.data_0(read_data_0_3),
.data_1(read_data_1_3),
.output_data(read_data_3)
);


MUX_data_2to1 m4(
.clock(clock),
.selector(read_4),
.data_0(read_data_0_4),
.data_1(read_data_1_4),
.output_data(read_data_4)
);


MUX_data_2to1 m5(
.clock(clock),
.selector(read_5),
.data_0(read_data_0_5),
.data_1(read_data_1_5),
.output_data(read_data_5)
);


MUX_data_2to1 m6(
.clock(clock),
.selector(read_6),
.data_0(read_data_0_6),
.data_1(read_data_1_6),
.output_data(read_data_6)
);


MUX_data_2to1 m7(
.clock(clock),
.selector(read_7),
.data_0(read_data_0_7),
.data_1(read_data_1_7),
.output_data(read_data_7)
);



endmodule

 In the above code, there are two registers voz. muxeaddr_2 and muxeaddr_3. These two 8bit address signals ae connected to write_addr2 and write_addr3 when write_en is high and to addr_0 and addr_1 when write_en is low.

 

When I creat the test bench, muxeaddr_2 and muxeaddr_3 show unknown values despite writing address values into write_addr2 and write_addr3. I used the same muxing concept in 2W/8R banked structure and it works perfectly fine. The code to my 2W/8R is given below:

module memory_2w8r(clock, write_en, addr_0, addr_1, addr_2, addr_3, addr_4, addr_5, addr_6, addr_7, write_data_0, write_data_1,
read_data_0, read_data_1, read_data_2, read_data_3, read_data_4, read_data_5, read_data_6, read_data_7);
    

input clock;
input write_en;

input [7:0] addr_0;
input [7:0] addr_1;
input [7:0] addr_2;
input [7:0] addr_3;
input [7:0] addr_4;
input [7:0] addr_5;
input [7:0] addr_6;
input [7:0] addr_7;

input [31:0] write_data_0;
input [31:0] write_data_1;

output [31:0] read_data_0;
output [31:0] read_data_1;
output [31:0] read_data_2;
output [31:0] read_data_3;
output [31:0] read_data_4;
output [31:0] read_data_5;
output [31:0] read_data_6;
output [31:0] read_data_7;

reg [7:0] muxed_addr_0;
reg [7:0] muxed_addr_1;
reg [7:0] muxed_addr_2;
reg [7:0] muxed_addr_3;
reg [7:0] muxed_addr_4;
reg [7:0] muxed_addr_5;


true_dual bank0 (
    .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(addr_0),
    .addr_1(addr_1),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_0),
    .read_data1(read_data_1)
);

true_dual bank_1 (
     .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(muxed_addr_0),
    .addr_1(muxed_addr_1),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_2),
    .read_data1(read_data_3)
);


true_dual bank_2 (
     .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(muxed_addr_2),
    .addr_1(muxed_addr_3),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_4),
    .read_data1(read_data_5)
);


true_dual bank_3 (
     .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(muxed_addr_4),
    .addr_1(muxed_addr_5),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_6),
    .read_data1(read_data_7)
);


always @(*) begin
    if(write_en == 1'b1) begin
        muxed_addr_0 <= addr_0;
        muxed_addr_1 <= addr_1;
		  muxed_addr_2 <= addr_0;
        muxed_addr_3 <= addr_1;
        muxed_addr_4 <= addr_0;
        muxed_addr_5 <= addr_1;
    end
    else begin
        muxed_addr_0 <= addr_2;
        muxed_addr_1 <= addr_3;
		  muxed_addr_2 <= addr_4;
	     muxed_addr_3 <= addr_5;
	     muxed_addr_4 <= addr_6;
	     muxed_addr_5 <= addr_7;
    end
end
endmodule

 What is the mistake I am making?

 

Thanks and regards

0 Kudos
Highlighted
Instructor
Instructor
15,476 Views
Registered: ‎07-21-2009

When I creat the test bench, muxeaddr_2 and muxeaddr_3 show unknown values...

 

Both muxeaddr_2 and muxeaddr_3 are generated by combinatorial assignments from signals which are all module inputs.

 

always @(*)
  if(write_en == 1'b1) begin
    muxeaddr_2 <= write_addr2;
    muxeaddr_3 <= write_addr3;
    end
  else begin
    muxeaddr_2 <= addr_0;
    muxeaddr_3 <= addr_1;
    end

 

The signals muxeaddr_2 and muxeaddr_3 cannot be unknown unless one or more of these signals (all of which are module inputs) is also unknown:

  • write_en
  • write_addr2
  • write_addr3
  • addr_0
  • addr_1

Does this make sense?

Are there any error or warning messages from the synthesis tool?

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
15,117 Views
Registered: ‎01-13-2012

Yes sir. My apologies. They do not show any unknown values.

 

I wrongly stated my error. 

0 Kudos
Highlighted
Instructor
Instructor
15,116 Views
Registered: ‎07-21-2009

Yes sir. My apologies. They do not show any unknown values. I wrongly stated my error.

 

It was your turn :)  This makes the two of us even (see posts #13 and #15 in this thread).

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
15,107 Views
Registered: ‎01-13-2012

Perhaps this is my last glitch in the mltiported memory design.

 

In the testbench screen shot, please focus on the following signals: clock, write_en, addr_3 and read_data3.

 

As you can observe, when I am giving a address input at addr_3 I get the corresponding updated value stored in that address displayed through read_data3. That is observed through the first cyle of write_en

 

However, on carefully observing the next cycle of write_en, for one time cycle a different value is shown and then the correct value is displayed on the next clock cycle. What is the reason for this glitch?

 

Thanks

error2.bmp
0 Kudos
Highlighted
Instructor
Instructor
15,104 Views
Registered: ‎07-21-2009

However, on carefully observing the next cycle of write_en, for one time cycle a different value is shown and then the correct value is displayed on the next clock cycle. What is the reason for this glitch?

 

Suggest you re-simulate, with all the signals in the path to read_data_3 included in the simulation.  The register read_data_3 is the output of a clocked mux_data_2to1 block, but the code for this block has not been posted.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
15,100 Views
Registered: ‎01-13-2012

I have attached the creenshot of all the signals leading to the read_data3. 

 

read_data_3 is the output from reading address input address_3. This output is the final output port of the multi-ported design.

 

addr_3 is the input address port of the multiported design.

 

Now, read_data_3 is the output obtained from the MUX based on the following working. There are two inputs to the MUX. One input is the data stored at address X from Bank 1 and the other input is the data stored at same address X from Bank2. The control signal determines which bank has the recently written value for that address. The signals for the MUX are as follows: selector, data_0 (data from Bank 0), data_1 (data from bank 1) and output_data.

 

The input to the MUX us from the output of Bank 1 and Bank 0 for the corresponding read_addr input. In this case for addr_3, the inputs to the MUX are the outputs read_data_0_3 which is output from bank 0 and read_data_1_3 which is output from bank 1. 

 

As you can observe data from read_data_0_3 will be sonsidered because the selector signal indicates that Bank 0 is the right bank. Hence I have also included signals from Bank 0. The signals from Bank 0 are clock, we_0, we_1, addr_0, addr_1, data_0, data_1, read_data0 and read_data1.

 

Also, at 600ns the value which is partially covered is the binary equivalent of 390. The testbench and the coding for MUX is given below.

 

my_multipumped_memory uut (
		.clock(clock), 
		.write_en(write_en), 
		.write_data_0(write_data_0), 
		.write_data_1(write_data_1), 
		.write_data_2(write_data_2), 
		.write_data_3(write_data_3), 
		.write_addr2(write_addr2), 
		.write_addr3(write_addr3), 
		.addr_0(addr_0), 
		.addr_1(addr_1), 
		.addr_2(addr_2), 
		.addr_3(addr_3), 
		.addr_4(addr_4), 
		.addr_5(addr_5), 
		.addr_6(addr_6), 
		.addr_7(addr_7), 
		.read_data_0(read_data_0), 
		.read_data_1(read_data_1), 
		.read_data_2(read_data_2), 
		.read_data_3(read_data_3), 
		.read_data_4(read_data_4), 
		.read_data_5(read_data_5), 
		.read_data_6(read_data_6), 
		.read_data_7(read_data_7)
	);

	initial
	clock = 1'b1;
	
	always
	#50 clock = ~clock;
	
	initial
	#10000 $finish;
	
	initial
	write_en = 1'b1;
	
	always
	#200 write_en = ~write_en;
	
	initial
	#10000 $finish;
	
	initial
	begin
	#30 write_data_2 = 32'd86;  write_addr2 = 8'b11001100;
		 write_data_3 = 32'd144; write_addr3 = 8'b10010110;
		 write_data_0 = 32'd118; addr_0 = 8'b11011010;
		 write_data_1 = 32'd390; addr_1 = 8'b00110101;
		 
		  #180 
				
				addr_3 = 8'b11011010;
				
		
				
		
		 end
		 
		 
      
endmodule

 Below is the code for MUX

 

module MUX_data_2to1(selector, data_0, data_1, output_data);

input selector;

input [31:0] data_0;
input [31:0] data_1;

output reg [31:0] output_data;

always @(*) begin

    case(selector)

        1'b0: begin
			output_data <= data_0;
        end

        1'b1: begin
			output_data <= data_1;
        end


    endcase
end

endmodule

 Thanks

main error.bmp
0 Kudos
Highlighted
Instructor
Instructor
15,087 Views
Registered: ‎07-21-2009

I sat down to try to chase down your problem, and I came across a roadblock.

 

Your code calls module MUX_data_2to1, and clock is on the module port list (see post #19 in this thread).

Then you post the code for module MUX_data_2to1, and this module has no clock port (see post #25 in this thread).

 

It seems that I am tracing through pieces of code from two different sets (revisions) of your code.  Please let us know when your code settles down.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
15,077 Views
Registered: ‎01-13-2012

Sir,

 

The clock is not part of the MUX. The code that I have posted recent is the final code for the MUX.

 

Thank you for your help and guidance.

0 Kudos
Highlighted
Adventurer
Adventurer
15,075 Views
Registered: ‎01-13-2012

Also I have another small doubt.

 

Suppose I have the following declaration for a memory register

 

reg [31:0] ram [0:255].

 

The above implies a 32 bit data width RAM of 256 memory locations. Assume that read_Addr is a signal that accesses the RAM. If I want to change the 30th bit of the data stored at read_Addr say from one to zero, how do I do it?

 

Thank you once again for your valuable help and guidance. 

0 Kudos
Highlighted
Instructor
Instructor
15,072 Views
Registered: ‎07-21-2009

The clock is not part of the MUX. The code that I have posted recent is the final code for the MUX.

 

The rest of your code includes additional changes, so please post your entire code from a single version along with matching simulation results.

 

reg [31:0] ram [0:255].

 

The above implies a 32 bit data width RAM of 256 memory locations. Assume that read_Addr is a signal that accesses the RAM. If I want to change the 30th bit of the data stored at read_Addr say from one to zero, how do I do it?

 

  • Select this bit as follows:  ram[read_Addr][30].
  • The MSB of the addressed memory word is ram[read_Addr][31]
  • The LSB of the addressed memory word is ram[read_Addr][0]

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Highlighted
Adventurer
Adventurer
15,060 Views
Registered: ‎01-13-2012

The following is the code to the design.

 

The top level module of the multiported design

module my_multipumped_memory(clock, write_en, write_data_0, write_data_1, write_data_2, write_data_3, 
write_addr2, write_addr3, addr_0, addr_1, addr_2, addr_3, addr_4, addr_5, addr_6, addr_7, read_data_0, read_data_1, read_data_2,
read_data_3, read_data_4, read_data_5, read_data_6, read_data_7);
 
input clock;
input write_en;

input [7:0] addr_0;
input [7:0] addr_1;
input [7:0] addr_2;
input [7:0] addr_3;
input [7:0] addr_4;
input [7:0] addr_5;
input [7:0] addr_6;
input [7:0] addr_7;
input [7:0] write_addr2;
input [7:0] write_addr3;

input [31:0] write_data_0;
input [31:0] write_data_1;
input [31:0] write_data_2;
input [31:0] write_data_3;

output  [31:0] read_data_0;
output  [31:0] read_data_1;
output  [31:0] read_data_2;
output  [31:0] read_data_3;
output  [31:0] read_data_4;
output  [31:0] read_data_5;
output  [31:0] read_data_6;
output  [31:0] read_data_7; 

wire [31:0] read_data_0_0;
wire [31:0] read_data_0_1;
wire [31:0] read_data_0_2;
wire [31:0] read_data_0_3;
wire [31:0] read_data_0_4;
wire [31:0] read_data_0_5;
wire [31:0] read_data_0_6;
wire [31:0] read_data_0_7;

wire [31:0] read_data_1_0;
wire [31:0] read_data_1_1;
wire [31:0] read_data_1_2;
wire [31:0] read_data_1_3;
wire [31:0] read_data_1_4;
wire [31:0] read_data_1_5;
wire [31:0] read_data_1_6;
wire [31:0] read_data_1_7;

reg [7:0] muxeaddr_2;
reg [7:0] muxeaddr_3;

wire read_0;
wire read_1;
wire read_2;
wire read_3;
wire read_4;
wire read_5;
wire read_6;
wire read_7;

always @(*) begin

if(write_en == 1'b1) begin
muxeaddr_2 <= write_addr2;
muxeaddr_3 <= write_addr3;
end

else begin
muxeaddr_2 <= addr_0;
muxeaddr_3 <= addr_1;
end

end

lvt_4w8r lvt(
.clock(clock),
.enable(write_en),
.write_address_0(addr_0),
.write_address_1(addr_1),
.write_address_2(muxeaddr_2),
.write_address_3(muxeaddr_3),
.read_addr_0(addr_0),
.read_addr_1(addr_1),
.read_addr_2(addr_2),
.read_addr_3(addr_3),
.read_addr_4(addr_4),
.read_addr_5(addr_5),
.read_addr_6(addr_6),
.read_addr_7(addr_7),
.read_addr_tag_0(read_0),
.read_addr_tag_1(read_1),
.read_addr_tag_2(read_2),
.read_addr_tag_3(read_3),
.read_addr_tag_4(read_4),
.read_addr_tag_5(read_5),
.read_addr_tag_6(read_6),
.read_addr_tag_7(read_7)
);


memory_2w8r mem0 (
.clock(clock),
.write_en(write_en),
.write_data_0(write_data_0),
.write_data_1(write_data_1),
.addr_0(addr_0),
.addr_1(addr_1),
.addr_2(addr_2),
.addr_3(addr_3),
.addr_4(addr_4),
.addr_5(addr_5),
.addr_6(addr_6),
.addr_7(addr_7),
.read_data_0(read_data_0_0),
.read_data_1(read_data_0_1),
.read_data_2(read_data_0_2),
.read_data_3(read_data_0_3),
.read_data_4(read_data_0_4),
.read_data_5(read_data_0_5),
.read_data_6(read_data_0_6),
.read_data_7(read_data_0_7)
);

memory_2w8r mem1 (
.clock(clock),
.write_en(write_en),
.write_data_0(write_data_2),
.write_data_1(write_data_3),
.addr_0(muxeaddr_2),
.addr_1(muxeaddr_3),
.addr_2(addr_2),
.addr_3(addr_3),
.addr_4(addr_4),
.addr_5(addr_5),
.addr_6(addr_6),
.addr_7(addr_7),
.read_data_0(read_data_1_0),
.read_data_1(read_data_1_1),
.read_data_2(read_data_1_2),
.read_data_3(read_data_1_3),
.read_data_4(read_data_1_4),
.read_data_5(read_data_1_5),
.read_data_6(read_data_1_6),
.read_data_7(read_data_1_7)
);

MUX_data_2to1 m0(

.selector(read_0),
.data_0(read_data_0_0),
.data_1(read_data_1_0),
.output_data(read_data_0)
);


MUX_data_2to1 m1(

.selector(read_1),
.data_0(read_data_0_1),
.data_1(read_data_1_1),
.output_data(read_data_1)
);


MUX_data_2to1 m2(

.selector(read_2),
.data_0(read_data_0_2),
.data_1(read_data_1_2),
.output_data(read_data_2)
);


MUX_data_2to1 m3(

.selector(read_3),
.data_0(read_data_0_3),
.data_1(read_data_1_3),
.output_data(read_data_3)
);


MUX_data_2to1 m4(

.selector(read_4),
.data_0(read_data_0_4),
.data_1(read_data_1_4),
.output_data(read_data_4)
);


MUX_data_2to1 m5(

.selector(read_5),
.data_0(read_data_0_5),
.data_1(read_data_1_5),
.output_data(read_data_5)
);


MUX_data_2to1 m6(

.selector(read_6),
.data_0(read_data_0_6),
.data_1(read_data_1_6),
.output_data(read_data_6)
);


MUX_data_2to1 m7(

.selector(read_7),
.data_0(read_data_0_7),
.data_1(read_data_1_7),
.output_data(read_data_7)
);



endmodule

  The Memory controller (Live Vaue Table) is below:

module lvt_4w8r (clock, enable, write_address_0, write_address_1, write_address_2, write_address_3, read_addr_0, read_addr_1, read_addr_2, read_addr_3, read_addr_4,read_addr_5, read_addr_6, read_addr_7,read_addr_tag_0, read_addr_tag_1, read_addr_tag_2, read_addr_tag_3, read_addr_tag_4, read_addr_tag_5, 
read_addr_tag_6, read_addr_tag_7);

input clock;
input enable;

input [7:0] write_address_0;
input [7:0] write_address_1;
input [7:0] write_address_2;
input [7:0] write_address_3;
input [7:0] read_addr_0;
input [7:0] read_addr_1;
input [7:0] read_addr_2;
input [7:0] read_addr_3;
input [7:0] read_addr_4;
input [7:0] read_addr_5;
input [7:0] read_addr_6;
input [7:0] read_addr_7;


output reg  read_addr_tag_0;
output reg  read_addr_tag_1;
output reg  read_addr_tag_2;
output reg  read_addr_tag_3;
output reg  read_addr_tag_4;
output reg  read_addr_tag_5;
output reg  read_addr_tag_6;
output reg  read_addr_tag_7;


reg [0:0] live_value_table [0:255];

always @(posedge clock) begin
if(enable) begin
    live_value_table[write_address_0] <= 1'b0;
    live_value_table[write_address_1] <= 1'b0;
    live_value_table[write_address_2] <= 1'b1;
    live_value_table[write_address_3] <= 1'b1;
end
else
begin
    read_addr_tag_0 <= live_value_table[read_addr_0];
    read_addr_tag_1 <= live_value_table[read_addr_1];
    read_addr_tag_2 <= live_value_table[read_addr_2];
    read_addr_tag_3 <= live_value_table[read_addr_3];
    read_addr_tag_4 <= live_value_table[read_addr_4];
    read_addr_tag_5 <= live_value_table[read_addr_5];  
    read_addr_tag_6 <= live_value_table[read_addr_6];
    read_addr_tag_7 <= live_value_table[read_addr_7];    
end

end
endmodule

 The Banked 2W/8R memory is given below:

module memory_2w8r(clock, write_en, addr_0, addr_1, addr_2, addr_3, addr_4, addr_5, addr_6, addr_7, write_data_0, write_data_1,
read_data_0, read_data_1, read_data_2, read_data_3, read_data_4, read_data_5, read_data_6, read_data_7);
    

input clock;
input write_en;

input [7:0] addr_0;
input [7:0] addr_1;
input [7:0] addr_2;
input [7:0] addr_3;
input [7:0] addr_4;
input [7:0] addr_5;
input [7:0] addr_6;
input [7:0] addr_7;


input [31:0] write_data_0;
input [31:0] write_data_1;

output [31:0] read_data_0;
output [31:0] read_data_1;
output [31:0] read_data_2;
output [31:0] read_data_3;
output [31:0] read_data_4;
output [31:0] read_data_5;
output [31:0] read_data_6;
output [31:0] read_data_7;

reg [7:0] muxed_addr_0;
reg [7:0] muxed_addr_1;
reg [7:0] muxed_addr_2;
reg [7:0] muxed_addr_3;
reg [7:0] muxed_addr_4;
reg [7:0] muxed_addr_5;


true_dual bank0 (
    .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(addr_0),
    .addr_1(addr_1),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_0),
    .read_data1(read_data_1)
);

true_dual bank_1 (
     .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(muxed_addr_0),
    .addr_1(muxed_addr_1),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_2),
    .read_data1(read_data_3)
);


true_dual bank_2 (
     .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(muxed_addr_2),
    .addr_1(muxed_addr_3),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_4),
    .read_data1(read_data_5)
);


true_dual bank_3 (
     .clock(clock),        
    .we_0(write_en),
    .we_1(write_en),
    .addr_0(muxed_addr_4),
    .addr_1(muxed_addr_5),
    .data_0(write_data_0),
    .data_1(write_data_1),
    .read_data0(read_data_6),
    .read_data1(read_data_7)
);


always @(*) begin
    if(write_en == 1'b1) begin
        muxed_addr_0 <= addr_0;
        muxed_addr_1 <= addr_1;
		  muxed_addr_2 <= addr_0;
        muxed_addr_3 <= addr_1;
        muxed_addr_4 <= addr_0;
        muxed_addr_5 <= addr_1;
    end
    else begin
        muxed_addr_0 <= addr_2;
        muxed_addr_1 <= addr_3;
		  muxed_addr_2 <= addr_4;
	     muxed_addr_3 <= addr_5;
	     muxed_addr_4 <= addr_6;
	     muxed_addr_5 <= addr_7;
    end
end
endmodule

 The MUX 2 to 1 is given below

module MUX_data_2to1(selector, data_0, data_1, output_data);

input selector;

input [31:0] data_0;
input [31:0] data_1;

output reg [31:0] output_data;

always @(*) begin

    case(selector)

        1'b0: begin
			output_data <= data_0;
        end

        1'b1: begin
			output_data <= data_1;
        end


    endcase
end

endmodule

 The code for the single true dual BRAM is given below:

module true_dual(clock, we_0,we_1, data_0,data_1, addr_0,addr_1, read_data0, read_data1
    );

input clock;
input we_0;
input we_1;
input [7:0] addr_0;
input [7:0] addr_1;
input [31:0] data_0;
input [31:0] data_1;

output reg [31:0] read_data0;
output reg [31:0] read_data1;

reg [31:0] ram [0:255];

always @(posedge clock)
begin
   if (we_0) begin
       ram[addr_0] <= data_0;
   end
	else
   read_data0 <= ram[addr_0] ;
end
	
	
always @(posedge clock)
begin
   if (we_1) begin
       ram[addr_1] <= data_1;
   end
	else
   read_data1 <= ram[addr_1] ;
end
endmodule

The simulation screenshots are from this code.

 

 Thank you for your help.

Regards

 

0 Kudos