Why is XST optimizing away my registers and how do I stop it? - embedded

I have a simple verilog program that increments a 32 bit counter, converts the number to an ASCII string using $sformat and then pushes the string to the host machine 1 byte at a time using an FTDI FT245RL.
Unfortunately Xilinx XST keeps optimizing away the string register vector. I've tried mucking around with various initialization and access routines with no success. I can't seem to turn off optimization, and all of the examples I find online differ very little from my initialization routines. What am I doing wrong?
module counter(CK12, TXE_, WR, RD_, LED, USBD);
input CK12;
input TXE_;
output WR;
output RD_;
output [7:0] LED;
inout [7:0] USBD;
reg [31:0] count = 0;
reg [7:0] k;
reg wrf = 0;
reg rd = 1;
reg [7:0] lbyte = 8'b00000000;
reg td = 1;
parameter MEM_SIZE = 88;
parameter STR_SIZE = 11;
reg [MEM_SIZE - 1:0] str;
reg [7:0] strpos = 8'b00000000;
initial
begin
for (k = 0; k < MEM_SIZE; k = k + 1)
begin
str[k] = 0;
end
end
always #(posedge CK12)
begin
if (TXE_ == 0 && wrf == 1)
begin
count = count + 1;
wrf = 0;
end
else if (wrf == 0) // If we've already lowered the strobe, latch the data
begin
if(td)
begin
$sformat(str, "%0000000000d\n", count);
strpos = 0;
td = 0;
end
str = str << 8;
wrf = 1;
strpos = strpos + 1;
if(strpos == STR_SIZE)
td = 1;
end
end
assign RD_ = rd;
assign WR = wrf;
assign USBD = str[87:80];
assign LED = count[31:24];
endmodule
Loading device for application
Rf_Device from file '3s100e.nph' in
environment /opt/Xilinx/10.1/ISE.
WARNING:Xst:1293 - FF/Latch str_0
has a constant value of 0 in block
. This FF/Latch will be
trimmed during the optimization
process.
WARNING:Xst:1896 - Due to other
FF/Latch trimming, FF/Latch str_1
has a constant value of 0 in block
. This FF/Latch will be
trimmed during the optimization
process.
WARNING:Xst:1896 - Due to other
FF/Latch trimming, FF/Latch str_2
has a constant value of 0 in block
. This FF/Latch will be
trimmed during the optimization
process.

The $sformat task is unlikely to be synthesisable - consider what hardware the compiler would need to produce to implement this function! This means your 'str' register never gets updated, so the compiler thinks it can optimize it away. Consider a BCD counter, and maybe a lookup table to convert the BCD codes to ASCII codes.
AFAIK 'initial' blocks are not synthesisable. To initialize flops, use a reset signal. Memories need a 'for' loop like you have, but which triggers only after reset.

Related

Continuous assignment with 0 delay not getting the expected value after a signal positive edge

I have implemented an 8 bit serial-in parallel-out register in SystemVerilog and I'm trying to test it. I'm using Icarus Verilog as simulator.
In the test bench, I send 8 bits and wait for the rising edge of a signal, then check the obtained parallel buffer. The problem is that, after waiting for the rising edge, the parallel buffer has not the expected value. However, if I add a #0 delay to the assert it does work.
The signal on which I'm waiting the rising edge, and the buffer that should contain the expected value are assigned as:
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{rdy}} & buff;
I know buff contains the right value, then, how is that on the rising edge of rdy, rdy is effectively 1 but out_data is still 0?
Wave dump
Note: See how when rdy goes high out_data is 0xaa.
Code
Serial-in parallel-out register
module sipo_reg(
input wire in_data,
output wire [7:0] out_data,
output wire rdy,
input wire en,
input wire rst,
input wire clk
);
reg [7:0] buff;
reg [2:0] i;
reg was_enabled;
wire _clk;
always #(posedge _clk, posedge rst) begin
if (rst) begin
buff <= 0;
i <= 7;
was_enabled <= 0;
end else begin
was_enabled <= 1;
buff[i] <= in_data;
i <= i == 0 ? 7 : (i - 1);
end
end
assign _clk = en | clk; // I know this is a very bad practice, I'm on it...
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{rdy}} & buff;
endmodule
Test bench:
module utils_sipo_reg_tb;
reg clk = 1'b1;
wire _clk;
always #2 clk = ~clk;
assign _clk = clk | en;
reg in_data = 1'b0, rst = 1'b0, en = 1'b0;
wire [7:0] out_data;
wire rdy;
sipo_reg dut(in_data, out_data, rdy, en, rst, clk);
integer i = 0;
initial begin
$dumpfile(`VCD);
$dumpvars(1, utils_sipo_reg_tb);
en = 1;
#4 rst = 1;
#4 rst = 0;
assert(out_data === 8'b0);
assert(rdy === 1'b0);
//
// read 8 bits works
//
#4 en = 0;
for (i = 0; i < 8; i = i + 1) begin
#(negedge _clk) in_data = ~in_data;
end
en = 1;
#(posedge rdy);
assert(rdy === 1'b1);
assert(out_data === 8'haa); // <-- This fails, but works if I add a '#0' delay.
#20;
$finish;
end
endmodule
I have tried to replace these lines
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{rdy}} & buff;
by these
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{((i == 7) & was_enabled)}} & buff;
because I suspected the simulator was 'calculating' out_data after rdy because the former depends on the latter. However, they are still continuous assignments with 0 delay, I would expect them to get their value at the exact same time (unless a delay is added).
Would it be a good design practice to add a few picoseconds of delay after each #(posedge signal) to make sure everything is settled by the simulator?
You have a race condition in your testbench because you are trying to sample a signal at a time where it is changing. All digital systems have inherent race conditions, and the way to deal with them is to only sample your signals when you know they are stable.
In your case, you could use a small numeric delay as you have suggested. However, since you have a clock signal, if you know that changes to signals only occur on the posedge of the clock, you could sample signals at the negedge:
#(posedge rdy);
#(negedge clk);
assert(rdy === 1'b1);
assert(out_data === 8'haa);
This is a more robust approach than using a numeric delay since it scales better (no need to worry about picking the best numeric delay value).
This is a synchronous design and your assertion should synchronous as well. That means only using one edge, the (positive) clock edge. Once you start using other signal edges, you run into race conditions between statements waiting for the signal to change, which includes both the #(posedge rdy) procedural delay and the assign out_data = {8{rdy}} & buff; continuous assignment.
There are two approaches to fixing this in your testbench:
Do not use #(posedge rdy) in your prodedural code. Use
#(posedge clk iff (rdy === 1'b1));
assert(out_data === 8'haa);
Since i and was_enabled are both updated with nonblocking assignments, rdy gets sampled with its old value, as well as out_data in the assertion that follows.
Another option is using a concurrent assertion which is outside of any procedural code
assert property (#(posedge clk) $rose(rdy) |-> out_data === 8'haa);
This reads "When rdy has risen, this implies on the same cycle that out_data must be 8'haa"

Icarus Verilog crash while compiling dynamic memory module

This is my first post on StackOverflow.
I'm a Verilog newbie, though I have significant experience with Python, C, and C++. I am using Icarus Verilog version 10.1.1 on Windows 10, and am trying to write a dynamic memory allocator. For some reason, when this command is run:
iverilog dynmem.v dynmem_test.v -o dynmem_test.out
the following is outputted:
Assertion failed!
Program: c:\iverilog\lib\ivl\ivl.exe
File: ../verilog-10.1.1/pform.cc, Line 333
Expression: lexical_scope
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
What is the problem with my code, and should I submit a bug report for this?
dynmem.v:
`define WORD_SIZE 32
`ifndef DYNMEM_SIZE // size of dynamic memory in words
`define DYNMEM_SIZE 16384*8/WORD_SIZE // 16 KB
`endif
`define __DYNMEM_BIT_SIZE WORD_SIZE*DYNMEM_SIZE-1 // size of dynamic memory in bits
reg [__DYNMEM_BIT_SIZE:0] dynmem; // dynamic memory
reg [DYNMEM_SIZE:0] allocated; // bitvector telling which words are allocated
reg mutex = 0;
module dynreg(address,
ioreg,
read_en,
write_en,
realloc_en);
output reg [WORD_SIZE-1:0] address;
output reg [WORD_SIZE-1:0] ioreg;
output reg read_en; // rising edge: put word stored at location address into ioreg
output reg write_en; // rising edge: put word stored in ioreg into location address
output reg realloc_en; // rising edge: if ioreg=0, free memory, otherwise reallocate memory into buffer of size ioreg.
task malloc; // allocate dynamic memory
output reg [WORD_SIZE-1:0] size;
output reg [WORD_SIZE-1:0] start;
unsigned integer size_int = size; // convert size to integer
reg flag1 = 1;
while (mutex) begin end // wait on mutex
mutex = 1; // acquire mutex
// loop through possible starting locations
for (index=size_int-1; (index < DYNMEM_SIZE) && flag1; index=index+1) begin
// check if unallocated
reg flag2 = 1;
for (offset=0; (offset < size_int) && flag2; offset=offset+1)
if (allocated[index-offset])
flag2 = 0;
if (flag2) begin // if memory block is free
start = index;
flag1 = 0; // exit loop
end
end
// mark as allocated
for (i=0; i<size; i=i+1)
allocated[start-offset] = 1;
mutex = 0; // release mutex
endtask
task freealloc;
output reg [WORD_SIZE-1:0] size;
output reg [WORD_SIZE-1:0] start;
while (mutex) begin end // wait on mutex
mutex = 1; // acquire mutex
// deallocate locations
for (index=start; index > 0; index=index-1)
allocated[index] = 0;
mutex = 0; // release mutex
endtask
// internal registers
unsigned integer start; // start address
unsigned integer size; // block size
unsigned integer address_int; // address register converted to int
initial begin
// allocate memory
size = ioreg;
malloc(size, start);
end
always #(posedge(read_en)) begin
// read memory into ioreg
address_int = address;
ioreg[WORD_SIZE-1:0] = dynmem[8*(start+address_int)-1 -:WORD_SIZE-1];
end
always #(posedge(write_en)) begin
// write memory from ioreg
address_int = address;
dynmem[8*(start+address_int)-1 -:WORD_SIZE-1] = ioreg[WORD_SIZE-1:0];
end
always #(posedge(realloc_en)) begin
unsigned integer ioreg_int = ioreg; // convert ioreg to integer
reg [WORD_SIZE-1:0] new_start; // new start address
if (ioreg_int != 0) begin // if memory is to be reallocated, not freed
malloc(ioreg, new_start); // allocated new memory
// copy memory
for (i=0; i<size; i=i+1)
dynmem[8*(new_start+i)-1 -:WORD_SIZE-1] = dynmem[8*(start+i)-1 -:WORD_SIZE-1];
end
freealloc(size, start); // free previous memory
// update registers
size = ioreg_int;
start = new_start;
end
endmodule
dynmem_test.v:
module testmodule();
$monitor ("%g ioreg1=%b ioreg2=%b",
$time, ioreg1, ioreg2);
reg [WORD_SIZE-1:0] address1, address2;
reg [WORD_SIZE-1:0] ioreg1=5, ioreg2=10;
reg read_en1, read_en2;
reg write_en1, write_en2;
reg realloc_en1, realloc_en2;
#1 dynreg dr1(address1, ioreg1, read_en1, write_en1, realloc_en1);
#1 dynreg dr2(address2, ioreg2, read_en2, write_en2, realloc_en2);
address1 = 0;
ioreg1 = 23;
#1 write_en1 = 1;
write_en1 = 0;
address1 = 2;
ioreg1 = 53;
#1 write_en1 = 1;
write_en1 = 0;
address1 = 0;
#1 read_en1 = 1;
read_en1 = 0;
address1 = 2;
#1 read_en1 = 1;
read_en1 = 0;
#1 $finish;
endmodule
UPDATE: C:\iverilog\lib\verilog-10.1.1 doesn't exist, and, in fact, I searched in C:\iverilog for pform.cc and found no results. Strange.
#1 dynreg dr1(address1, ioreg1, read_en1, write_en1, realloc_en1);
Using a delay (#1) on an instance declaration is probably confusing Icarus as much as it's confusing me. (What exactly is supposed to get delayed? Does the instance not exist for one simulation step?)
Remove those delays, and put all of the code in your testbench following those two instance declarations into an initial block.
For what it's worth, dynreg is probably not synthesizable as written. It has no clock input, and it contains several loops which cannot be unrolled in hardware.
UPDATE: C:\iverilog\lib\verilog-10.1.1 doesn't exist, and, in fact, I searched in C:\iverilog for pform.cc and found no results. Strange.
This path is probably referring to the location of the code on the developer's computer where your copy of Icarus was compiled. Unless you plan on trying to fix the bug that caused this crash yourself, you can safely ignore this.

Conditional code in Verilog in a generate loop

I am trying to encode conditional behavior for Verilog statements in a generate loop. For example, the code below returns an error.
module <something> (out);
parameter [4:0] someParam = 0;
output [5:0] out;
genvar l, m;
for(l=0; l<5; l=l+1) begin:STAGE_1
m = 0;
if(someParam[l] < 2)
m = l+2;
else begin
m = l-2;
end
if (m>16) assign out[l] = 1'b0;
else assign out[l] = 1'b1;
end
endmodule
The problem is that the variable m is not a constant and the code errors out. Is there any way I can use compile time variable inside a generate statement which would allow some functionality like the variable m above?
Thanks.
I didnt understand what you intended to calculate due to some errors in your code.
In general, for you to use a parameter in a statement you can use an always block with a if statement as following:
module <something> (out);
parameter [4:0] someParam = 0;
output out; // in this case out is only one bit. it can be more of course.
integer l,m; // no need for genver when not using generate
always (*) begin
m = 0;
for (l=0; l<5; l=l+1) begin:STAGE_1
if (someParam[l] == 1'b1) // nothing good comes for checking if a bit is less then 2
m = m+1; // just counting bits in someParam. doing +-2 does not make sense.
end
if (m >= 3)
out = 1'b1;
else
out = 1'b0;
end
The above is a majority function.
Good luck

Strange delay of one cycle in modules in verilog

i'm beginner in verilog and digital circuits, and i have one doubt in the code below. In this code i made a state machine that saves values in a "reg" into another module in verilog. I made this code just to explain my doubt:
//STATE MACHINE
module RegTest(clk,enable,reset, readData1_out);
parameter State1 = 0;
parameter State2 = 1;
parameter State3 = 2;
parameter State4 = 3;
parameter State5 = 4;
parameter State6 = 5;
parameter State7 = 6;
parameter State8 = 7;
parameter State9 = 8;
parameter State10 = 9;
parameter Beg = 10;
input clk, enable, reset;
output readData1_out;
wire clk,enable, reset;
reg[5:0] State;
reg writeEn ;
reg [15:0] writeData;
wire [15:0] readData1;
wire writeEn_out = writeEn;
RegFile registrador_component (
.dataIn(writeData),
.dataOut(readData1),
.clock(clk),
.writeEnable(writeEn)
);
defparam
registrador_component.WIDTH = 16;
always #(posedge clk or posedge reset) begin
if (reset)
begin
State = Beg;
end else begin
case (State)
Beg:
begin
State = State1;
end
State1:
begin
writeEn = 1 ;
writeData = 10;
State = State2;
end
State2:
begin
writeEn = 0 ;
State = State3;
end
State3:
begin
writeEn = 1;
writeData = readData1 + 10;
State = State4;
end
State4:
begin
writeEn = 0 ;
State = State5;
end
State5:
begin
writeEn = 1 ;
writeData = readData1 + 10;
State = State6;
end
State6:
begin
writeEn = 0 ;
State = State7;
end
State7:
begin
writeEn = 1 ;
writeData = readData1 + 10;
State = State8;
end
State8:
begin
writeEn = 0 ;
State = State9;
end
endcase
end
end
endmodule
//Example of a register file
module RegFile(clock, writeEnable, dataIn, dataOut);
parameter WIDTH = 16;
input clock, writeEnable;
input [WIDTH-1 : 0] dataIn;
output [WIDTH-1 : 0] dataOut;
wire [WIDTH-1 : 0] dataOut;
reg [WIDTH-1 : 0] wha;
assign dataOut = wha;
always#( posedge clock)
begin
if (writeEnable)
wha = dataIn;
end
endmodule
My doubt is, why do I need to wait 1 cycle to get the value that is stored in RegFile?
Why can't I skip the State2 for example?
You do in fact have 2 clock cycles of delay in the code you wrote above. It would help if you simulated this so you can see it for yourself, but I'll describe it.
On the first cycle, WriteEnable goes high. It takes 1 full clock cycle to be valid to other parts of the logic. So after the first clock cycle is done, WriteEnable will be available for use elsewhere.
On the second cycle, your regFile module can "see" the fact that WriteEnable went high previously. It then will put dataIn into wha signal, which gets passed to dataOut. So after the second clock cycle is done, dataOut will be available for use elsewhere. (It gets used on the third clock cycle in State 3).
This is why you need to go to state 2. State 2 allows for the 1 extra clock cycle needed for RegFile to register the output data.
Clock cycle delay is an extremely important concept to understand, so it's good that you're putting in the time when you are still new to fully grasp it.
For more information see this tutorial here, it explains registers and clock cycle delay and will be useful for you.
Clock Cycle Delays and Registered Logic

Verilog I/O reading a character

I seem to have some issues anytime I try anything with I/O for verilog. Modelsim either throws function not supported for certain functions or does nothing at all. I simply need to read a file character by character and send each bit through the port. Can anyone assist
module readFile(clk,reset,dEnable,dataOut,done);
parameter size = 4;
//to Comply with S-block rules which is a 4x4 array will multiply by
// size so row is the number of size bits wide
parameter bits = 8*size;
input clk,reset,dEnable;
output dataOut,done;
wire [1:0] dEnable;
reg dataOut,done;
reg [7:0] addr;
integer file;
reg [31:0] c;
reg eof;
always#(posedge clk)
begin
if(file == 0 && dEnable == 2'b10)begin
file = $fopen("test.kyle");
end
end
always#(posedge clk) begin
if(addr>=32 || done==1'b1)begin
c <= $fgetc(file);
// c <= $getc();
eof <= $feof(file);
addr <= 0;
end
end
always#(posedge clk)
begin
if(dEnable == 2'b10)begin
if($feof(file))
done <= 1'b1;
else
addr <= addr+1;
end
end
//done this way because blocking statements should not really be used
always#(addr)
begin:Access_Data
if(reset == 1'b0) begin
dataOut <= 1'bx;
file <= 0;
end
else if(addr<32)
dataOut <= c[31-addr];
end
endmodule
I would suggest reading the entire file at one time into an array, and then iterate over the array to output the values.
Here is a snippet of how to read bytes from a file into a SystemVerilog queue. If you need to stick to plain old Verilog you can do the same thing with a regular array.
reg [8:0] c;
byte q[$];
int i;
// Read file a char at a time
file = $fopen("filename", "r");
c = $fgetc(file);
while (c != 'h1ff) begin
q.push_back(c);
$display("Got char [%0d] 0x%0h", i++, c);
c = $fgetc(file);
end
Note that c is defined as a 9-bit reg. The reason for is that $fgetc will return -1 when it reaches the end of the file. In order to differentiate between EOF and a valid 0xFF you need this extra bit.
I'm not familiar with $feof and don't see it in the Verilog 2001 spec, so that may be something specific to Modelsim. Or it could be the source of the "function not supported."