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