Good day guys, I'm created a Shift - And - Add multiplier. I'm confused on why my output is wrong and always at 85. Is it something with the Test bench ? It's working by the way.
new1.v
`define M ACC[0]
module mult4X4 (Clk, St, Mplier, Mcand, Done, Result);
input Clk,St;
input [3:0] Mplier, Mcand;
output Done;
output [7:0] Result;
reg [3:0] State;
reg [8:0] ACC;
initial
begin
State = 0;
ACC = 0;
end
always #(posedge Clk)
begin
case (State)
0:
begin
if(St == 1'b1)
begin
ACC[8:4] <= 5'b00000 ;
ACC[3:0] <= Mplier ;
State <= 1;
end
end
1,3,5,7 :
begin
if(`M==1'b1)
begin
ACC[8:4] <= {1'b0, ACC[7:4]} + Mcand ;
State <= State +1;
end
else
begin
ACC <= {1'b0, ACC[8:1]};
State <= State + 2;
end
end
2,4,6,8 :
begin
ACC <= {1'b0, ACC[8:1]};
State <= State +1;
end
9:
begin
State <= 0;
end
endcase
end
assign Done = (State == 9) ? 1'b1 : 1'b0 ;
assign Result = (State == 9) ? ACC[7:0] : 8'b01010101;
endmodule
tb_new1.v
module tb_mult4X4;
reg Clk,St,nReset;
reg [3:0] Mplier;
reg [3:0] Mcand;
wire Done;
wire [7:0] Result;
mult4X4 UUT (Clk,St,Mplier,Mcand,Done,Result);
initial begin
$dumpfile ("mult4X4.vpd");
$dumpvars;
end
initial
Clk = 0;
always
#5 Clk =~Clk;
initial begin
nReset = 0;
St = 0;
Mcand = 4'b1101;
Mplier = 4'b1011;
#10
nReset = 1;
St = 1;
Mcand = 4'b1111;
Mplier = 4'b1001;
#10
Mcand = 4'b0101;
Mplier = 4'b1010;
#10
Mcand = 4'b1111;
Mplier = 4'b1111;
#10
Mcand = 4'b1101;
Mplier = 4'b1010;
$finish;
end
endmodule
I ran though the code so many times and everything seems to be following my FSM. Can anyone please point out where went wrong. Really confused on this one
#10 is way to short. Your RTL requires 10 clocks to complete but you change the input every clock (half clk is #5).
Use #100 or better yet #(posedge Done); (which makes the test-bench to wait for done regardless the number of clocks that is required).
Related
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!
I'm trying to write a module which performs convolution on 24 by 24 bitmap image.
And here is the DUT and testbench.
Maybe there are some problems and I spend couple of hours to find what is problem but I can't figure it out.
Additionally, RTL Anaylsis works well without any error which makes me think that there is no problem on DUT.
Is there anyone who can help me?
module top_conv(clk,resetn,start,load_image_0,load_image_1,load_image_2,done,result);
input clk,resetn,load_image_0,load_image_1,load_image_2,start;
output done,result;
reg [1:0] st;
reg [1:0] nst;
reg [7:0] input_buffer_0 [0:2];
reg [7:0] input_buffer_1 [0:2];
reg [7:0] input_buffer_2 [0:2];
wire [7:0] load_image_0;
wire [7:0] load_image_1;
wire [7:0] load_image_2;
reg [7:0] result;
reg done;
integer load_cnt, row_cnt, col_cnt , result_cnt ;
parameter IDLE = 2'b00, LOAD = 2'b01, MAC = 2'b10, DONE = 2'b11;
always#(posedge clk or negedge resetn)begin
case(st)
LOAD:begin
input_buffer_0[load_cnt] <= load_image_0;
input_buffer_1[load_cnt] <= load_image_1;
input_buffer_2[load_cnt] <= load_image_2;
end
MAC:begin
input_buffer_0[0] <= input_buffer_0[1];
input_buffer_1[0] <= input_buffer_1[1];
input_buffer_2[0] <= input_buffer_2[1];
input_buffer_0[1] <= input_buffer_0[2];
input_buffer_1[1] <= input_buffer_0[2];
input_buffer_2[1] <= input_buffer_0[2];
input_buffer_0[2] <= load_image_0;
input_buffer_1[2] <= load_image_1;
input_buffer_2[2] <= load_image_2;
end
endcase
end
always#(posedge clk or negedge resetn)begin
if(!resetn) load_cnt <= 0;
else if(st == LOAD) load_cnt <= load_cnt + 1;
else load_cnt <= 0;
end
always#(posedge clk or negedge resetn)begin
if(!resetn) begin
col_cnt <= 0;
row_cnt <= 0;
end
else if(st == MAC) begin
if(col_cnt == 21) begin
col_cnt <= 0;
row_cnt <= row_cnt +1;
end
end
else begin
col_cnt <= 0;
row_cnt <= 0;
end
end
always#(posedge clk or negedge resetn)begin
if( st == MAC ) begin
result <= (input_buffer_0[0] + 2*input_buffer_0[1] + input_buffer_0[2])/16 + (input_buffer_1[0] + 2*input_buffer_1[1] + input_buffer_1[2])/8 + (input_buffer_2[0] + 2*input_buffer_2[1] + input_buffer_2[2])/16;
done <= 1'b1;
end
else done <=1'b0;
end
always#(posedge clk or negedge resetn)begin
if(!resetn) st <= 0;
else st <= nst;
end
always#(*)begin
case(st)
IDLE:begin
if(start) nst = LOAD;
else nst = IDLE;
end
LOAD:begin
if(load_cnt == 2)nst = MAC;
else nst = LOAD;
end
MAC:begin
if((row_cnt == 21)&&(col_cnt == 21)) nst = DONE;
else if(col_cnt == 21) nst = LOAD;
else nst = MAC;
end
DONE:begin
nst = IDLE;
end
endcase
end
endmodule
module testbench;
reg clk,resetn,start;
reg[7:0] val;
reg [7:0] b_load_image_0,g_load_image_0,r_load_image_0;
reg [7:0] b_load_image_1,g_load_image_1,r_load_image_1;
reg [7:0] b_load_image_2,g_load_image_2,r_load_image_2;
wire [2:0] done;
wire [7:0] b_result,g_result,r_result;
integer index;
top_conv blue_result (clk,resetn,start,b_load_image_0,b_load_image_1,b_load_image_2,done[0],b_result);
top_conv green_result (clk,resetn,start,g_load_image_0,g_load_image_1,g_load_image_2,done[1],g_result);
top_conv red_result (clk,resetn,start,r_load_image_0,r_load_image_1,r_load_image_2,done[2],r_result);
parameter read_fileName1 = "D:/blur_filter_unit/test.bmp" ;
localparam ARRAY_LEN = 24*24*3 + 54;
reg [7:0] data1 [0:ARRAY_LEN-1];
integer size,start_pos,width,height,bitcount;
task readBMP;
integer fileID1;
begin
fileID1 = $fopen(read_fileName1, "rb");
$display("%d" ,fileID1);
if(fileID1 == 0) begin
$display("Error: please check file path");
$finish;
end
else begin
$fread(data1, fileID1);
$fclose(fileID1);
size = {data1[5],data1[4],data1[3],data1[2]};
$display("size - %d", size);
start_pos = {data1[13],data1[12],data1[11],data1[10]};
$display("startpos : %d", start_pos);
width = {data1[21],data1[20],data1[19],data1[18]};
height = {data1[25],data1[24],data1[23],data1[22]};
$display("width - %d; height - %d",width,height);
bitcount = {data1[29],data1[28]};
if(bitcount != 24) begin
$display("Error: Please check the image file. It may be corrupted");
end
if(width%4)begin
$display("width is not suitable");
$finish;
end
end
end
endtask
integer i,j;
localparam RESULT_ARRAY_LEN = 24*24*3;
reg[7:0] result[0:RESULT_ARRAY_LEN - 1];
always #(posedge clk or negedge resetn)begin
if(!resetn)begin
j <= 8'b0;
end
else begin
if(&done[2:0]) begin
result[j] <= b_result;
result[j+1] <= g_result;
result[j+2] <= r_result;
j <= j+3;
end
end
end
parameter write_fileName1 = "D:/blur_filter_unit/result.bmp";
task writeBMP;
integer fileID, k;
begin
fileID = $fopen(write_fileName1,"wb");
for(k = 0; k < start_pos; k=k+1)begin
$fwrite(fileID, "%c",data1[k]);
end
for(k = start_pos; k<size; k=k+1)begin
$fwrite(fileID,"%c",result[k-start_pos]);
end
$fclose(fileID);
$display("Result.bmp is generated \n");
end
endtask
always begin
#1 clk = ~clk;
end
initial begin
clk = 1;
resetn = 0;
start = 0;
index = 1;
b_load_image_0 = 0;
g_load_image_0 = 0;
r_load_image_0 = 0;
b_load_image_1 = 0;
g_load_image_1 = 0;
r_load_image_1 = 0;
b_load_image_2 = 0;
g_load_image_2 = 0;
r_load_image_2 = 0;
readBMP;
#10;
resetn = 1;
start = 1;
for(i = start_pos; i<size; i=i+3)begin
{r_load_image_0, r_load_image_1, r_load_image_2} ={data1[i+2],data1[i+2+width*3],data1[i+2+width*6]};
{g_load_image_0, g_load_image_1, g_load_image_2} = {data1[i+1],data1[i+1+width*3],data1[i+1+width*6]};
{b_load_image_0, b_load_image_1, b_load_image_2} = {data1[i],data1[i+width*3],data1[i+width*6]};
#1;
end
#10;
#writeBMP;
#10
$stop;
end
endmodule
Even though this is not a complete answer, for figuring out the error you can use the below code which is revised version of your code for ease of debugging.
i think when synthesizing your design you might have faced this issue
Due to line numbers 25 & 71 in your code.You are declaring edge sensitive signal in sensitivity list and u are not using it in the always block. so tool cannot understand how to map it and throwing an error.
module top_conv(
input clk,resetn,start,
input [7:0] load_image_0,load_image_1,load_image_2,
output reg done,
output reg [7:0] result
);
reg [7:0] input_buffer_0 [0:2];
reg [7:0] input_buffer_1 [0:2];
reg [7:0] input_buffer_2 [0:2];
reg [4:0] row_cnt, col_cnt;
reg [1:0] load_cnt;
parameter IDLE = 2'b00,
LOAD = 2'b01,
MAC = 2'b10,
DONE = 2'b11;
reg [1:0] state,next;
always#(posedge clk or negedge resetn)begin
if(!resetn) state <= #10 IDLE ;
else state <= #10 next ;
end
always#(*)begin
next = 'bx; // default undefined state
case(state)
IDLE: next = start ? LOAD : IDLE ;
LOAD: next = (load_cnt == 2) ? MAC : LOAD ;
MAC : next = ((row_cnt == 21)&&(col_cnt == 21)) ? DONE :
(col_cnt == 21) ? LOAD : MAC ;
DONE: next = IDLE ;
endcase
end
always#(posedge clk or negedge resetn)begin
if(!resetn) begin
col_cnt <= #10 0;
row_cnt <= #10 0;
load_cnt <= #10 0;
done <= #10 1'b0;
result <= #10 0;
end else begin
col_cnt <= #10 0;
row_cnt <= #10 0;
load_cnt <= #10 0;
done <= #10 1'b0;
result <= #10 0;
case(next)
LOAD:load_cnt <= #10 load_cnt + 1'b1 ;
MAC :begin
col_cnt <= #10 (col_cnt == 21) ? 0 : col_cnt + 1'b1 ;
row_cnt <= #10 (col_cnt == 21) ? row_cnt : row_cnt + 1'b1 ;
end
DONE:begin
result <= #10 (input_buffer_0[0] + 2*input_buffer_0[1] + input_buffer_0[2])/16 +
(input_buffer_1[0] + 2*input_buffer_1[1] + input_buffer_1[2])/8 +
(input_buffer_2[0] + 2*input_buffer_2[1] + input_buffer_2[2])/16 ;
done <= #10 1'b1;
end
endcase
end
end
always#(posedge clk)begin
case(next)
LOAD:begin
input_buffer_0[load_cnt] <= #10 load_image_0;
input_buffer_1[load_cnt] <= #10 load_image_1;
input_buffer_2[load_cnt] <= #10 load_image_2;
end
MAC:begin
input_buffer_0[0] <= #10 input_buffer_0[1];
input_buffer_1[0] <= #10 input_buffer_1[1];
input_buffer_2[0] <= #10 input_buffer_2[1];
input_buffer_0[1] <= #10 input_buffer_0[2];
input_buffer_1[1] <= #10 input_buffer_0[2];
input_buffer_2[1] <= #10 input_buffer_0[2];
input_buffer_0[2] <= #10 load_image_0;
input_buffer_1[2] <= #10 load_image_1;
input_buffer_2[2] <= #10 load_image_2;
end
endcase
end
endmodule
I make a design for an adder but the result is wrong.
module FMUL(CLK, St, F1, E1, F2, E2, F, V, done);
input CLK;
input St;
input [3:0] F1;
input [3:0] E1;
input [3:0] F2;
input [3:0] E2;
output[6:0] F;
output V;
output done;
reg[6:0] F;
reg done;
reg V;
reg[3:0] A;
reg[3:0] B;
reg[3:0] C;
reg[4:0] X;
reg[4:0] Y;
reg Load;
reg Adx;
reg SM8;
reg RSF;
reg LSF;
reg AdSh;
reg Sh;
reg Cm;
reg Mdone;
reg[1:0] PS1;
reg[1:0] NS1;
reg[2:0] State;
reg[2:0] Nextstate;
initial
begin
State = 0;
PS1 = 0;
NS1 = 0;
Nextstate=0;
end
always #(PS1 or St or Mdone or X or A or B)
begin : main_control
Load = 1'b0;
Adx = 1'b0;
NS1 = 0;
SM8 = 1'b0;
RSF = 1'b0;
LSF = 1'b0;
V = 1'b0;
F = 7'b0000000;
done = 1'b0;
case (PS1)
0 :
begin
F = 7'b0000000;
done = 1'b0;
V = 1'b0;
if(St == 1'b1)
begin
Load = 1'b1;
NS1 = 1;
end
end
1 :
begin
Adx = 1'b1;
NS1 = 2;
end
2 :
begin
if(Mdone == 1'b1)
begin
if(A==0)
begin
SM8 = 1'b1;
end
else if(A == 4 & B == 0)
begin
RSF = 1'b1;
end
else if (A[2] == A[1])
begin
LSF = 1'b1;
end
NS1 = 3;
end
else
begin
NS1 = 2;
end
end
3 : begin
if(X[4] != X[3])
begin
V = 1'b1;
end
else
begin
V = 1'b0;
end
done = 1'b1;
F = {A[2:0],B};
if(St==1'b0)
begin
NS1 = 0;
end
end
endcase
end
always #(State or Adx or B)
begin : mul2c
AdSh = 1'b0;
Sh = 1'b0;
Cm = 1'b0;
Mdone = 1'b0;
Nextstate = 0;
case(State)
0 :
begin
if(Adx==1'b1)
begin
if((B[0]) == 1'b1)
begin
AdSh = 1'b1;
end
else
begin
Sh = 1'b1;
end
Nextstate = 1;
end
end
1,2 :
begin
if((B[0])==1'b1)
begin
AdSh = 1'b1;
end
else
begin
Sh = 1'b1;
end
Nextstate = State + 1;
end
3:
begin
if((B[0])==1'b1)
begin
Cm = 1'b1;
AdSh = 1'b1;
end
else
begin
Sh = 1'b1;
end
Nextstate = 4;
end
4:
begin
Mdone = 1'b1;
Nextstate = 0;
end
endcase
end
wire [3:0] addout;
assign addout = (Cm == 1'b0)? (A+C) : (A-C);
always #(posedge CLK)
begin : update
PS1 <= NS1;
State <= Nextstate;
if(Load == 1'b1)
begin
X <= {E1[3], E1};
Y <= {E2[3], E2};
A <= 4'b0000;
B <= F1;
C <= F2;
end
if(Adx == 1'b1)
begin
X <= X+Y;
end
if(SM8 == 1'b1)
begin
X <= 5'b11000;
end
if(RSF == 1'b1)
begin
A <= {1'b0, A[3:1]};
B <= {A[0], B[3:1]};
X <= X+1;
end
if(LSF == 1'b1)
begin
A <= {A[2:0], B[3]};
B <= {B[2:0], 1'b0};
X <= X+31;
end
if(AdSh == 1'b1)
begin
A <= {(C[3]^Cm), addout[3:1]};
B <= {addout[0], B[3:1]};
end
if(Sh == 1'b1)
begin
A <= {A[3], A[3:1]};
B <= {A[0], B[3:1]};
end
end
endmodule
test bench.
module tb_FMUL();
wire[6:0] F;
wire done;
wire V;
reg[3:0] A;
reg[3:0] B;
reg[3:0] C;
reg[4:0] X;
reg[4:0] Y;
reg Load;
reg Adx;
reg SM8;
reg RSF;
reg LSF;
reg AdSh;
reg Sh;
reg Cm;
reg Mdone;
reg[1:0] PS1;
reg[1:0] NS1;
reg[2:0] State;
reg[2:0] Nextstate;
reg CLK;
reg St;
reg [3:0] F1;
reg [3:0] E1;
reg [3:0] F2;
reg [3:0] E2;
FMUL u0(CLK, St, F1, E1, F2, E2, F, V, done);
always
begin
#10 CLK <= ~CLK;
end
initial
begin
#100 F1 = 2.125;
E1 = 5; F2 = 5.1; E2 = 1; St=0;
#100 F1 = 1.125;
E1 = 5; F2 = 2.1; E2 = 2; St=0;
#100 F1 = 5.125;
E1 = 5; F2 = 3.1; E2 = 3; St=0;
end
endmodule
The simulation results waveform.
enter image description here
I refer to the book.There is no code test bench.
So I made. But did't operate.
also CLK not is not changed.
please review the testbench code.
You have (at least) two problems:
Your clock needs to be initialised (eg to 1'b0):
initial CLK = 1'b0;
The initial value of any wire or reg in Verilog is 1'bx; ~1'bx is 1'bx; so CLK remains at 1'bx.
Your simulation doesn't stop. I added a call to $finish in the main initial block.
https://www.edaplayground.com/x/r4U
I have written an asynchronous fifo buffer but when I run it I get XXX on output ports. I referred to concerned questions on SO which said asserting reset signals should make it work but despite of doing it I am still facing the same issue.
Any help will be appreciated.
Thanks
module fifo
#(parameter width =8,
addr_width = 4,
depth = (1 << addr_width)
)
( // Read port
output [width - 1:0] dout,
output reg empty_out,
input wire rd_en,
input wire rclk,
//write port
input wire [width-1:0] din,
output reg full,
input wire wr_en,
input wire wclk,
input wire rst
);
(* ram_style = "bram" *)
reg [width-1:0] memory_s[depth-1:0];
reg [31:0] push_ptr;
reg [31:0] pop_ptr;
assign dout = memory_s[pop_ptr]; // assign cannot assign values to registers
always #(posedge wclk)
begin
if (rst == 1)
push_ptr <= 0;
else if(wr_en == 1)
begin
memory_s\[push_ptr\] <= din;
//$display("w: %d", push_ptr);
if (push_ptr == (depth -1))
push_ptr <= 0;
else
push_ptr <= push_ptr + 1;
end
end
always # (posedge rclk)
if (rst == 1)
pop_ptr <= 0;
else if (rd_en ==1)
begin
//dout <= memory_s\[pop_ptr\];
//$display("r: %d", pop_ptr);
if (pop_ptr == depth-1)
pop_ptr <=0;
else
pop_ptr <= pop_ptr+1;
end
reg full_s;
reg overflow;
always #*
begin
if (rst == 1)
full_s <= 0;
else if (push_ptr <= pop_ptr)
if (push_ptr + 1 == pop_ptr)
begin
full_s <= 1;
$display("push,pop,full: %d %d %d", push_ptr,pop_ptr,full_s);
end
else
full_s <=0;
else
if(push_ptr + 1 == pop_ptr + depth)
begin
full_s <= 1;
$display("push,pop,full: %d %d %d", push_ptr,pop_ptr,full_s);
end
else
full_s <= 0;
end
endmodule]
Here is a waveform:
(external link)
Added Testbench
module fifoTb;
// Inputs
reg rd_en;
reg rclk;
reg [7:0] din;
reg wr_en;
reg wclk;
reg rst;
// Outputs
wire[7:0] dout;
wire empty_out;
wire full;
// Instantiate the Unit Under Test (UUT)
fifo uut (
.dout(dout),
.empty_out(empty_out),
.rd_en(rd_en),
.rclk(rclk),
.din(din),
.full(full),
.wr_en(wr_en),
.wclk(wclk),
.rst(rst)
);
initial begin
// Initialize Inputs
rd_en = 0;
rclk = 0;
wr_en = 0;
wclk = 0;
rst = 1;
din = 8'h0;
// Wait 100 ns for global reset to finish
#100;
rst = 0;
wr_en = 1;
din = 8'h1;
#101 din = 8'h2;
rd_en = 1;
// Add stimulus here
end
always begin #10 wclk = ~wclk; end
always begin #10 rclk = ~rclk; end
endmodule
I would suggest adding additional logic on your output dout signal
to avoid having 'bxxx values because memory_s has an initial value
of 'bxxx:
assign dout = (rd_en) ? memory_s[pop_ptr] : 0;
Additional tips in creating your testbench:
First, it is very important to try to understand how your
device works.
Upon reading your RTL code, I concluded that your fifo works in the
following manner:
Write operation
always #(posedge wclk)
begin
if (rst == 1)
push_ptr <= 0;
else if(wr_en == 1)
begin
memory_s[push_ptr] <= din;
if (push_ptr == (depth -1))
push_ptr <= 0;
else
push_ptr <= push_ptr + 1;
end
end
When wr_en is high, two operations are performed.
The value from din will be written on memory_s pointed by
push_ptr at the next positive edge of wclk.
If push_ptr is equal with (depth -1), 0 will be written to
the register push_ptr else register push_ptr is incremented by 1
instead.
Write operation will not be performed when wr_en is low.
Read operation
assign dout = memory_s[pop_ptr];
always # (posedge rclk)
if (rst == 1)
pop_ptr <= 0;
else if (rd_en ==1)
begin
if (pop_ptr == depth-1)
pop_ptr <=0;
else
pop_ptr <= pop_ptr+1;
end
When rd_en is high, increment the register pop_ptr by 1 if
pop_ptr is not equal to depth-1 else write it with 0 instead.
dout will all the time hold the value of memory_s pointed by the register
pop_ptr.
Creating tasks for every operation that you are going to perform
is usually convenient.
wr_en = 1;
din = 8'h1;
#101 din = 8'h2;
rd_en = 1;
I created write and read tasks for you as an example and you might want
to substitute your code above.
task write(input [7:0] pdin);
$display("[ testbench ] writing data: %0x", pdin);
din <= pdin;
wr_en <= 1;
#(posedge wclk);
din <= 0;
wr_en <= 0;
endtask
task read(output [7:0] prdata);
rd_en <= 1;
#(posedge rclk);
prdata = dout;
rd_en <= 0;
$display("[ testbench ] reading data: %0x", prdata);
endtask
Here is how to use the tasks:
write(8'hAA);
read(read_data);
write(8'hCC);
read(read_data);
write(8'hBC);
read(read_data);
In writing a combinational circuit, it is not recommended to add
a reset logic on to it.
always #*
begin
if (rst == 1)
full_s <= 0; . . .
Also, most of the EDA tool vendors recommend to use blocking (=) assignment
in writing a combinational circuit and non-blocking assignment (<=) in a
sequential circuit.
End you're simulation when you're done by calling $finish.
initial begin
#1000; $finish;
end
I have a program written in Verilog and I want to convert it into a FSM automatically. Is this possible (just to visualize it)?
Here is the code :
module pci(reset,clk,frame,irdy,trdy,devsel,idsel,ad,cbe,par,stop,inta,led_out);
input reset;
input clk;
input frame;
input irdy;
output trdy;
output devsel;
input idsel;
inout [31:0] ad;
input [3:0] cbe;
inout par;
output stop;
output inta;
output [3:0] led_out;
parameter DEVICE_ID = 16'h9500;
parameter VENDOR_ID = 16'h106d; // Sequent!
parameter DEVICE_CLASS = 24'hFF0000; // Misc
parameter DEVICE_REV = 8'h01;
parameter SUBSYSTEM_ID = 16'h0001; // Card identifier
parameter SUBSYSTEM_VENDOR_ID = 16'hBEBE; // Card identifier
parameter DEVSEL_TIMING = 2'b00; // Fast!
reg [2:0] state;
reg [31:0] data;
reg [1:0] enable;
parameter EN_NONE = 0;
parameter EN_RD = 1;
parameter EN_WR = 2;
parameter EN_TR = 3;
reg memen; // respond to baseaddr?
reg [7:0] baseaddr;
reg [5:0] address;
parameter ST_IDLE = 3'b000;
parameter ST_BUSY = 3'b010;
parameter ST_MEMREAD = 3'b100;
parameter ST_MEMWRITE = 3'b101;
parameter ST_CFGREAD = 3'b110;
parameter ST_CFGWRITE = 3'b111;
parameter MEMREAD = 4'b0110;
parameter MEMWRITE = 4'b0111;
parameter CFGREAD = 4'b1010;
parameter CFGWRITE = 4'b1011;
`define LED
`ifdef LED
reg [3:0] led;
`endif
`undef STATE_DEBUG_LED
`ifdef STATE_DEBUG_LED
assign led_out = ~state;
`else
`ifdef LED
assign led_out = ~led; // board is wired for active low LEDs
`endif
`endif
assign ad = (enable == EN_RD) ? data : 32'bZ;
assign trdy = (enable == EN_NONE) ? 'bZ : (enable == EN_TR ? 1 : 0);
assign par = (enable == EN_RD) ? 0 : 'bZ;
reg devsel;
assign stop = 1'bZ;
assign inta = 1'bZ;
wire cfg_hit = ((cbe == CFGREAD || cbe == CFGWRITE) && idsel && ad[1:0] == 2'b00);
wire addr_hit = ((cbe == MEMREAD || cbe == MEMWRITE) && memen && ad[31:12] == {12'b0, baseaddr});
wire hit = cfg_hit | addr_hit;
always #(posedge clk)
begin
if (~reset) begin
state <= ST_IDLE;
enable <= EN_NONE;
baseaddr <= 0;
devsel <= 'bZ;
memen <= 0;
`ifdef LED
led <= 0;
`endif
end
else begin
case (state)
ST_IDLE: begin
enable <= EN_NONE;
devsel <= 'bZ;
if (~frame) begin
address <= ad[7:2];
if (hit) begin
state <= {1'b1, cbe[3], cbe[0]};
devsel <= 0;
// pipeline the write enable
if (cbe[0])
enable <= EN_WR;
end
else begin
state <= ST_BUSY;
enable <= EN_NONE;
end
end
end
ST_BUSY: begin
devsel <= 'bZ;
enable <= EN_NONE;
if (frame)
state <= ST_IDLE;
end
ST_CFGREAD: begin
enable <= EN_RD;
if (~irdy || trdy) begin
case (address)
0: data <= { DEVICE_ID, VENDOR_ID };
1: data <= { 5'b0, DEVSEL_TIMING, 9'b0, 14'b0, memen, 1'b0};
2: data <= { DEVICE_CLASS, DEVICE_REV };
4: data <= { 12'b0, baseaddr, 8'b0, 4'b0010 }; // baseaddr + request mem < 1Mbyte
11: data <= {SUBSYSTEM_ID, SUBSYSTEM_VENDOR_ID };
16: data <= { 24'b0, baseaddr };
default: data <= 'h00000000;
endcase
address <= address + 1;
end
if (frame && ~irdy && ~trdy) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
ST_CFGWRITE: begin
enable <= EN_WR;
if (~irdy) begin
case (address)
4: baseaddr <= ad[19:12]; // XXX examine cbe
1: memen <= ad[1];
default: ;
endcase
address <= address + 1;
if (frame) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
end
ST_MEMREAD: begin
enable <= EN_RD;
if (~irdy || trdy) begin
case (address)
`ifdef LED
0: data <= { 28'b0, led };
`endif
default: data <= 'h00000000;
endcase
address <= address + 1;
end
if (frame && ~irdy && ~trdy) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
ST_MEMWRITE: begin
enable <= EN_WR;
if (~irdy) begin
case (address)
`ifdef LED
0: led <= ad[3:0];
`endif
default: ;
endcase
address <= address + 1;
if (frame) begin
devsel <= 1;
state <= ST_IDLE;
enable <= EN_TR;
end
end
end
endcase
end
end
endmodule
If there is no automatic way, could you explain a way of doing this?
Here is an FSM made with hand but can't test so ...
Does it seem ok?
It is sometimes easier to write the code and have the documentation generated from that. Sometimes you inherit legacy code without documentation, in these situations especially if new to a language tools to help visualise what is happening can be quite useful.
With cadence tools you can run your code with 'code coverage' then imc can load the coverage data and run FSM Analysis.
I have included a simple FSM below and show the generated state diagram.
module simple_fsm();
//Inputs to FSM
logic clk;
logic rst_n;
logic [1:0] state ;
logic [1:0] nextstate;
logic turn_on ;
logic turn_off ;
localparam S_OFF = 2'b00;
localparam S_GO_ON = 2'b01;
localparam S_ON = 2'b10;
localparam S_GO_OFF = 2'b11;
// State FlipFlop
always #(posedge clk or negedge rst_n) begin
if (~rst_n) begin
state <= 2'b0;
end
else begin
state <= nextstate;
end
end
//Nextstate Logic
always #* begin
case (state)
2'd0 : if (turn_on) begin
nextstate = S_GO_ON;
end
2'd1 : nextstate = S_ON;
2'd2 : if (turn_off) begin
nextstate = S_GO_OFF ;
end
2'd3 : nextstate = S_OFF;
endcase
end
//TB clk
initial begin
#1ns;
clk = 0;
forever begin
#20ns;
clk = ~clk;
end
end
//The Test
initial begin
rst_n = 1'b0;
turn_on = 1'b0;
turn_off = 1'b0;
#(posedge clk);
#(posedge clk);
rst_n = 1'b1 ;
#(posedge clk);
turn_on = 1'b1;
#(posedge clk);
turn_on = 1'b0;
#(posedge clk);
#(posedge clk);
#100ms;
$finish();
end
endmodule
Execute with :
$ irun simple_fsm.sv -coverage all -covdut simple_fsm
$ imc &
Load cov_work (folder created by above simulation) in imc, select simple_fsm and choose FSM Analysis.
imc also helps to visualise your test coverage as well. Arcs and states that have not been hit are shown in red.
We have seen that there are some tools which can visualise the FSM, another part of the question is; is the syntax of the purposed FSM suitable for these tools.
#vermaete has reported that Modelsim SE can not see the FSM. From imc I get :
Which does not seem to cover the complexity of the code, and is shown as only having 2 reachable states, IDLE and BUSY. I would recommend if OP is going down the route of using tools to visualise, adopt a simpler (syntax) FSM structure so that the tools can parse it better.
The better and expensive simulators can detect FSM's in the code and make a visualization of it. E.g. the Modelsim SE version. These can be nice to understand code and check the coveage.
But making you're own drawing of a 6-state FSM is not that hard.
The way to check if it's OK is to write a simulation and check that the behaviour is what you want. There is no point getting a bubble diagram out and seeing if it matches your hand-drawn one, as you have no way of knowing if your hand-drawn diagram is correct...
case(segmentRead)
//-------------------
SEGMENT0: begin
READ_Ready_EEPROM <= 1'b0;
READ_RDSR_Enable <= 1'b0;
Read_Enable <= 1'b0;
READ_RDSR_DATA_REG <= 8'b0;
// READ_DATA_REG <= 8'b0;
end
//-------------------
SEGMENT2: begin
READ_RDSR_Enable <= 1'b1;
READ_RDSR_DATA_REG <= 8'b0;
end
// //-------------------
SEGMENT3: begin
READ_RDSR_Enable <= 1'b0;
READ_RDSR_DATA_REG <= RDSR_Data;
end
//-------------------
SEGMENT4: begin
Read_Enable <= 1'b1;
end
//-------------------
SEGMENT5: begin
Read_Enable <= 1'b0;
READ_DATA_REG <= Read_Data;
end
//-------------------
SEGMENT6: begin
READ_Ready_EEPROM <= 1'b1;
end
//-------------------
endcase