Yosys synthesizer removes blocks from case statements in verilog - verilog

I am new to the field of ASIC design. I am trying to synthesize my code but am facing a problem when synthesizing. The tools used are Openlane and technology node is GF180 nm. The issue is that when synthesizing verilog blocks such as following are not completely synthesized and only partially synthesized. e.g.
//a is a single bit value with value 0 or 1
//f is a 8 bit vector and fin is a 16 bit vector
//depending on the value of a, either the first half or the second half of the fin goes to f
case (a)
0: begin
f=fin[7:0];
end
1: begin
f=fin[15:8];
end
The problem is that after the net-list is generated only the first half of the fin is connected and the rest of fin is removed i.e. only the condition for 1st case block is synthesized rest is removed (in optimization pass I presume). I have confirmed this from the netlist as well as gds generated where the pins for fin[15:8] are unconnected.
I have tried to create illusions in the code by creating a dummy register and connecting the unused part of input fin to that register but to no avail. The net-list still does not connect the upper parts of fin to anything. The above sample code is part of a larger code block and there are more case and if statements on top of this block. I am expecting a chain of multiplexers to be used to synthesize the logic. I am hoping if anyone can tell what kind of coding style can be opted to avoid this problem? How can this logic be written so that this issue does not arise for other designs?

Related

Error "does map to unexpanded memory" in yosys verilog when using indexed part select

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.

Variable length messages in Verilog (serial CRC-32)

I'm working with a serial protocol. Messages are of variable length that is known in advance. On both transmission and reception sides, I have the message saved to a shift register that is as long as the longest possible message.
I need to calculate CRC32 of these registers, the same as for Ethernet, as fast as possible. Since messages are variable length (anything from 12 to 64 bits), I chose serial implementation that should run already in parallel with reception/transmission of the message.
I ran into a problem with organization of data before calculation. As specified here , the data needs to be bit-reversed, padded with 32 zeros and complemented before calculation.
Even if I forget the part about running in parallel with receiving or transmitting data, how can I effectively get only my relevant message from max-length register so that I can pad it before calculation? I know that ideas like
newregister[31:0] <= oldregister[X:0] // X is my variable length
don't work. It's also impossible to have the generate for loop clause that I use to bit-reverse the old vector run variable number of times. I could use a counter to serially move data to desired length, but I cannot afford to lose this much time.
Alternatively, is there an operation that would directly give me the padded and complemented result? I do not even have an idea how to start developing such an idea.
Thanks in advance for any insight.
You've misunderstood how to do a serial CRC; the Python question you quote isn't relevant. You only need a 32-bit shift register, with appropriate feedback taps. You'll get a million hits if you do a Google search for "serial crc" or "ethernet crc". There's at least one Xilinx app note that does the whole thing for you. You'll need to be careful to preload the 32-bit register with the correct value, and whether or not you invert the 32-bit data on completion.
EDIT
The first hit on 'xilinx serial crc' is xapp209, which has the basic answer in fig 1. On top of this, you need the taps, the preload value, whether or not to invert the answer, and the value to check against on reception. I'm sure they used to do all this in another app note, but I can't find it at the moment. The basic references are the Ethernet 802.3 spec (3.2.8 Frame check Sequence field, which was p27 in the original book), and the V42 spec (8.1.1.6.2 32-bit frame check sequence, page 311 in the old CCITT Blue Book). Both give the taps. V42 requires a preload to all 1's, invert of completion, and gives the test value on reception. Warren has a (new) chapter in Hacker's Delight, which shows the taps graphically; see his website.
You only need the online generators to check your solution. Be careful, though: they will generally have different preload values, and may or may not invert the result, and may or may not be bit-reversed.
Since X is a viarable, you will need to bit assignments with a for-loop. The for-loop needs to be inside an always block and the for-loop must static unroll (ie the starting index, ending index, and step value must be constants).
for(i=0; i<32; i=i+1) begin
if (i<X)
newregister[i] <= oldregister[i];
else
newregister[i] <= 1'b0; // pad zeros
end

Verilog Tri-State Issue (Xilinx Spartan 6)

Referring to my earlier question here, I've been utilizing tri-states to work with a common bus. I still appear to have some implementation issues.
The tri-states use this type of code:
assign io [width-1:0] = (re)?rd_out [width-1:0]:{width{1'bz}};
Synthesis and translation goes well. No warnings or errors I wasn't expecting (I was expecting some since this is only a trial run and most of the components don't do anything and will hence be left unconnected). But when I actually try to implement it, all busses (there are three) output a 1111111111111111, or a -1, as converted by my binary to BCD converter. I checked if it really the case by instructing the control matrix to halt if the instruction received on the bus is -1, and it did halt.
The warning I receive for the tri-state being converted to logic is:
Xst:2040 - Unit Neptune_I: 16 multi-source signals are replaced by logic (pull-up yes)
Xst:2042 - Unit alu: 16 internal tristates are replaced by logic (pull-up yes):
And so on. Neptune_I is the top module, and I believe the multi-source signals it's referring to are the busses.
I have a doubt whether the pull-up yes is the root of this problem. Is it simply pulling everything up, causing it to be -1 all the time? But this does not make sense to me, because when the tri-state is activated, the signal should be controlled by whatever entity it is supposed to be controlled by.
I would like to take the time to replace the code with logic instead of the tri-states, but I'm unsure how to proceed.
Any help would be appreciated.
Are these signals going off-chip? Or are they internal to your FPGA? If the answer is the latter, you need to change your code. Modern FPGAs (like Spartan 6) no longer support internal tri-state buffers. They only exist for off-chip signals.
You need to write all of you internal code to avoid tri-state buffers. Create dedicated paths between components, no bidirectional interfaces.

Verilog: Common bus implementation issue

I've been coding a 16-bit RISC microprocessor in Verilog, and I've hit yet another hurdle. After the code writing task was over, I tried to synthesize it. Found a couple of accidental mistakes and I fixed them. Then boom, massive error.
The design comprises of four 16-bit common buses. For some reason, I'm getting a multiple driver error for these buses from the synthesis tool.
The architecture of the computer is inspired by and is almost exactly the same as the Magic-1 by Bill Buzzbee, excluding the Page Table mechanism. Here's Bill's schematics PDF: Click Here. Scroll down to page 7 for the architecture.
The control matrix is responsible for handling when the buses and driven, and I am absolutely sure that there is only one driver for each bus at any given instance. I was wondering whether this could be the problem, since the synthesis tool probably doesn't know this.
Tri-state statements enable writing to a bus, for example:
assign io [width-1:0] = (re)?rd_out [width-1:0]:0; // Assign IO Port the value of memory at address add if re is true.
EDIT: I forgot to mention, the io port is bidirectional (inout) and is simply connected to the bus. This piece of code is from the RAM, single port. All other registers other than the RAM have separate input and output ports.
The control matrix updates a 30-bit state every negative edge, for example:
state [29:0] <= 30'b100000000010000000000000100000; // Initiate RAM Read, Read ALU, Write PC, Update Instruction Register (ins_reg).
The control matrix is rather small, since I only coded one instruction to test out the design before I spent time on coding the rest.
Unfortunately, it's illogical to copy-paste the entire code over here.
I've been pondering over this for quite a few days now, and pointing me over to the right direction would be much appreciated.
When re is low, the assign statement should be floating (driving Zs).
// enable ? driving : floating
assign io [width-1:0] = (re) ? rd_out [width-1:0] : {width{1'bz}};
If it is driving any other value then the synthesizer will treat is as a mux and not a tri-state. This is where the conflicting driver message come from.

How to access text files at synthesis level

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.

Resources