- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic to the Top
- Bookmark
- Subscribe
- Printer Friendly Page
Re: Multi ported RAM in FPGA
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
02-21-2012 03:10 AM
What version of tools?
------------------------------------------
"If it don't work in simulation, it won't work on the board."
Re: Multi ported RAM in FPGA
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
02-24-2012 10:51 PM
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?
UPDATED: Multi ported RAM in FPGA
[ Edited ]- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
02-25-2012 12:03 AM - edited 02-25-2012 10:32 PM
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
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.
Re: Multi ported RAM in FPGA
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
02-25-2012 08:26 PM
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
Re: Multi ported RAM in FPGA
[ Edited ]- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
02-25-2012 10:21 PM - edited 02-25-2012 10:26 PM
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
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.
Re: Multi ported RAM in FPGA
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
02-25-2012 10:37 PM
Your updated code looks good, to me. Have the simulation results changed?
-- Bob Elkind
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.
Re: Multi ported RAM in FPGA
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
02-26-2012 03:53 AM
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
Re: Multi ported RAM in FPGA
[ Edited ]- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
02-26-2012 07:31 AM - edited 02-26-2012 07:32 AM
You should add the muxed_addr_n signals to your simulation trace.
-- Bob Elkind
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.
Re: Multi ported RAM in FPGA
- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
02-26-2012 11:54 PM
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
unknown values in sim
[ Edited ]- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content
02-27-2012 12:24 AM - edited 02-27-2012 12:27 AM
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
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.











