How to assign a dynamic range of bits - verilog

Assume I have three registers concatenated like so:
{C, A, Q}
Where C is one bit, and A and Q are, say, 8 bits.
I need to periodically perform a shift operation like so:
if (shift_regs) {C, A, Q} <= {C, A, Q} >> 1;
Another register, P, starts with a value equal to the number of bits in Q, in this case 8, and counts down by one every time a shift occurs. The whole sequence stops when P reaches 0, and the output result is 16 bits equal to {A, Q}.
However, I want perform an optimization by detecting the case where Q prematurely becomes zero before all its bits are shifted out, and assign the output result to {{8-bits_shifted_so_far{1'b0}}, A, Q[7:8-bits_shifted_so_far]} instead.
Example sequence:
C = 0, A = 8'b1101_0100, Q = 8'b0000_0011
1) after first shift, {C, A, Q} becomes {1'b0, 8'b0110_1010, 8'b0000_0001}.
2) after second shift, {C, A, Q} becomes {1'b0, 8'b0011_0101, 8'b0000_0000}.
3) Q is now zero, so assign output to {{8-bits_shifted_so_far{1'b0}}, A, Q[7:8-bits_shifted_so_far]}, i.e. {6'b00_0000, 8'b0011_0101, 2'b00}.
How can I implement this in verilog or systemverilog?

In keeping with your example, I will assume the output has a width of 16 bits.
Your problem can be simplified, since you are performing this operation at the point when Q == 8'h00, then your output does not need to contain Q[7:8-bits_shifted_so_far], it can be replaced with zeros. As Serge pointed out, dynamic ranges are not possible in verilog, but your problem has a simple solution:
//Note the blocking assignment
if(shift_regs) {C, A, Q} = {C, A, Q} >> 1;
//Set the output to A bit-shifted left by the desired amount
if(!Q) output = {8'h00, A} << (8-bits_shifted_so_far);
Essentially, all you are doing is outputting A bit shifted relative to how many shift operations have been performed.

Related

Unexpected result of Not operator in assignment

I have two 8-bit inputs A and B,
input [7:0] A,B;
and a 9-bit output F,
output reg [8:0] F;
A and B are combined and assigned to F like this:
F <= ~(A^B);
If A is equal to 8'hFF, and B is equal to 8'hF0, why does F become 9'h1F0 and not 9'h0F0?
Why is the output 9'h1F0 and not 9'h0F0?
You defined F as 9 bits wide. Thus the compiler will expand the right-hand-side arguments to 9 bits before doing any operations.
As both A and B are unsigned they become resp
A = 9'h0FF, B=9'h0F0. EXOR gives 9'h00F. Ones complement then gives 9'h1F0.
Beware that the width expansion does not happen if you put the expression between {}:
F2 = {~(A^B)};
F2 will be 9'h0F0;
Because sections 11.8.2 Steps for evaluating an expression and 11.8.3 Steps for evaluating an assignment of the IEEE 1800-2017 LRM effectively say that the operands get extended first to match the size of the result before any operation is performed.

I want to update inputs in verilog

I want to implement the following algorithm in verilog. Is there a way to update input in verilog just like c/c++(eg, a=a+i;)
a←a + b + 2 · lsw(a) · lsw(b)
d←(d ⊕ a) >>> 32
c←c + d + 2 · lsw(c) · lsw(d)
b←(b ⊕ c) >>> 24
a←a + b + 2 · lsw(a) · lsw(b)
d←(d ⊕ a) >>> 16
c←c + d + 2 · lsw(c) · lsw(d)
d←(b ⊕ c) >>> 63
here a,b,c,d are 64 bit ASCII inputs. And lsw(x) is the least significant word of 32 bit."⊕" denotes bit wise XOR and "+" denotes wordwise addition., and >>> denotes right shift operation.
I assume that you want the code to execute line by line as in C. You can use blocking statements inside an always statement for this. You will need a clock signal, because of the feedback nature of your signals.
For example,
always# (posedge clk)
begin
a = a+1;
b = b*a;
c = a+b-c;
end
The above code will execute line by line, on every positive edge of clock.
And for the operators you require,
lsw(x) - the least significant word of 32 bit can be represented by x[7:0] assuming x is defined as [31:0].
"⊕" bit wise XOR can be represented by ^ operator.
"+" and "." can be represented by | and & respectively.
right shift can be done by >> operator.

Non-integer values in verilog

Is there a way to store and compute non-integer values in verilog, (say x = 5/2 = 2.5 ).
Can I compute and store 2.5 in x defined above?
Yes, you can use real registers to store real values, i.e.:
real float; // a register to store real value
Usually it's a 64-bit wide data type that stores floating-point values. But not all Verilog operators can be used with expression involving real numbers and real registers. Concatenations, modulus operator, case equality, bit-wise operators, reduction operators shift operators, bit-selects and part-selects on real type variables are not allowed.
Simple example:
module ecample;
real r;
initial begin
r = 123456e-3;
$display("r=%f",r); // r = 123.456000
#20 r = r / 2;
$display("r=%f",r); // r = 61.728000
$finish;
end
endmodule

Simple "Assign" Function

i have just started to learn some verilog and came across a problem that would normally be solved using a for loop in other languages.
s2 s1 s0 m
0 0 0 u
0 0 1 v
0 1 0 w
0 1 1 x
1 0 0 y
1 0 1 z
This is the truth table of the problem where s2,s1,s0 are switches, (u,v,w,x,y,z) are inputs and if certain switches are set, the output(m) will be set as one of the inputs. However, this is only 1 bit wide and we can just assign each m to be one of the following inputs provided that s0,s1,s2 matches. If it were 3 bit wide input and output ex:(u0,u1,u2),(m0,m1,m2) but each of the variables still follows the same logic with one another(ex: u0,u1,u2 will all be the outputs m0,m1,m2 provided that all switches are 0) how can i shorten my code. Am i allowed to do:
assign m[3:0] = (~s0&~s1&~s2&u[3:0])
No, that is not a good solution. Verilog will extend your select signals to be the same width as m before performing the & operation, and the default behavior is to add zeros on the left to extend a signal. It might work if you declared the select signals to be signed but I think you can do better.
Furthermore, the example you provide only deals with the first row of your truth table. For the other seven combinations of s0, s1, and s2 you would be assigning all zeros to m. If you want to do this in a single combinational assignment then you would need 8 logical expressions like the one you have, all ORed together to get the final result.
A much cleaner way of doing this is with an if-then-else or case statement inside an always block.
Try a case statement:
always #* begin
case ({s2,s1,s0})
3'b000 : m = u;
3'b001 : m = v;
3'b010 : m = w;
3'b011 : m = x;
3'b100 : m = y;
3'b101 : m = z;
default: m = 0; /* <-- catch all */
endcase
end
Note: Use default if the truth table is incomplete. Otherwise a latch will be inferred.
Working example: http://www.edaplayground.com/s/6/187

Verilog reg assignment to part of another reg

I am using Verilog with modelSim and I get the following errors when I try to assign reg variables to different parts of another reg variable:
** Error: Range width must be greater than zero.
** Error: Range width must be constant expression.
here is the relevant code:
integer f; //zd, qd, R and Q are regs
always # * begin
f = 52 - zd;
R = qd[f +:0];
Q = qd[63 -:f+1];
end
I want R to include qd (from 0 to f) and Q to be (the rest) qd (from f+1 to 63). How to do it? Thanks.
What you are trying to do is not legal in verilog 2001.
As your warning says, Range width must be constant expression, i.e. you cannot have variable length part selects.
You can have fixed length part select that varies the starting point (i.e. select 8 bits starting from f), but the syntax for that is this:
vector_name[starting_bit_number +: part_select_width]
vector_name[starting_bit_number -: part_select_width]
In hardware the size of a bus must be a fixed size, you cannot change the number of wires in silicon based on the contents of a register :)

Resources