Nested IF in For Loop Verilog - verilog

I would like to know if I can put below code in a for loop so I can parameterize my code. Thank you.
always#(*) begin
if (exist_reg[0] == 'd0) begin
nth_empty_location_descending = 'd1; // specify
end
else if (exist_reg[1] =='d0) begin
nth_empty_location_descending = 'd2;
end
else if (exist_reg[2] =='d0) begin
nth_empty_location_descending = 'd4;
end
else if (exist_reg[3] =='d0) begin
nth_empty_location_descending = 'd8;
end
else if (exist_reg[4] =='d0) begin
nth_empty_location_descending = 'd16;
end
else if (exist_reg[5] =='d0) begin
nth_empty_location_descending = 'd32;
end
else if (exist_reg[6] =='d0) begin
nth_empty_location_descending = 'd64;
end
else if (exist_reg[7] =='d0) begin
nth_empty_location_descending = 'd128;
end
else if (exist_reg[8] =='d0) begin
nth_empty_location_descending = 'd256;
end
else if (exist_reg[9] =='d0) begin
nth_empty_location_descending = 'd512;
end
else begin
nth_empty_location_descending = 'd0;
end
end
It is basically checking an "exist_reg" bits, if it encounters any bit from left to right is zero then it will rise that bit in "nth_empty_location_descending" register(any better approach?). Now I want to create parameterized code for the width of the register. Currently, it is 10-bit hardcoded code.
Thank you experts.

first of all it, the best solution is probably using casez statement instead of the if/else chain:
always#(*) begin
casez (exist_reg)
10'b?????????0: nth_empty_location_descending1 = 'd1;
10'b????????01: nth_empty_location_descending1 = 'd2;
10'b???????011: nth_empty_location_descending1 = 'd4;
10'b??????0111: nth_empty_location_descending1 = 'd8;
10'b?????01111: nth_empty_location_descending1 = 'd16;
10'b????011111: nth_empty_location_descending1 = 'd32;
10'b???0111111: nth_empty_location_descending1 = 'd64;
10'b??01111111: nth_empty_location_descending1 = 'd128;
10'b?011111111: nth_empty_location_descending1 = 'd256;
10'b0111111111: nth_empty_location_descending1 = 'd512;
default : nth_empty_location_descending1 = 'd0;
endcase // casez (exist_reg)
end // always# (*)
however, if you insist, there is a loop-based solution:
always #* begin
nth_empty_location_descending2 = 'd0;
for (j = 0; j < 10; j = j + 1) begin
if (exist_reg[j] == 1'b0) begin
if (nth_empty_location_descending2 == 0)
nth_empty_location_descending2 = (10'b1 << j);
end
end
end // always # *

parameter WIDTH = 10;
reg [WIDTH-1:0] exist_reg, nth_empty_location_descending2;
integer ii;
always #* begin
nth_empty_location_descending2 = 0;
for(ii=0;ii<WIDTH;ii=ii+1)
if (exist_reg[j] == 1'b0 && nth_empty_location_descending2 == 0)
nth_empty_location_descending2[ii] = 1'b1;
end
In SystemVerilog
parameter WIDTH = 10;
logic [WIDTH-1:0] exist_reg, nth_empty_location_descending2;
always_comb begin
nth_empty_location_descending2 = 0;
for(int ii=0;ii<WIDTH;ii++)
if (exist_reg[j] == 1'b0) begin
nth_empty_location_descending2[ii] = 1'b1;
break;
end
end

Related

Sync FIFO simulation does not work as expected

I don't know what is wrong in my code. Refer to the /* status */ comment near the full and empty logic.
I have write pointer wrapping around catching up with read pointer, then wr_addr[3] == ~rd_addr[3] and wr_addr[2:0] == rd_addr[2:0], I have a full condition.
I have read pointer catching up with write pointer, then wr_addr[3:0] == rd_addr[3:0], I have empty.
Please check my code and give me some advice.
I also provide the code on edaplayground (for those of you who have an account there).
module fifo(input clk, rst,
input wr, rd,
input [3:0] din,
output logic [3:0] dout,
output fifo_full, fifo_empty
);
logic [3:0] w_ptr, r_ptr;
logic w_en, r_en;
status_pointer ptr(clk, rst, wr, rd, w_en, r_en, w_ptr, r_ptr, fifo_full, fifo_empty);
memory mem(clk, w_en, r_en, w_ptr, r_ptr, din, dout);
endmodule
module memory(input clk, we, oe,
input [3:0] w_ptr, r_ptr,
input [3:0] din,
output logic [3:0] dout
);
logic [3:0] mem [7:0];
always_ff #(posedge clk) begin
if(we & (~ oe)) begin
mem[w_ptr[2:0]] <= din;
end
else if((~ we) & oe) begin
dout <= mem[r_ptr[2:0]];
end
else if(we & oe) begin
mem[w_ptr[3:0]] <= din;
dout <= mem[r_ptr[2:0]];
end
end
endmodule
module status_pointer(input clk, rst,
input wr, rd,
output w_en, r_en,
output logic [3:0] w_ptr, r_ptr,
output logic fifo_full, fifo_empty
);
/* status */
always #(posedge clk) begin
if(rst) begin
fifo_full <= 0;
fifo_empty <= 0;
end
else begin
if(w_ptr[2:0] == r_ptr[2:0]) begin
if(w_ptr[3] == r_ptr[3])
fifo_empty <= 1;
else
fifo_full <= 1;
end
else begin
fifo_full <= fifo_full;
fifo_empty <= 0;
end
end
end
/* pointer */
assign w_en = (fifo_full == 0) & wr;
assign r_en = (fifo_empty == 0) & rd;
always_ff #(posedge clk, posedge rst) begin
if(rst) begin
w_ptr <= 4'b0;
r_ptr <= 4'b0;
end
else if(w_en & (!r_en)) begin
w_ptr <= w_ptr + 4'b001;
end
else if(r_en & (!w_en)) begin
r_ptr <= r_ptr + 4'b001;
end
else if(w_en & r_en) begin
w_ptr <= w_ptr + 4'b001;
r_ptr <= r_ptr + 4'b001;
end
else begin
w_ptr <= w_ptr;
r_ptr <= r_ptr;
end
end
endmodule
//// test bench ////
module tb_fifo();
logic clk, rst, wr, rd;
logic [3:0] din, dout;
logic fifo_full, fifo_empty;
logic [4:0] counter;
fifo dut_fifo(clk, rst, wr, rd, din, dout, fifo_full, fifo_empty);
always begin
clk = 1; #4;
clk = 0; #4;
end
initial begin
counter = 5'b00000;
rst = 0; #240; rst = 1;
end
always #(posedge clk) begin
if(~ rst) begin
counter <= counter + 5'b00001;
if(counter == 5'b00000) begin
wr = 1; rd = 0; din = counter[3:0];
end
else if(counter == 5'b00001) begin
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b00010) begin
wr = 0; rd = 1; din = counter[3:0];
end
else if(counter == 5'b00011) begin
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b00100) begin // [3]
wr = 1; rd = 0; din = counter[3:0];
end
else if(counter == 5'b00101) begin // [3]
wr = 1; rd = 0; din = counter[3:0];
end
else if(counter == 5'b00110) begin // [3]
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b00111) begin // [3]
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01000) begin // [3]
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01001) begin // [3]
wr = 0; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01010) begin // [3]
wr = 0; rd = 1; din = counter[4:1];
end
else if(counter == 5'b01011) begin // [3]
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01100) begin // [3]
wr = 1; rd = 1; din = counter[4:1];
end
else if(counter == 5'b01101) begin // [3]
wr = 0; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01110) begin // [3]
wr = 0; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01111) begin // [3]
wr = 1; rd = 0; din = counter[3:0];
end
else if(counter == 5'b11111) begin
$stop;
end
else begin
wr = 0; rd = 0;
end
end
else begin
counter <= 5'b00000;
wr = 0; rd = 0;
end
end
endmodule
There is a problem in your testbench. Your design expects an active-high reset. You need to drive rst high starting at time 0 to reset the design, then drop it low after a delay. Just invert how you drive rst. Change:
rst = 0; #240; rst = 1;
to:
rst = 1; #240; rst = 0;

Triangular signal with noise +1, -1 in Verilog

I am struggling for some time already and I can't find a simple and useful solution.
I would like to simulate triangular signal in size of 16 bits
and add a random noise to it with values 1 , 0, -1. It is important that signal with noise never differs for more than 1 from original noise and from previous value in noised signal.
For example, I would like values in that way:
ORIGINAL SIGNAL: 11111 22222 33333 44444 55555 ...
NOISED SIGNAL : 12321 12332 23434 34345 45665 ...
I simulated signal for values between 0 and 30766 because main focus now is adding noise to this original signal. This code work properly because I removed the conditions which limit the difference between values for maximum 1.
This signal is used for test bench.
reg [15:0] SIGNAL_i;
reg [15:0] SIGNAL_ii;
reg [15:0] SIGNAL_noise_i;
reg [15:0] SIGNAL_noise_reg; //za hranjenje zasumljenega signala
int RANDOM_noise_i;
int COUNT_end;
int COUNT;
initial SIGNAL_i=1;
initial COUNT_end=0;
initial COUNT=3'd4;
initial SIGNAL_ii=0;
initial SIGNAL_noise_i=1;
initial SIGNAL_noise_reg=0;
initial RANDOM_noise_i=1;
initial CLK = 1;
always #5 CLK = ~CLK;
always #10
begin
SIGNAL_noise_reg <= SIGNAL_noise_i;
RANDOM_noise_i = $signed($urandom_range(0,2))-1; //random noise generation
//upcount
if ((SIGNAL_i<16'd30766) && (SIGNAL_ii<SIGNAL_i)) //32765
begin
begin
if (COUNT_end==COUNT)
begin
assign SIGNAL_noise_i=SIGNAL_i + (RANDOM_noise_i);
SIGNAL_i=SIGNAL_i + 1;
SIGNAL_ii=SIGNAL_ii + 1;
COUNT_end=0;
COUNT_end=0;
end
else
begin
assign SIGNAL_noise_i=SIGNAL_i + (RANDOM_noise_i);
COUNT_end= COUNT_end + 1;
end
end
end
//counter on zero
else if (SIGNAL_i == 0)
begin
SIGNAL_i = 1;
SIGNAL_ii = 0;
SIGNAL_noise_i = SIGNAL_i + RANDOM_noise_i;
end
//down count
else
begin
if (COUNT_end==COUNT)
begin
assign SIGNAL_noise_i=SIGNAL_i + (RANDOM_noise_i);
SIGNAL_i=SIGNAL_i - 1;
SIGNAL_ii=SIGNAL_ii + 1;
COUNT_end=0;
COUNT_end=0;
end
else
begin
assign SIGNAL_noise_i=SIGNAL_i + (RANDOM_noise_i);
COUNT_end= COUNT_end + 1;
end
end
end
end
I would really appreciate your help!
Thank you.
I got the signal I wanted but for sure there are also beter ways to implement it. I simplified it a bit.
always #10
begin
SIGNAL_noise_reg <= SIGNAL_noise_i;
RANDOM_noise_i = $signed($urandom_range(0,2))-1;
if ((SIGNAL_i<16'd30766) && (SIGNAL_ii<SIGNAL_i)) //32765
begin
if(COUNT_end==COUNT-1)
begin
assign SIGNAL_noise_i=SIGNAL_i-1;
SIGNAL_i=SIGNAL_i + 1;
SIGNAL_ii=SIGNAL_ii + 1;
COUNT_end=0;
end
else if (COUNT_end == 0)
begin
assign SIGNAL_noise_i=SIGNAL_i -1;
COUNT_end= COUNT_end + 1;
end
else
begin
if (SIGNAL_i + RANDOM_noise_i - SIGNAL_noise_i > 1)
begin
assign SIGNAL_noise_i=SIGNAL_i;
COUNT_end= COUNT_end + 1;
end
else
begin
assign SIGNAL_noise_i=SIGNAL_i + RANDOM_noise_i;
COUNT_end= COUNT_end + 1;
end
end
end
else if (SIGNAL_i == 0)
begin
SIGNAL_i = 1;
SIGNAL_ii = 0;
SIGNAL_noise_i = SIGNAL_i + RANDOM_noise_i;
end
else
begin
if(COUNT_end==COUNT-1)
begin
assign SIGNAL_noise_i=SIGNAL_i+1;
SIGNAL_i=SIGNAL_i - 1;
SIGNAL_ii=SIGNAL_ii + 1;
COUNT_end=0;
end
else if (COUNT_end == COUNT-2)
begin
assign SIGNAL_noise_i=SIGNAL_i;
COUNT_end= COUNT_end + 1;
end
else
begin
if (SIGNAL_i + RANDOM_noise_i - SIGNAL_noise_i > 1)
begin
assign SIGNAL_noise_i=SIGNAL_i;
COUNT_end= COUNT_end + 1;
end
else
begin
assign SIGNAL_noise_i=SIGNAL_i + RANDOM_noise_i;
COUNT_end= COUNT_end + 1;
end
end
end
end

error in verilog code of object on left side should be assigned a variable

I have been trying to make an asynchronous fifo in verilog but I'm facing a problem of object "empty" and "full" on left side of assignment should have variable data type.
Top module:
module async_fifo (reset, wclock, rclock, datain, dataout, e, f);
input [15:0] datain;
output reg [15:0] dataout;
//reg [15:0] mem1, mem2, mem3, mem4, mem5, mem6, mem7, mem8;
reg [15:0] mem [7:0];
input reset, rclock, wclock;
/*reg [0:2] wptr, rptr;
initial wptr = 3'b000;
initial rptr = 3'b000;*/
integer wflag = 0, rflag = 0;
wire empty , full;
input e,f;
reg [0:2] wptr = 3'b000, rptr = 3'b000;
counter c(wclock, rclock, empty, full);
e = empty;
f = full;
always#(posedge wclock)
begin
if(f == 1'b0)
begin
e = 1'b0;
if (wptr < 3'b111)
begin
mem[wptr] = datain;
wptr = wptr + 3'b001;
end
else if(wptr == 3'b111 && wflag == 0)
wflag = 1;
else if (wflag == 1)
begin
wptr = 3'b000;
wflag = 0;
end
end
end
always#(posedge rclock)
begin
if(e == 1'b0)
begin
f = 1'b0;
if (rptr < 3'b111)
begin
dataout = mem[rptr];
rptr = rptr + 3'b001;
end
else if(rptr == 3'b111 && rflag == 0)
rflag = 1;
else if (rflag == 1)
begin
rptr = 3'b000;
rflag = 0;
end
end
end
endmodule
Counter module:
module counter(w_clock, r_clock, empty, full);
input w_clock, r_clock;
output reg empty = 0, full = 0;
integer rear = 0, front = 0;
always # (posedge w_clock)
begin
if ((front == 1 && rear == 8) || front == rear + 1)
full = 1;
else if(rear == 8)
begin
rear = 1;
empty = 0;
end
else
begin
rear = rear+1;
empty = 0;
end
end
always # (posedge r_clock)
begin
if (front == 0 && rear == 0)
empty = 1;
else if(front == 8)
begin
front = 1;
full = 0;
end
else
begin
front = front+1;
full = 0;
end
end
endmodule
You are using full and empty in left hand side of behavioral block (always). So they have to be registers.
But at the same time they are output of counter and have to be wires.
You can't use variables in that way.They can either be output of an instant and only used in right hand side of other parts of code or be regsietrs for using in left hand side of behavioral blocks that can also be input of another instant.
You better change your coding style.
Here is an examole of async FIFO:
http://www.asic-world.com/code/hdl_models/aFifo.v
And also you need to study about blocking & nonblocking assignment and race conditions. Take a look at this:
http://ee.hawaii.edu/~sasaki/EE361/Fall01/vstyle.txt

Verilog error: Range must be bounded by constant expressions

I'm new to verilog and I am doing a project for my class. So here is my code:
wire [n-1:0] subcounter_of_counter;
reg [n-1:0] mask,free;
//subcounter_of_counter: dinei ena vector apo poious subcounter apoteleitai o counter(id)
always #(*) begin //command or id or mask or free or subcounter_of_counter
if (command==increment) begin
for (int i = 0; i < n; i=i+1)begin
if (i<id) begin
subcounter_of_counter[i]=1'b0;
end else if (i==id) begin
subcounter_of_counter[i]=1'b1;
end else begin
if( (|mask[id+1:i]) || (|free[id+1:i]) ) begin
subcounter_of_counter[i]=1'b0;
end else begin
subcounter_of_counter[i]=1'b1;
end
end
end
end
end
And the error says "the range must be bounded by constant expressions."
Any ideas how else I could write it to do the same operation?
Thanks a lot
What you will need to do is create a masked and shifted version of mask and free.
reg [n-1:0] mask,free,local_mask, local_free;
always #(*) begin //command or id or mask or free or subcounter_of_counter
if (command==increment) begin
local_mask = mask & ((64'b1<<id+1)-1); // clear bits above id+1
local_free = free & ((64'b1<<id+1)-1); // clear bits above id+1
for (int i = 0; i < n; i=i+1)begin
if (i<id) begin
subcounter_of_counter[i]=1'b0;
end else if (i==id) begin
subcounter_of_counter[i]=1'b1;
end else begin
if( (|local_mask) || (|local_free) ) begin
subcounter_of_counter[i]=1'b0;
end else begin
subcounter_of_counter[i]=1'b1;
end
end
end
local_mask = local_mask >> 1; // clear bits below i
local_free = local_free >> 1;
end // for
end // always
I didn't try this code, but hopefully it points you in the right direction.

Verilog Testbench Implementation

I'm trying to implement a verilog program and the majority of the test cases are passing (1,188 out of 1440). My question however is that my expected overflow output is currently being displayed at 0 while the expected value is supposed to be 1.
Heres two examples of what's being printed to the logs with the expected value being incorrect (scroll all the way to the right):
in1=1000000000000000 in2=1000000000000000 opCode=1001 result= 0111111111111111 expectedResult= 0111111111111111 overflow=0 expectedOverflow=1 in1=-32768 in2=-32768 opCode= 9 result= 32767 expectedResult= 32767 overflow=0 expectedOverflow=1
in1=1000000000000000 in2=1000000000000001 opCode=1001 result= 0111111111111111 expectedResult= 0111111111111111 overflow=0 expectedOverflow=1 in1=-32768 in2=-32767 opCode= 9 result= 32767 expectedResult= 32767 overflow=0 expectedOverflow=1
I can't find exactly where I went wrong with my implementation. So I guess my question is, what exactly did I do wrong? Thanks!
Heres an implementation of my verilog code for reference:
module Calculator(in1,in2,opCode,result,overflow);
input signed[15:0] in1, in2;
input[3:0] opCode;
output reg signed[15:0] result;
output reg overflow;
always # (*) begin
if(opCode == 0000) begin
if(in1+in2<=32767 & in1+in2>= -32768) begin
overflow = 0;
end
else
begin
overflow = 1;
end
end
end
always # (*) begin
if(opCode == 0001) begin
if(in1-in2<=32767 & in1-in2>= -32768) begin
overflow = 0;
end
else
begin
overflow = 1;
end
end
end
always # (*) begin
if(opCode == 0010) begin
if(in1*5<=32767 & in1*5>= -32768) begin
overflow = 0;
end
else
begin
overflow = 1;
end
end
end
always # (*) begin
if(opCode == 0011) begin
if ((in1 % 10) == 0) begin
overflow = 0;
end else begin
overflow = 1;
end
end
end
always # (*) begin
if(opCode == 0100) begin
overflow = 0;
end
end
always # (*) begin
if(opCode == 0101) begin
overflow = 0;
end
end
always # (*) begin
if(opCode == 0110) begin
overflow = 0;
end
end
always # (*) begin
if(opCode == 0111) begin
overflow = 0;
end
end
always # (*) begin
if(opCode == 1000) begin
if(in1 == 32767) begin
overflow = 1;
end
else begin
overflow = 0;
end
end
end
always # (*) begin
if(opCode == 1001) begin
if(in1==-32768) begin
overflow = 1;
end
else
begin
overflow = 0;
end
end
end
always # (*) begin
case(opCode)
4'b0000: result = in1+in2; //add
4'b0001: result = in1-in2; //subtract
4'b0010: result = in1*5; //mult by 5
4'b0011: result = in1/10; //divide by 10
4'b0100: result = in1&in2; //AND
4'b0101: result = in1^in2; //XOR
4'b0110: result = in1|in2; //OR
4'b0111: result = /*((2^16)-1)-in1;*/(-(in1))-1; //complement
4'b1001: result = in1-1; //decrement
4'b1000: result = in1+1; //increment
endcase
end
endmodule
Reassigning the same variable will result in such errors. Try adding new variables/registers for your code and you can aslo remove the "always#*"(in every if case) and just use "begin . . . end" format inside a single program. Provided you "begin" initially and "end" finally it will work fine.

Resources