How to dynamically change value assigned to a vector register - verilog

I am a newbie to verilog coding. In my problem statement, I will get number of entries in a sorted table from another module and based on number of entries I need to decide where should I start my binary search
(e.g. Let num_entries be 15, then start index should be 8). Code snippet is given below:
srch_addr <= {{(TBL_AW-msb_loc(num_entries)-1){1'b0}},2'b10, {(msb_loc(num_entries)-1){1'b0}}};
//function to find out MSB 1
integer LOC;
function [3:0] msb_loc;
input [TBL_AW:0] num_entries;
reg found;
//input start;
begin
//if(start = 1)
//begin
found = 1'b0;
msb_loc = 3'b000;
for (LOC=TBL_AW; LOC> 0; LOC=LOC-1)
begin
if((num_entries[LOC] == 1) && !found)
begin
msb_loc = LOC;
found = 1'b1; //TO exit the loop
end
end
//end
end
endfunction
Compiler gives me this error "Illegal operand for constant expression". What can be done to resolve this error?

The replicator 'count' value must be a non-zero, non-X and non-Z constant expression.
{(TBL_AW-msb_loc(num_entries)-1){1'b0}}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This is not a constant.
To get the 'halfway' address you can just the standard mathematical way: divided and round upwards. In this case add one and divide by two:
srch_addr <= (msb_loc(num_entries)+1)>>1;
Coming back to your formula. This part just makes zeros: {(TBL_AW-msb_loc(num_entries)-1){1'b0}} You don't need that.
This part 2'b10, {(msb_loc(num_entries)-1){1'b0}} actually shifts 2'b10 left by "(msb_loc(num_entries)-1)" positions.
This does the same but then without syntax errors:
srch_addr <= 1'b1 << msb_loc(num_entries);
What I can see it does NOT give you the half-way address.
Further:
Your integer LOC; should be inside your function as a local variable.

Related

How the for loop works in this case?

As title. I'm quite unsure how the for loop would help to count the number of 1's in the input.
always #(*)
begin
for ( int i= 0 ;i< 255 ;i++ )
out = out + in[i];
end
If my input is 1001, out = out + in[1001]. So how can it count the number of 1's in this case?
Thank you
Assuming your input in is defined something like input [254:0] in then you would never have in[1001] as in is indexed on i that goes from 0 to 254.
As long as out is at least 8 bits, this should calculate the number of 1s in the input though not very efficiently for hardware as it's describing a long chain of 1-bit adders starting from in[0] + out to in[254] + out where the output of the previous adder is fed into the next. There is also an error as you need to initialize out to 0 or your loop will run forever as the always block depends on both in and out in its current implementation.
The main problem with your code is it doesn't initialize out. Without resetting out to zero, any change to in will only increment out; potentially overflow and keep adding.
The question is tagged as Verilog, but it is using SystemVerilog syntax. There proper Verilog way of writing this code would be:
integer i; // 'int' is a SystemVerilog keyword
always #(*)
begin
out = 0; // <-- initialize to zero
for ( i = 0 ; i < 255 ; i=i+1 ) // Verilog doesn't allow decelerating 'i' here or '++'
out = out + in[i];
end
With SystemVerilog, it can be written as bellow. Modern Verilog simulations are SystemVerilog simulations. The preferred way to enable the feature is changing the file extension from .v to .sv
always_comb
begin
out = '0; // <-- fill with zeros
for ( int i = 0 ; i < 255 ; i++ ) // or: foreach(in[i])
out += in[i];
end

Bits Not Shifting

I want to be able to create a shift from right to left everytime I press a button, but my simulation says my bits is not shifting.
this is the code I wrote:
module Sipo(KEY0, qIN, qOUT, LEDsipo);
input KEY0;
output reg [5:0] qIN;
output reg [5:0] qOUT;
output [6:0] LEDsipo;
assign LEDsipo[0] = qIN[0];
assign LEDsipo[1] = qIN[1];
assign LEDsipo[2] = qIN[2];
assign LEDsipo[3] = qIN[3];
assign LEDsipo[4] = qIN[4];
assign LEDsipo[5] = qIN[5];
assign LEDsipo[6] = KEY0;
always #(KEY0) begin
if (KEY0 == 1)
qIN = 6'b000000;
qOUT[0] <= KEY0;
qOUT[1] <= qOUT[0];
qOUT[2] <= qOUT[1];
qOUT[3] <= qOUT[2];
qOUT[4] <= qOUT[3];
qOUT[5] <= qOUT[4];
if (qOUT == 7'b111111)
qOUT[0] = 0;
qOUT[1] = 0;
qOUT[2] = 0;
qOUT[3] = 0;
qOUT[4] = 0;
qOUT[5] = 0;
qIN = qOUT;
end
endmodule
The result I got in the simulation is that LEDsipo[0] was responding to KEY0, but the rest of the LEDsipo was not. I don't see why my bits are not shifting.
It is dificult to test your code without a testbench, which you have not provided, but I thik that you rissue is an extra exposure to python.
Verilog does not understand indentation as scope indicators and requires begin/end to indicats scopes. So, my guess is that you have at least several issues:
missing begin/end: if (KEY0 == 1) begin...end
incorrect mix of non-blocing/non-blocking assignments mix
Incorrect coding of your latch
bad use of veriog syntax
so, though it is corret, you can avoid using separate bits:
assign LEDsipo[6:0] = {KEY0, qIN[5:0]};
do not use sensititivity lists in the latch, it will not synthesize correctly in your case. Use always #* instead. Well, and begin/end.
I do not know why you need qIn, but it makes no sense to initialize it to 0 in the first place. Also, it is not a part of the latch and should be moved out of the always block.
always #* begin
if (KEY0 == 1) begin // need begin/end for multiple statements
// qIN <= 6'b000000; -- why do you need it?
qOut[5:0] <= {qOut[4:0], KEY0};
if (qOUT == 7'b111111) // can omit begin/end for a single statement
qOut <= 6'b0;
end
end
assign qIn = qOut;
Since you have not provide any testbench, I did not test the code.

Verilog Register to output

I am working with an Altera DE2 development board and I want to read an input in on the switches. This is stored in registers. Based on a counter these registers are incremented. The registers are then supposed to be output to the Seven Segment Displays thought a B2D converter. But I can not pass a register to a function.
wire [26:0] Q,Q2,Q3,Q4;
wire [3:0] one,two,three,four;
reg SecInc,MinInc,HrInc;
reg [3:0] M1,M2,H1,H2;
assign one = SW[3:0];
assign two = SW[7:4];
assign three = SW[11:8];
assign four = SW[15:12];
always begin
M1 = SW[3:0];
M2 = SW[7:4];
H1 = SW[11:8];
H2 = SW[15:12];
end
This is how I get and store the inputs. They come from the switches which we use as a binary representation on Hours and Minutes.
Based on a counter we increment a minute or an hour register.
//increment seconds from 0 to 60
counter seconds (SecInc,KEY[0],Q2);
defparam seconds.n = 8;
defparam seconds.mod = 60;
always # (negedge CLOCK_50) begin
if (Q2 >= 60) begin
MinInc = 1;
M1 <= M1 + 1'b1;
if(M1 >= 9) begin
M1 <= 0;
M2 <= M2 + 1'b1;
end
end else begin
MinInc = 0;
end
end
We want to display the result on the SSD's.
hex(M1,HEX4);
hex(M2,HEX5);
hex(H1,HEX6);
hex(H2,HEX7);
Here in lies the problem. This is not allowed in verilog. I need a way to send my registers to a function which displays numbers from 0 to 9 using some B2D conversion.
I will say I have never had a formal intro to verilog before and I have tried all I can think to do. I even tried to make a new module in which I would pass one,two,three,four and have the module increment them, like it does with Q2 for the counter I have shown. Any suggestions or help is greatly appreciated!
As requested here is the hex module:
module hex(BIN, SSD);
input [15:0] BIN;
output reg [0:6] SSD;
always begin
case(BIN)
0:SSD=7'b0000001;
1:SSD=7'b1001111;
2:SSD=7'b0010010;
3:SSD=7'b0000110;
4:SSD=7'b1001100;
5:SSD=7'b0100100;
6:SSD=7'b0100000;
7:SSD=7'b0001111;
8:SSD=7'b0000000;
9:SSD=7'b0001100;
endcase
end
endmodule
Thank you in advance!
Your hex module is not a function, it is a module and therefore must be instantiated with an instance name like this:
hex digit0(.BIN(M1), .SSD(HEX4));
hex digit1(.BIN(M2), .SSD(HEX5));
hex digit2(.BIN(H1), .SSD(HEX6));
hex digit3(.BIN(H2), .SSD(HEX7));
In addition to nguthrie being correct, that you need to instantiate your hex converter as a module, you drive M1 from a race condition in your always block. Non-blocking assignments will evaluate simultaneously within a block (or essentially simultaneously). This is not a program, where things happen in order. What might work better is:
always # (negedge CLOCK_50) begin
if (Q2 >= 60) begin
MinInc = 1;
if (M1 < 9) begin
M1 <= M1 + 1'b1;
end else begin
M1 <= 0;
M2 <= M2 + 1'b1;
end
end else begin
MinInc = 0;
end
end
You will also potentially get unexpected results from your blocking assignments to MinInc, but since I don't see where this is read it's hard to know what will happen.
Read up on blocking (=) vs non-blocking (<=) assignments in Verilog. It's one of the trickiest concepts of the language, and misuse of the two operations is the cause of 90% of the most dastardly bugs I've ever seen.
EDIT: In re-reading your question, it seems that you're trying to drive M1-4 from at least three places. You really can't have a continuous always begin block and a clocked (always # (negedge clock) begin) driving the same register. This will send your compiler into a tantrum.

"<signal> is not a constant" error in if-statement

I am trying to write a simple module to output a 14-bit number based on the value of four input signals. My attempt is shown below.
module select_size(
input a,
input b,
input c,
input d,
output [13:0] size
);
if (a) begin
assign size = 14'h2222;
end
else begin
if (b) begin
assign size = 14'h1111;
end
else begin
if (c) begin
assign size = 14'h0777;
end
else begin
assign size = 14'h0333;
end
end
end
endmodule
Upon compilation, I receive the following error:
ERROR:HDLCompiler:44 - Line 67: c is not a constant
I don't understand why that particular if-statement isn't working if the other two preceding it are. I have tried changing the condition to
if (c == 1) begin
but to no avail.
Does anybody know how to solve this error? Thank you!
Two problems:
1) You need to put if statements inside an always block.
If you use verilog-2001, you can use
always #*
if ....
end
end
Otherwise specify all the inputs in the sensitivity list:
always #(a or b or c or d)
if ....
end
end
2) Constant assignments are not allowed inside if statements.
Remove the assign keyword from any statements inside the if block:
if (a) begin
size = 14'h2222;
end
You will also have to declare size as a reg type.
However my preference would be to rewrite the entire module with conditional operator, I find it much preferrable to read. This following module achieves the same result:
module select_size(
input a,
input b,
input c,
input d,
output [13:0] size
);
assign size = a ? 14'h2222 :
b ? 14'h1111 :
c ? 14'h0777 :
14'h0333 ;
endmodule
As #Tim has already answered, using reg types inside always blocks or wire with assign.
#Tim has also described the nested ternary assignments, while in the example are written very well, they are generally seen as bad practice. They imply a very long combinatorial path and can be hard to maintain. The combinatorial path may be optimised by synthesis which should imply a mux with optimised selection logic.
Easier to maintain code will have a lower cost of ownership, and as long as it does not lead to a larger synthesised design it is normally preferred.
My implementation would be to use a casez, (? are don't cares). I find the precedence of each value easier to see/debug.
module select_size(
input a,
input b,
input c,
input d,
output logic [13:0] size //logic (SystemVerilog) or reg type
);
always #* begin
casez ({a,b,c})
3'b1?? : size = 14'h2222 ;
3'b01? : size = 14'h1111 ;
3'b001 : size = 14'h0777 ;
3'b000 : size = 14'h0333 ;
default: size = 'bx ;
endcase
end
endmodule

Trouble using 'generate' in verilog always block

I am try to generate some conditions in a case statement in Verilog.
I have a parameter known as MANT_WIDTH and the number of conditions in the case statement depends on the value of MANT_WIDTH
for example I have
always #(*) begin
case (myvariable)
{MANT_WIDTH{1'b1}}:
begin new_variable = {1'b0, {MANT_WIDTH{1'b1}}}; end
genvar n;
generate
for (n = 2; n <= MANT_WIDTH-1; n = n+1) begin: NORMALIZE
{(MANT_WIDTH-n){1'b0}},{n{1'b1}}}:
begin new_variable = {{n{1'b1}},1'b0;
end
endgenerate
default:
begin new_variable = {(MANT_WIDTH+1){1'b0}}; end
endmodule
end
there might be some conditions in this code that don't make sense (incorrect bit widths, etc.) but the gist of what I am trying to do is here.
The problem I am having is that I am getting the following errors when I try to simulate this code using ncverilog:
for (n = 2; n <= MANT_WIDTH-1; n = n+1) begin: NORMALIZE
|
ncvlog: *E, ILLPRI (fpmodule.v,278|6): illegal expression primary [4.2(IEEE)]
also I get illegal lvalue syntax [9.2[IEEE)]
I need to count leading zeros. I didn't actually paste my real code, I just need some way to count leading zeros, but I have a few special cases that will have to put outside of a for loop.
THANK YOU SO MUCH!
It is not legal to use a generate in an always block. They are only valid in the module declaration scope.
module;
//Valid here
endmodule
I have a parameter known as MANT_WIDTH and the number of conditions in
the case statement depends on the value of MANT_WIDTH
There is no way to directly control the number of case statements using a parameter.
I can't tell what you're trying to calculate(new_variable = {myvariable,1'b0}?) but rarely do you need generate loops to achieve a shift of some sort nor does it look like you need leading zeros here.
I resorted to using the following compiler directives:
`ifdef
`else
`endif
So therefore I could define a block a code as such:
`define MYMACRO 1;
`ifdef MYMACRO
// some code
`else
`ifdef ANOTHERMACRO
// different code
`endif
`endif

Resources