Minimum in array - verilog

I am trying to build a module for practice which gets as input:
clk, rst.
an array of 3 numbers each one is 4 bits.
The final purpose is to return in the output the minimum value in the array but I can't get it really working and I don't understand why.
module minVal(
input logic rstN, clk,
input logic unsigned [2:0][3:0] resArray,
output logic [3:0] minVal
);
logic unsigned [3:0] currRes;
always_ff #(posedge clk, posedge rstN) begin
if(rstN == 1'b1) begin
currRes <= 4'b1111;
end
else begin
for(int i = 0; i < 3; i++) begin
if( resArray[i] < currRes) begin
currRes <= resArray[i];
minVal <= resArray[i];
end
end
end
end
endmodule
I wrote the following test bench:
module minVal_tb();
logic rstN, clk;
logic unsigned [2:0][3:0] resArray;
logic [3:0] minVal;
minVal thisInst(.rstN(rstN), .clk(clk), .resArray(resArray), .minVal(minVal));
always begin
#20 clk = ~clk;
end
initial begin
clk = 1'b0;
rstN = 1'b1;
resArray[0] = 5;
resArray[1] = 1;
resArray[2] = 3;
#5 rstN = 1'b0;
end
endmodule
I expect the output to be 1 right after the first clock cycle, but I get it only after 2 clock cycles. Why?

When you unroll the for loop, this is what it would look like:
always_ff #(posedge clk, posedge rstN) begin
if(rstN == 1'b1) begin
currRes <= 4'b1111;
end
else begin
if( resArray[0] < currRes) begin
currRes <= resArray[0];
minVal <= resArray[0];
end
if( resArray[1] < currRes) begin
currRes <= resArray[1];
minVal <= resArray[1];
end
if( resArray[2] < currRes) begin
currRes <= resArray[2];
minVal <= resArray[2];
end
end
end
You end up with multiple nonblocking assignments to the same register (currRes).
On the 1st posedge of the clock after reset, all 3 if clauses are true, and the last assignment wins:
currRes <= resArray[2];
So, currRes is assigned the value 3, not 1.
The same is true of minVal.
You need to sort the 3 input values, then compare the minimum of those values to the current minimum.

Related

How to get outputs/pulses when counter reaches two particular values?

I have created a counter that counts up to 30. I have an output signal out. At two particular counts, i.e., when counter reaches 10 (first) and when counter reaches 15 (second), I want the output to become low. Somehow I'm missing a basic logic here as only at one particular count (either at 10 or 15) I'm able to make the output zero.
Here is the code
module user_def_pulse(
output integer counter,
output reg out,
input clk, reset
);
parameter no_of_counts = 30;
parameter first = 10;
parameter second = 15;
initial
begin
counter = 0;
out = 1'b0;
end
always #(posedge clk)
begin
if (reset)
begin
counter <= 1'b0;
end
else if (counter == no_of_counts)
begin
counter <= 1'b0;
out <= 1'b0;
end
else
begin
if ((counter == first) || (counter == second))
out <= 1'b0;
else
begin
counter <= counter + 1;
out <= 1'b1;
$display($time," The value of counter is %d", counter);
end
end
end
endmodule
Here is the test bench
module user_def_pulse_tb(
);
parameter time_period = 10;
wire [31:0] COUNTER;
wire OUT;
reg CLK, RESET;
user_def_pulse udp1 (.counter(COUNTER), .out(OUT), .clk(CLK), .reset(RESET));
initial
begin
CLK = 1'b0;
RESET = 1'b1;
#20 RESET = 1'b0;
end
always
#time_period CLK = ~CLK;
endmodule
Here is the output waveform.
The problem with your code is that is stops incrementing the counter as soon as it hits the first value. You need to keep incrementing the counter. I moved the increment outside of the if ((counter == first) || ... clause.
always #(posedge clk) begin
if (reset) begin
counter <= 1'b0;
end else if (counter == no_of_counts) begin
counter <= 1'b0;
out <= 1'b0;
end else begin
counter <= counter + 1;
$display($time," The value of counter is %d", counter);
if ((counter == first) || (counter == second)) begin
out <= 1'b0;
end else begin
out <= 1'b1;
end
end
end

Can't resolve multiple constant drivers for net Quartus error

this is a very basic question but if somebody can help me with these errors, I'd really appreciate it. I am an EE undergrad, new to Verilog, and I'd appreciate any help/explanation.
The errors I received were:
10028 Can't resolve multiple constant drivers for "led" at compare_block.sv (66)
10029 Constant driver at compare_block.sv(61)
What are the multiple constant drivers here? Originally, I had the led assignment (led <= led_val) within the second always block, and I thought moving it up to the first always block would change the errors, but it did not.
module compare_block (clk, reset_n, result, led);
parameter data_width = 8; /
parameter size = 1000;
input clk, reset_n;
input [data_width:0] result;
logic [(data_width):0] data_from_rom;
logic [9:0] addr_to_rom;
output reg led;
reg [(data_width):0] comp_sig [size-1:0];
reg [data_width:0] comp_sig_temp;
reg [(data_width):0] filt_sig [size-1:0];
reg [(data_width):0] ans_sig [size-1:0];
integer i, iii;
reg [9:0] ii ;
integer sum_array;
wire [(data_width+3):0] array_avg;
reg [data_width:0] summed_arr [size-2 : 0];//container for all summation steps
wire total_sum;
reg ans_sig_done;
reg [data_width : 0] summed_ans;
reg [data_width:0] max_val, error_val;
initial begin
i = 0;
ii = 0;
led=0;
data_from_rom='b000000000;
summed_ans='b000000000;
max_val='b000000000;
for (iii=0;iii<(size-1);iii=iii+1) begin
filt_sig[iii]=0;
ans_sig [iii]=0;
comp_sig[iii]=0;
summed_arr[iii]=0;
end
end
//port map to ROM
rom_compare ref_wave(
.clk(clk),
.addr(addr_to_rom), //text file?
.data(data_from_rom)
);
//Moore FSM
localparam [3:0]
s0=0, s1 = 1, s2 = 2, s3 = 3, s4 = 4, s5 = 5;
reg [3:0] state_reg, state_next;
initial state_next = 0;
always #(posedge clk, negedge reset_n) begin
if (reset_n == 'b0) begin //reset is active low
state_reg <= s0;
end else begin
state_reg <= state_next;
led <= led_val;
end
end
always #(state_reg) begin
state_next = state_reg;
led=0;
case (state_reg)
s0 : begin //initial state, reset state
if (!reset_n) begin
led <= 0;
ii <= 0;
end else begin
state_next <= s1;
end
end
s1 : begin
if (ii>(size)) begin
ii <= 0;
end else begin
addr_to_rom <= ii;
state_next <= s2;
end
end
s2 : begin
comp_sig_temp <= data_from_rom;
filt_sig [ii] <= result;
state_next <= s3;
end
s3 : begin
comp_sig[ii] <= comp_sig_temp;
state_next <= s4;
end
s4 : begin
ans_sig[ii] <= filt_sig[ii] - comp_sig[ii];
state_next <= s5;
end
s5 : begin
if (ii>(size-2)) begin
ans_sig_done = 1;
end else begin
ans_sig_done = 0;
end
ii <= ii+1;
state_next <= s0;
end
endcase
end
reg [(data_width+2):0] sum;
integer j;
always #* begin
sum = 0;
if (ans_sig_done == 1) begin
for (j=4; j<(size-1); j=j+2) begin
sum = sum +ans_sig[j];
if (ans_sig[j] > max_val) begin
max_val = ans_sig[j];
end
end
end
end
assign array_avg = sum >> 'd3; //2^3 = 8
always #(clk, result) begin //posedge clk, result
filt_sig [i] <= result;
i <= i + 1;
end
assign error_val = max_val >> 'd2; //approx 25% of max value of array
reg led_val;
always #(*)
begin
if (array_avg < error_val) begin
led_val <= 'b1;
end else begin
led_val <= 'b0;
end
end
endmodule
I figured it out!
The two instances were me trying to initialize one led = 0 in one always block and then assigning led <= led_val in another. You can't refer to an output in two different always blocks.

Module instantiation with the "number sign"

I have the main module with FIFO stuff.
Here it is:
module syn_fifo #(
parameter DATA_WIDTH = 8, // inpit capacity
parameter DATA_DEPTH = 8 // the depth of the FIFO
)
(
input wire clk,
input wire rst,
// Write_______________________________________________
input wire [DATA_WIDTH-1:0]din, // the input data
input wire wren, // Write anable
output wire full,
// Read________________________________________________
output wire [DATA_WIDTH-1:0]dout, // The output data
input wire rden, // Read enable
output wire empty
);
integer q_size; // The queue size(length)
integer golova; // The queue beginning
integer hvost; // The end of queue
reg [DATA_WIDTH-1:0]fifo[DATA_DEPTH-1:0];
assign full = (q_size == DATA_DEPTH) ? 1'b1: 1'b0; // FIFO is full
/*
True { full = (q_size==DATA_TEPTH) = 1 }, then wire "full" goes to "1" value
False { full = (q_size==DATA_TEPTH) = 0 }, then wire "full" goes to "0" value
*/
assign empty = (golova == hvost); // FIFO is empty
assign dout = fifo[hvost]; // FWFT (other write mode)
integer i;
//___________(The queue fullness)___________________
always #(posedge clk or posedge rst)
begin
if (rst == 1'b1)
begin
for (i = 0; i < DATA_DEPTH; i = i + 1) // incrementing the FIFO
fifo[i] <= 0; // Resetting the FIFO
golova <= 0; // Resetting the queue start variable
end
else
begin //Write_______________________________________
if (wren && ~full)
begin
fifo[golova] <= din; // putting data in to the golova
if (golova == DATA_DEPTH-1) // restrictions for the queue beginning
golova <= 0; // Reset the beginning
else
golova <= golova + 1; // other occurence incrementing
end
end
end
//Reading
always #(posedge clk or posedge rst)
begin
if (rst == 1'b1)
begin
hvost <= 0;
end
else
begin
if (rden && !empty)
/*for staying inside the queue limits - make the check of non equality of the "hvost" & "queue size"*/
begin
if (hvost == DATA_DEPTH-1) // if hvost = DATA_DEPTH-1, then
hvost <= 0; // Reset hvost
else
hvost <= hvost + 1;
end
end
end
always # (posedge clk)
begin
if (rst == 1'b1) begin
q_size <= 0;
end
else
begin
case ({wren && ~full, rden && ~empty} )
2'b01: q_size <= q_size + 1; // RO
2'b10: q_size <= q_size - 1; // WO
default: q_size <= q_size; // read and write at the same time
endcase
end
end
endmodule
Also i've got the testbench module down delow:
`timescale 1ns / 1ps
module fifo_tb();
localparam CLK_PERIOD = 10;
reg clk;
reg rst;
always begin
clk <= 1'b0;
#(CLK_PERIOD / 2);
clk <= 1'b1;
#(CLK_PERIOD / 2);
end
localparam DATA_WIDTH = 8;
localparam DATA_DEPTH = 4;
reg [DATA_WIDTH-1:0]din;
reg wren;
reg rden;
wire [DATA_WIDTH-1:0]dout;
wire empty;
wire full;
wire wr_valid;
wire rd_valid;
task write;
input integer length;
begin
if (length) begin
#(posedge clk);
wren <= 1'b1;
while (length) begin
#(posedge clk);
if (wr_valid) begin
length <= length - 1;
if (length == 1) begin
wren <= 1'b0;
end
end
end
end
end
endtask
task read;
input integer length;
begin
if (length) begin
#(posedge clk);
rden <= 1'b1;
while (length) begin
#(posedge clk);
if (rd_valid) begin
length <= length - 1;
if (length == 1) begin
rden <= 1'b0;
end
end
end
end
end
endtask
initial begin
rst <= 1'b0;
wren <= 1'b0;
rden <= 1'b0;
#50;
rst <= 1'b1;
#50;
rst <= 1'b0;
#200;
/* Test Start */
//write(4);
//read(4);
/* Test Stop */
#1000;
$finish;
end
assign wr_valid = wren & ~full;
assign rd_valid = rden & ~empty;
always #(posedge clk) begin
if (rst == 1'b1) begin
din <= 0;
end else begin
if (wr_valid == 1'b1) begin
din <= din + 1;
end
end
end
// write?
always begin
#400;
write(5);
#15;
write(7);
#25;
write(3);
#15;
write(9);
#15;
write(1);
#10000;
end
// read?
always begin
#420;
read(3);
#37;
read(13);
#21;
read(7);
#15;
read(9);
#15;
read(4);
#20;
read(7);
#10000;
end
initial begin
$dumpfile("test.vcd");
$dumpvars(0,fifo_tb);
end
syn_fifo #(.DATA_WIDTH(DATA_WIDTH),
.DATA_DEPTH(DATA_DEPTH)) dut ( .clk(clk),
.rst(rst),
.din(din),
.wren(wren),
.full(full),
.dout(dout),
.rden(rden),
.empty(empty));
endmodule
Trying to compile all of it with iVerilog + GTKwave + Win10 by next command:
C:\Program Files\iverilog\bin>iverilog -o fifo.v fifo_tb.v
The compiler gives me the next message:
fifo_tb.v:138:error: Unknown module type:syn_fifo
2 error(s) during elaboration.
These modules were missing:syn_fifo referenced 1 times
At the necessary line "138" maybe the main mistake is covered by the "Number sign" in module instantiation?
/*132|*/ initial begin
/*133|*/ $dumpfile("test.vcd");
/*134|*/ $dumpvars(0,fifo_tb);
/*135|*/ end
/*136|*/
/*137|*/ syn_fifo #(.DATA_WIDTH(DATA_WIDTH),
/*138|*/ .DATA_DEPTH(DATA_DEPTH)) dut ( .clk(clk),
/*139|*/ .rst(rst),
/*140|*/ .din(din),
/*141|*/ .wren(wren),
/*142|*/ .full(full),
/*143|*/ .dout(dout),
/*144|*/ .rden(rden),
/*145|*/ .empty(empty));
/*146|*/
/*147|*/ endmodule
I'm not shure of that.
Seems like you are indicating fifo.v to be your output file, try:
iverilog -o syn_fifo.tb -s fifo_tb fifo_tb.v fifo.v
-o -> output file
-s -> top module (in this case, the test one)
(after everything, include all the files)
Then, to run it:
vvp syn_fifo.tb
Thank you, dear #m4j0rt0m
I just forgot to type in the output file name at the CMD window. Was very exhausted so haven't noticed such a detail)))
Usually it looks like:
iverilog -o OUTPUT_FILE_NAME fifo_tb.v fifo.v
And also I tried your advice, and it's finally done!

verilog code of FIFO (first in first out) is not showing the proper result?

I wanted to design a FIFO having a certain depth and width. The Verilog code of the FIFO is written in Vivado 2017.4. The code is able to to read the input data, but it is only showing XX as the output. The design sources and test bench of the FIFO is given below. Help me to find the problem.
module fifo #(parameter WIDTH=8, parameter DEPTH=8) (
input wire [WIDTH-1:0] data_in,
output reg [WIDTH-1:0] data_out,
output reg data_valid,
input wire reset,
input wire clk
);
function integer clog2(input reg [32-1:0] value);
begin
value = value-1;
for (clog2=0; value>0; clog2=clog2+1)
value = value>>1;
end
endfunction
reg [WIDTH-1:0] data [DEPTH-1:0];
reg [clog2(DEPTH)-1:0] write_pointer;
reg [clog2(DEPTH)-1:0] read_pointer;
always #(posedge clk) begin
if (reset == 1'b0) begin
write_pointer <= 0;
read_pointer <= 1;
data_valid <= 0;
end else begin
if (write_pointer == DEPTH-1) write_pointer <= 0;
else write_pointer <= write_pointer + 1;
if (read_pointer == DEPTH-1) read_pointer <= 0;
else read_pointer <= read_pointer + 1;
data[write_pointer] <= data_in;
data_out <= data[read_pointer];
end
if (read_pointer == 0) data_valid <= 1'b1;
end
endmodule
test bench
`timescale 1ns / 1ps
module fifo_tb;
parameter WIDTH = 16;
parameter DEPTH = 8;
reg reset;
reg clk;
reg [(WIDTH-1):0] data_in;
wire [(WIDTH-1):0] data_out;
wire data_valid;
fifo #(WIDTH,DEPTH) U0(data_in,data_out,data_valid,reset,clk);
initial begin
clk = 0;
reset = 1;
#1 reset = 0;
#1 reset = 1;
end
// Create clock
always
#5 clk = ~clk;
reg signed [15:0] rom_memory [4096-1:0];
integer i=0;
initial
begin
$readmemh("C:\\Users\\input_7_zz.txt",rom_memory);
end
always#(posedge clk )
begin
if(~reset)
begin
data_in <= 0;
end
else
begin
data_in <= rom_memory[i];
i <= i+ 1;
end
end
endmodule
In your test bench code the clock is changed every 5 ticks:
// Create clock
always
#5 clk = ~clk;
The reset in RTL uses posedge of this clock:
always #(posedge clk) begin
if (reset == 1'b0) begin
write_pointer <= 0;
read_pointer <= 1;
data_valid <= 0;
So, the reset action could happen only if the posedge clk could be detected during the reset period. In other words you have a synchronous reset.
Nevertheless, in your test bench code your reset lasts only a single tick:
initial begin
clk = 0;
reset = 1;
#1 reset = 0;
#1 reset = 1; // << one tick after the reset was asserted.
end
Potentially you have 2 possible solutions.
1) keep the synchronous reset, but make sure that the posedge of the clk could be detected during the reset. So, make it bigger than a clock cycle (or at least half clock cycle if you are sure when it comes). Something like 5 should work in your case. Make it 10 or more to be sure for arbitrary starting points.
initial begin
clk = 0;
reset = 1;
#1 reset = 0;
#5 reset = 1; // << 5 tick after the reset was asserted.
The reset above will last from time 1 to time 6. The first posegde will happen at time 5. So, it should be sufficient in your case.
2) you can use an asynchronous reset in RTL which will look as the following:
always #(posedge clk or reset) begin
if (reset == 1'b0) begin
write_pointer <= 0;
read_pointer <= 1;
data_valid <= 0;
In the above case the always block will be executed whenever 'reset' changes. However you have to be careful about the timing of other assignment there. They could happen when you deassert reset with some offset from the posedge clk.

Change code to use block RAMs

I want to implement in Verilog the following Matlab code:
symBuf = [symBuf(numFFT/2+1:end); zeros(numFFT/2,1)];
symBuf(KF+(1:KF)) = symBuf(KF+(1:KF)) + txSymb;
It is a simple overlap and add operation.
Here is my implementation:
module overlap
#(K = 3,
FFT = 128
)
(
input signed [15:0] symbInReal ,
input signed [15:0] symbInImag ,
input clock ,
input reset ,
input readyIn ,
input validIn ,
input lastIn ,
output signed [15:0] outReal ,
output signed [15:0] outImag ,
output reg lastOut ,
output wire readyOut ,
output reg validOut
);
reg signed [15:0] previousSymbolReal [2*FFT*K-1:0] ;
reg signed [15:0] previousSymbolImag [2*FFT*K-1:0] ;
reg signed [15:0] txSymbolBuffReal [K*FFT-1:0] ;
reg signed [15:0] txSymbolBuffImag [K*FFT-1:0] ;
reg [15:0] counter ;
reg [1:0] state ;
reg [3:0] nextstate ;
reg [15:0] clockcount ;
reg signed [15:0] outputValueReal ;
reg signed [15:0] outputValueImag ;
reg [15:0] buffcount ;
reg [7:0] symboutcount ;
reg [7:0] symbincount ;
reg last ;
reg lastvalidout ;
wire lastout ;
integer i;
initial begin
for (i=0; i<2*FFT*K ; i = i + 1) begin
previousSymbolReal[i] = 0;
previousSymbolImag[i] = 0;
end
end
always#(posedge clock) begin
if(~reset) begin
counter <= 0;
end else begin
counter <= counter +1;
if(nextstate != state)
counter <= 0;
end
end
always#(*) begin
if(~reset) begin
nextstate = 0;
end else begin
nextstate = state;
if(readyIn) begin
case(state)
4'd0: begin
if(validIn || last) begin
nextstate = 1;
end
end
4'd1: begin
if (counter == (FFT*K-2)) begin
nextstate = 2;
end
end
4'd2: begin
nextstate = 0;
end
endcase
end
end
end
always#(posedge clock) begin
if(~reset) begin
state <= 0;
end else begin
if(readyIn)
state <= nextstate;
end
end
always#(posedge clock) begin
if(~reset) begin
clockcount <= 0;
symboutcount <= 0;
lastOut <= 0;
end else begin
if(readyIn) begin
clockcount <= clockcount +1 ;
case(state)
4'd0: begin
validOut <= 0;
clockcount <= 0;
lastOut <= 0;
end
4'd1: begin
if(~lastvalidout)
validOut <= 1;
outputValueReal <= previousSymbolReal[clockcount+ FFT/2];
outputValueImag <= previousSymbolImag[clockcount+ FFT/2];
end
4'd2: begin
outputValueReal <= previousSymbolReal[clockcount + FFT/2];
outputValueImag <= previousSymbolImag[clockcount + FFT/2];
clockcount <= 0;
if(~lastvalidout)
validOut <= 1;
if(symboutcount == symbincount + 1 && last)
lastOut <= 1;
symboutcount <= symboutcount +1 ;
end
endcase
end
end
end
assign readyOut = readyIn;
genvar M;
generate
for(M=0;M<K*FFT;M=M+1) begin
always#(posedge clock) begin
if(state==2) begin
previousSymbolReal[M] <= previousSymbolReal[M+FFT/2];
previousSymbolImag[M] <= previousSymbolImag[M+FFT/2];
end
end
end
for(M=K*FFT;M<2*K*FFT-FFT/2;M=M+1) begin
always#(posedge clock) begin
if(state==2) begin
previousSymbolReal[M] <= previousSymbolReal[M+FFT/2]+txSymbolBuffReal[M-K*FFT];
previousSymbolImag[M] <= previousSymbolImag[M+FFT/2]+txSymbolBuffImag[M-K*FFT];
end
end
end
for(M=2*K*FFT-FFT/2;M<2*K*FFT;M=M+1) begin
always#(posedge clock) begin
if(state==2) begin
previousSymbolReal[M] <= txSymbolBuffReal[M-K*FFT];
previousSymbolImag[M] <= txSymbolBuffImag[M-K*FFT];
end
end
end
endgenerate
always#(posedge clock) begin
if(~reset) begin
buffcount <= 0;
symbincount <= 0;
last <= 0;
end else begin
if(validIn) begin
txSymbolBuffReal[buffcount] <= symbInReal;
txSymbolBuffImag[buffcount] <= symbInImag;
buffcount <= buffcount +1;
if(buffcount == K*FFT-1) begin
symbincount <= symbincount + 1;
buffcount <= 0;
end
if(lastIn)
last <= 1;
end
end
end
always#(posedge clock) begin
if(~reset)
lastvalidout <= 0;
else begin
if(last && lastOut)
lastvalidout <= 1;
end
end
assign outReal = outputValueReal;
assign outImag = outputValueImag;
endmodule
The problem here is that I have 4 huge arrays which take up to 4 times what is available in my FPGA.
Hence, I want to be able to use block RAMs. However, I don't think it's possible due to the number of read and write operations performed.
Does anyone have a solution for this?
However, I don't think it's possible due to the number of read and write operations performed.
Correct. At least, not without major changes to your design.
A typical block RAM element can only read or write one (or sometimes two) values per clock cycle, but your generate loops are trying to update every element in the RAM at once!
To make this operation use a block RAM, you will need to implement a state machine to update one element per clock cycle, and to sequence operations such that other states wait until the updates have completed.
If you want to accelerate this, you may be able to split the array into multiple block RAMs so that multiple values can be updated in parallel. (You will need to carefully consider which elements need to be read/written to avoid conflicts.)

Resources