爲啥要在FPGA上實現for循環的代碼?
在現在的編程和算法中,有一部分的算法的速度已經到達了瓶頸,爲了提高算法的速度,提高效率,經常會遇到將c或者c++的代碼轉換爲Verilog語言進行在FPGA上實現。
下文中,我借鑑的是明德揚的FPGA專題for循環對應verilog代碼,上面是視頻鏈接,本文是博主的學習筆記,喜歡可以拿去借鑑。
例1
for(i=0;i<8;i++){
}
對於這樣一個for循環,我們很容易理解的就是i這裏相當於一個計數器,不斷自加一,但是爲了保證模塊的功能完整,即for循環只執行8次而且只執行一次,所以我們需要一個en使能信號和一個flag來標識計數一次的完成。
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = flag_add;
assign end_cnt = add_cnt && cnt==8-1;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
flag_add<=0;
end
else if(en==1)begin
flag_add<=1;
end
else if(end_cnt==1)begin
flag_add<=0;
end
end
例2
for(i=0;i<8;i++){
sum +=a[i];
}
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = flag_add;
assign end_cnt = add_cnt && cnt==8-1 ;
reg [7:0]a [7: 0];
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
flag_add<=0;
end
else if(en==1)begin
flag_add<=1;
end
else if(end_cnt==1)begin
flag_add<=0;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
sum<=0;
end
else begin
sum<= sum +a[cnt];
end
end
if判斷的其中的一種情況:
for(i=0;i<8;i++){
if(i==6)
sum +=a[i];
}
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = flag_add;
assign end_cnt = add_cnt && cnt==8-1 ;
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
flag_add<=0;
end
else if(en==1)begin
flag_add<=1;
end
else if(end_cnt==1)begin
flag_add<=0;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
sum<=0;
end
else if(add_cnt && cnt==7-1)begin
sum<= sum +a[cnt];
end
end
例3
for(i=0;i<8;i++){
for(j=0;j<4;j++){
sum +=a[i][j];
}
}
在這裏的雙重循環,我們根據前面想到的是調用兩個計數器,但是這裏不同於二維數組的是,這裏使用 sum <= sum + a[cnt1][cnt0];語法上可能不支持,所以我們可以根據數組的大小來聲明爲對應位寬的線,讓下標索引單線的不同位的切片,從而得到這樣雙重循環的實現。
同樣的方法我們可以想到常用的ram,我們可以進行聲明對應大小的ram從而對其地址進行索引
//-------------------------------------------------------
//-------------------------------------------------------
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
flag_add<=0;
end
else if(en==1)begin
flag_add<=1;
end
else if(end_cnt==1)begin
flag_add<=0;
end
end
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt0 <= 0;
end
else if(add_cnt0)begin
if(end_cnt0)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1;
end
end
assign add_cnt0 =flag_add;
assign end_cnt0 = add_cnt0 && cnt0==4-1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt1 <= 0;
end
else if(add_cnt1)begin
if(end_cnt1)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1;
end
end
assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1==8-1;
reg [7:0]a[7:0][3:0];
reg [255:0]a;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
sum <= 0;
end
else if(add_cnt0==1)begin
sum <= sum + a[cnt1][cnt0];//可能語法不支持
sum <= sum + a[(cnt1*32+cnt0*8 + 8-1) -:8];
end
end
注:固定數的乘法,可以直接使用乘號
例4
for(i=0;i<8;i++){
if(i==1){
a = b + 1;
c = a + d;
a = 2;
}
}
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
a <=0;
end
else if(add_cnt && cnt ==2-1)begin
a <=2;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
c <= 0;
end
else if(add_cnt && cnt ==2-1)begin
c = b + 1+ d;
end
end
例5
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt0 <= 0;
end
else if(add_cnt0)begin
if(end_cnt0)
cnt0 <= 0;
else
cnt0 <= cnt0 + 1;
end
end
assign add_cnt0 =flag_add;
assign end_cnt0 = add_cnt0 && cnt0==x-1;
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt1 <= 0;
end
else if(add_cnt1)begin
if(end_cnt1)
cnt1 <= 0;
else
cnt1 <= cnt1 + 1;
end
end
assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1==y-1;
always @(*)begin
x= (len-1) - cnt1;
y= (len-1);
end
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)begin
vec <=0;
end
else if(add_cnt0 && vec[cnt0]<vec[cnt0+1])begin
vec[cnt0] <= vec[cnt0+1];
vec[cnt0+1]<= vec[cnt0] ;
end
end