【0基础学会Verilog】007. Verilog实现类似C语言的循环结构

本文介绍如何使用Verilog HDL语言实现类似C语言循环结构,以此为基础进一步向同学们介绍Verilog语法

1. C语言循环结构求累加和函数

1.1 待转换的C语言函数–For循环结构求和

#include <stdio.h>
//---------------------------------------------------
//C语言函数:for_loop_sum_c()
//---------------------------------------------------
void for_loop_sum_c (int low,int high, int* sum)
{	
    int sum_t = 0; 	//定义局部变量保存累加和
    int i;			//为for循环定义一个循环变量
    for(i = low; i <= high; i++){ 	//for循环控制结构
        sum_t = sum_t + i;			//for循环体,可以是多条语句,为简单起见,这里只做累加	
    }
    //输出结果
    *sum = sum_t;
}

本例代码C语言函数for_loop_sum_c()使用for循环结构求从最小值low到最大值high之间整数累加和,然后函数使用指针变量int* sum输出累加结果。

1.2 编写调用函数for_loop_sum_c()的主函数验证函数的正确性

//调用get_loop_sum()函数,输出结果验证函数的功能正确性
void main(){
    int low_val = 2; 
    int high_val = 8;
    int sum = 0;
    for_loop_sum_c (low_val,high_val,&sum);
    printf("sum from %d to %d = %d",low_val,high_val,sum);
    return;
}

2. Verilog实现相同功能的模块

为了转换C语言的循环结构到Verilog的对应功能模块,我们先分析一下C语言函数for_loop_sum_c()里面for循环结构的几个要点:

  • for循环主要是使用一个循环变量控制的循环的执行次数,本例代码里是int i
  • 循环变量需要被初始化,本例代码里是i = low
  • 依据循环变量的值判断要继续循环或退出循环,本例代码里是i <= high
  • 循环变量在每次循环后必须更新为一个新的的值,这样保证有机会退出循环;
  • 必须有一个循环体,其内容可以很简单,也可以很复杂,在这里都会被当做一个复合语句对待。本例只简单地求累加和sum_t = sum_t + i;

这里要特别提醒!!!

很多教程里都会讲到Verilog语言里面也有for循环结构,但Verilog自带的for循环结构一般只能用于编写仿真代码,是不可综合的,也就是只能用于仿真模块里initial块里面,不可以用于编写可综合的硬件模块

Testbenchinitial块里代码都是类似C语言的结构,即所谓阻塞赋值,在这里Verilogfor循环结构与C语言的for循环结构基本一致,功能也相似。因为仿真代码本质是与C语言类似,是在CPU上运行的代码,而我们要实现的是实际的硬件模块设计,这是与C语言函数的本质区别。

`timescale 1ns/1ps
module for_loop_sum_v (
    input clk,
    input rst,

    input req,
    input [7:0] low, 
    input [7:0] high, 

    output reg busy,
    output reg valid,    
    output reg [15:0] sum
);

reg [7:0] cnt;
always @(posedge clk) begin
    if(rst) cnt <= 8'hff;
    else if (req) cnt <= low;
    else if (cnt <= high+1) cnt <= cnt + 1;
    else cnt <= cnt;
end

always @(posedge clk) begin
    if(rst) sum <= 0;
    else if(req) sum <= 0;
    else if(cnt >= low && cnt <= high) 
        sum <= sum + cnt;
    else sum <= sum;
end

always @(posedge clk) begin
    if(rst) valid <= 1'b0;
    else if(cnt == high) valid <= 1'b1;
    else valid <= 1'b0;
end

always @(*) begin
    if(cnt<=high) busy = 1'b1;
    else busy = 1'b0;
end

endmodule

3. 编写仿真测试模块

`timescale 1ns / 1ps
module for_loop_sum_v_tb();
	//1. 为时序逻辑生成时钟信号clk和复位信号rst
    reg clk;
    initial begin
        clk = 0;
    end
    always clk = #50 ~clk;

    //2. 为待测模块的每个输入信号声明一个reg型变量,包括复位信号rst
    reg rst;
    reg req;
    reg [7:0] low; 
    reg [7:0] high; 
	
	//3. 为待测模块的每个输出信号声明一个wire型变量
	wire busy;
    wire valid;    
    wire [15:0] sum;
    
	//4. initial block依序为待测模块的每个输入信号赋值
    initial begin
        low  = 0;
        high = 0;
        req = 1'b0;
        rst = 1;
        #300;
        rst = 0;
        #200; 

        //将req信号拉高一个时钟,启动待测模块的计算动作
        low  = 2;
        high = 12;
        #20;
        req = 1'b1;
        #100;
        req = 1'b0;

        //等待待测模块的输出信号valid变为1,表示计算结束
        @valid;

        #200;
        //再次将req信号拉高一个时钟,启动待测模块的下一次计算动作
        low  = 3;
        high = 9;
        #20;
        req = 1'b1;
        #100;
        req = 1'b0;

        //等待待测模块的输出信号valid变为1,表示计算结束
        @valid;

        #300;
        //结束仿真
        $finish;    
    end

    //例化待测试模块

    
    for_loop_sum_v uut(
        .clk(clk),
        .rst(rst),

        .req(req),
        .low(low), 
        .high(high), 

        .busy(busy),
        .valid(valid),    
        .sum(sum)
    );
endmodule

4. 仿真波形分析

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值