为啥要在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 

 

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐