I am trying to write a behavioral code in verilog describing a RAM that has 256 locations, each of size 64-bits. so, I created a module RAM_cell that has output data_out and input data_in,both of width 64 bits. then, I created another module called RAM within which, I declared,
RAM_cell mem [255:0] (data_out,data_in,rd);
the RAM reads from 8-bit Maddr when rd=1 or writes to Maddrwhen rd=0.Now
in the module RAM, which has Mdata_out as output, for read operation, I wrote,
always #(posedge clk)
initial
begin
if (rd == 1'b1)
Mdata_in = mem[Maddr].data_out;
end
that didn't work. the compiler threw error that the indexing variable is not a constant.
Why didn't it work? what are the other ways (Other than using case statement using 256 control signals..!!).
Thank you. Any help will be highly appreciated.
PS: I can upload all necessary data (like exact code,compiler output,etc..) on demand.
This is similar to the generate..endgenerate. the compiler allocates the number of instances you required. The array index will become a part of the name.
So it will create 256 uniquely named instances like m[0], m[1], ... where '[]' will be just a part of the generated name. You cannot index into it. There is no such name as 'mem[Maddr]'
So, instead you should index your data_out.
I do not recommend using this construct at all due to confusing syntax around it. Instead use a generate block and a for loop to instantiate it. In this case you would have a complete control over what you pass to it:
generate
for(geni = 0; geni < 256; geni++) begin: loop
RAM_cell mem (data_out[geni],data_in[geni],rd);
end
endgenerate
always #* begin
...
Mdata_in = data_out[Maddr];
...
end
If you insist on XMR (non synthesizable) to access internal signals in the 'mem', you can put your always block inside the 'for' loop and use 'mem.sig'
Related
I'm having trouble understanding this error I'm getting in Yosys.
I copied the relevant (I think) code below.
reg signed [15:0] wb1 [0:131071];
reg signed [27:0] currentAttrWB [0:4094];
always #(posedge clk)
currentAttrWB <= wb1[attrWBoffset +: 4094];
ERROR (on last line): "currentAttrWB does map to an unexpanded memory!"
What I'm trying to do is select a sub-range of 4095 16bit words in a long array of 131072 16bit words, using indexed part select (+:). This range would be offset within the long array using attrWBoffset. But obviously there is something I am not understanding. At first I thought this was because currentAttrWB was not large enough to contain 4095 16bit words. But I still get the error when bumping its register up to 28bits.
I guess I need to understand what is meant by expanded and unexpanded.
Thanks for your help.
Yosys does not support memories, i.e. anything defined as reg [x:0] mem[0:y]; being on the left hand side of an assignment. I am not sure if this is a Yosys limitation or a Verilog one, but such a pattern makes little sense for an FPGA application where memories are accessed one element at a time.
If Yosys could implement such a pattern, it would have to map the memory to LUTs and flipflops rather than use dedicated RAM resources, as such a simultaneous transfer isn't possible with block RAM. There are very few FPGAs with over 2 million flipflops available, and if you had one you probably wouldn't want to fill it up with something like this.
What you probably want is a counter that counts from 0 to 4094 and copies one entry every clock cycle until it completes.
I am having trouble initializing the contents of an inferred ram in Verilog. The code for the ram is as below:
module ram(
input clock, // System clock
input we, // When high RAM sets data in input lines to given address
input [13:0] data_in, // Data lines to write to memory
input [10:0] addr_in, // Address lines for saving data to memory
input [10:0] addr_out, // Address for reading from ram
output reg data_out // Data out
);
reg [13:0] ram[2047:0];
// Initialize RAM from file
// WHAT SHOULD GO HERE?
always #(posedge clock) begin
// Save data to RAM
if (we) begin
ram[addr_in] <= data_in;
end
// Place data from RAM
data_out <= ram[addr_out];
end
endmodule
I have run into the command $readmemh. However, documentation for it seems sparse. How should I format the file that contains the data? Also, how can I pass the file as argument when instantiating this module so that I can have different instances of this module load from different files?
I want the initialized content to be available for both simulation and actual implementation. So that the FPGA already boots with this content in RAM.
I am using Vivado 2015.4 to program a Kintex xc7k70 FPGA.
You are correct that you should use $readmemh inside an initial block. In order to make it so different instances of the module can have different initialization files, you should use a parameter like so:
parameter MEM_INIT_FILE = "";
...
initial begin
if (MEM_INIT_FILE != "") begin
$readmemh(MEM_INIT_FILE, ram);
end
end
The format is described in Section 21.4 of the IEEE1800-2012 specification; typically the file is just a bunch of lines containing hex numbers of the correct bit-length, like so:
0001
1234
3FFF
1B34
...
Note that there is no "0x" prefix and each line represents an adjacent address (or any separating whitespace). In the example above, $readmemh would put 14'h0001 into ram[0], 14'h1234 into ram[1], 14'h3FFF into ram[2] and so on. You can also include comments in the hex file using // or /* */. Finally, you can use the # symbol to designate an address for the following numbers to be located at, like so:
#0002
0101
0A0A
...
In the above file, ram[0] and ram[1] would be uninitialized and ram[2] would get 14'h0101. Those are all the major constructs of the hex file format, though you can also use _, x and z as you would in other Verilog numbers and theres a few more rules you can read in the section sited above.
Apart from #Unn's excellent ans, I want to add that, If you just want to initialize your memory with either all bits to 1'b1 or 1'b0, then you can just put following code,
integer j;
initial
for(j = 0; j < DEPTH; j = j+1)
ram[j] = {WIDTH{MEM_INIT_VAL}};
For your case, WIDTH=14, and MEM_INIT_VAL may be 1'b1 or 1'b0.
Since your question cited the #xilinx and #vivado tags, I wanted to suggest that you can also use the xpm_memory family of primitives to instantiate a parameterized memory. The advantages of this approach:
Exports exactly the hardware capabilities of the memory resources on the FPGA (ie, makes you think clearly about limitations such as memory ports).
Guarantees correct identical behavior in simulation and benchtop for memory primitives.
You can allow Vivado to choose the most efficient memory implementation (BRAM, UltraRAM, distributed RAM, flops) at synthesis time, according to your design constraints.
Easy to fine tune (enable or disable internal pipeline stages, etc.).
With that said, purely inferred memories are often easier to code. But, it's still worth getting familiar with the Xilinx-provided memory primitives so that you'll have a clearer idea of what Vivado can easily synthesize, and what it can't.
For more information, see UG573, the Vivado Memory Resources User Guide:
https://www.xilinx.com/support/documentation/user_guides/ug573-ultrascale-memory-resources.pdf
integer j;
initial
for(j = 0; j < DEPTH; j = j+1)
ram[j] = j;
This might be easy in case of debug, where the value of a location is its location number.
Also, I would suggest you to not initialize the RAMs. It will help you in catching bugs, if any, in simulation as the data driven will be 'x if RAM is un-intialized and can be caught easily.
I am trying to create a memory shift operation in verilog and was wondering the best way to do it. An example code is:
reg [MSB:0] a [0:NO_OF_LOCATIONS];
// after some processing
for(i =0; i <= NO_OF_LOCATIONS; i= i+1)
a[i] = a[i+1]
If I use a ROM in Xilinx it can only do synchronize writes and I need to do all the shifts within one clock cycle. If I do use a memory as above I am not sure if on board implementation will result in metastability or don't care propagation.
Also what would be the best way to do it instead of a for loop?
I am assuming this is part of a clocked synchronous block, i.e. something like the following (it would not make much sense otherwise and you wrote "I need to do all the shifts within one clock cycle", which implies that this is part of a synchronous design):
reg [MSB:0] a [0:NO_OF_LOCATIONS];
always #(posedge clk)
if (...) begin
for(i =0; i < NO_OF_LOCATIONS; i= i+1)
a[i] <= a[i+1];
a[NO_OF_LOCATIONS] <= ...;
end
// also use a[] somewhere
assign a0 = a[0];
Btw: a[] has NO_OF_LOCATIONS+1 locations in it. I'm not sure if this is intended but I just left it that way. Usually the range of a[] would be written as [0:NO_OF_LOCATIONS-1] for NO_OF_LOCATIONS memory locations.
Notice that I have changed the assignment = to <=. When assigning something in a clocked always-block and the thing you assign to is read anywhere outside that always-block then you must assign non-blocking (i.e. with <=) in order to avoid race conditions in simulation that can lead to simulation-synthesis mismatches.
Also notice that I have factored out the assignment to a[NO_OF_LOCATIONS], as it would have got its value from a[NO_OF_LOCATIONS+1], which is out-of-bounds and thus would always be undef. Without that change the synthesis tool would be right to assume that all elements of a[] are constant undef and would simply replace all reads on that array with constant 'bx.
This is perfectly fine code. I'm not sure why you brought up metastability but as long as the ... expressions are synchronous to clk there is no metastability in this circuit. But it does not really model a memory. Well, it does, but one with NO_OF_LOCATIONS write ports and NO_OF_LOCATIONS read ports (only counting the read ports inferred by that for-loop). Even if you had such a memory: it would be very inefficient to use it like that because the expensive thing about a memory port is its capability to address any memory location, but all the ports in this example have a constant memory address (i is constant after unrolling the for-loop). So this huge number of read and write ports will force the synthesis tool to implement that memory as a pile of individual registers. However, if your target architecture has dedicated shift register resources (such as many fpgas do), then this might be transformed to a shift register.
For large values of NO_OF_LOCATIONS you might consider implementing a fifo using cursor(s) into the memory instead of shifting the content of the entire memory from one element to the next. This would only infer one write port and no read port from inside the for-loop. For example:
reg [MSB:0] a [0:NO_OF_LOCATIONS];
parameter CURSOR_WIDTH = $clog2(NO_OF_LOCATIONS+1);
reg [CURSOR_WIDTH-1:0] cursor = 0;
always #(posedge clk)
if (...) begin
a[cursor] <= ...;
cursor <= cursor == NO_OF_LOCATIONS ? 0 : cursor+1;
end
assign a0 = a[cursor];
I am writing Verilog code using Lattice Diamond for synthesis.
I have binary data in a text file which I want to use as input for my code.
At simulation level we can use $readmemb function to do it. How is this done at synthesis level?
I want to access data present in text file as an input for FPGA.
As suggested by Mr Martin Thompson(answers below) I have written a Verilog code to read data from a file.
Verilog code is given below:-
module rom(clock,reset,o0);
input clock,reset;
output o0;
reg ROM [0:0];
reg o0;
initial
$readmemb("rom.txt",ROM);
always #(negedge clock,negedge reset )
begin
if(reset==0)
begin
o0<=0;
end
else
begin
o0<=ROM[0];
end
end
endmodule
When I am running this code on fpga I am facing the problem below:-
If text file which I want to read have only one bit which is '1' then I am able to assign input output pins to clock,reset and ROM. But if I have one bit which is '0' or more than one bits data in text file I am unable to assign input pins(i.e clock,reset) and a warning is displayed:-
WARNING: IO buffer missing for top level port clock...logic will be discarded.
WARNING: IO buffer missing for top level port reset...logic will be discarded.
I am unable to understand why I am getting this warning and how I can resolve it.
One way is to build the data into the netlist that you have synthesised. You can initialise a read-only memory (ROM) with the data using $readmemb and then access that as a normal memory from within your device.
Here's an introduction to some memory initialisation methods:
http://myfpgablog.blogspot.co.uk/2011/12/memory-initialization-methods.html
And in here:
http://rijndael.ece.vt.edu/schaum/slides/ddii/lecture16.pdf
is an example of a file-initialised RAM on the second to last slide. If you want just a ROM, leave out the if (we) part.
Think of Simulation as an environment not a level. You should just be switching the DUT (Device Under Test) from the RTL code to the synthesised netlist, other than this nothing should change in your simulation environment.
From the block of code you have given it does not look like you are separating out the test and code for the fpga. You should not be trying to synthesise your test I would recommend splitting it between at least 2 separate modules, your test instantiating the code you want to place on the fpga. Pretty sure the $fwrite is also not synthesizable.
A simple test case might look like:
module testcase
//Variables here
reg reg_to_drive_data;
thing_to_test DUT (
.input_ports ( reg_to_drive_data )
.output_ports ()
...
);
//Test
initial begin
#1ns;
reg_to_drive_data = 0;
...
end
endmodule
Via includes, incdir or file lists the code for thing_to_test (DUT) is being pulled in to the simulation, change this to point to the synthesised version.
If what you are trying to do is initialise a ROM, and hold this data in a synthesised design Martin Thompson's answer covers the correct usage of $readmemb for this.
I am getting the warning that:
One or more signals are missing in the
sensitivity list of always block.
always#(Address)begin
ReadData = instructMem[Address];
end
How do I get rid of this warning?
Verilog does not require signal names in the sensitivity list. Use the #* syntax to signify that the always block should be triggered whenever any of its input signals change:
always #* begin
ReadData = instructMem[Address];
end
Add InstructMem to the sensitivity list.
Declare ReadData as a wire instead of a reg and then replace your always block with an assign.
assign ReadData = instructMem[Address];
I am not sure what the declaration of instructMem looks like. Anyway, ReadData = instructMem[address] is going to result in a multiplexer with address being treated as selection logic and instructMem as data lines of the multiplexer using a typical synthesis tool. You would need to put in instructMem in the sensitivity list since whenever this changes so should ReadData.
I tried Icarus, and you anyway cannot do something like always #(instructMem or address) where instructMem has a declaration like reg [7:0] instructMem [255:0] --> implying memory.
Note: do not try to synthesize Verilog memories this way, typically you are supposed to instantiate memory IPs and connect to their ports. Vendors provide memory models for such purposes.