Verilog语法——3.模块设计实战

参考资料
【明德扬_verilog零基础入门语法HDL仿真快速掌握-手把手教你写FPGA/ASIC代码设计流程中的应用】

3 模块设计实战

3.1 简单模块设计

3.1.1 需要实现的简单模块示例

Verilog语法——3.模块设计实战_第1张图片

3.1.2 简单模块实现代码

写法一:组合逻辑和异步逻辑组合分开来写
Verilog语法——3.模块设计实战_第2张图片
写法二:组合逻辑和异步逻辑合起来写
Verilog语法——3.模块设计实战_第3张图片
代码一:(数据宽度不易改变)

//模块设计
module mul_module(
	mul_a,//输入
	mul_b,//输入
	clk,//输入——时钟
	rst_n,//输入——复位
	mul_result//输出
);
	//输入
	input[3:0] mul_a;//四位
	input[2:0] mul_b;//三位
	input clk;//一位
	input rst_n;//一位
	//输出,output需要定义reg还是wire
	output[6:0] mul_result;//七位
	reg[6:0] mul_result;//本模块。always产生,用reg
	reg[6:0] mul_result_tmp;

	//组合逻辑
	always@(*)begin
		mul_result_tmp = mul_a * mul_b;//组合逻辑的等号没有箭头
	end 
	//异步时序逻辑
	always@(posedge clk or negedge rst_n)begin 
		if(rst_n==1'b0)begin
			mul_result <= 0;
		end
		else begin
			mul_result <= mul_result_tmp;//时序逻辑的等号有箭头
		end
	end	
endmodule

代码二:(参数化数据位数)

//模块设计
module mul_module(
	mul_a,//输入
	mul_b,//输入
	clk,//输入——时钟
	rst_n,//输入——复位
	mul_result//输出
);
	//定义参数——位宽
	parameter A_W = 4;
	parameter B_W = 3;
	parameter C_W = A_W + B_W;
	//输入
	input[A_W-1:0] mul_a;//四位
	input[B_W-1:0] mul_b;//三位
	input clk;//一位
	input rst_n;//一位
	//输出,output需要定义reg还是wire
	output[C_W-1:0] mul_result;//七位
	reg[C_W-1:0] mul_result;//本模块。always产生,用reg
	reg[C_W-1:0] mul_result_tmp;

	//组合逻辑
	always@(*)begin
		mul_result_tmp = mul_a * mul_b;//组合逻辑的等号没有箭头
	end 
	//异步时序逻辑
	always@(posedge clk or negedge rst_n)begin 
		if(rst_n==1'b0)begin
			mul_result <= 0;
		end
		else begin
			mul_result <= mul_result_tmp;//时序逻辑的等号有箭头
		end
	end	
endmodule

Verilog语法——3.模块设计实战_第4张图片

3.2 复杂模块设计

3.2.1 需要实现的复杂模块示例(用到了3.1中设计的简单模块)

3.2.2 个人编码练习

module mul2port(
    din_a,//输入a
    din_b,//输入b
    din_c,//输入c
    din_d,//输入d
    sel_a,//输入选择信号a
    sel_b,//输入选择信号b
    clk,//时钟
    rst_n,//复位
    result_a,//输出a
    result_b//输出b
    );
    //宏定义
    parameter W_A = 3;//输入a位宽
    parameter W_B = 2;//输入b位宽
    parameter W_SWITCH = 4;//输入c位宽或输入d位宽
    parameter W_RESULT_A = W_A + W_SWITCH;//输出a位宽
    parameter W_RESULT_B = W_B + W_SWITCH;//输出b位宽
    //输入
    input[W_A-1:0] din_a;
    input[W_B-1:0] din_b;
    input[W_SWITCH-1:0] din_c;
    input[W_SWITCH-1:0] din_d;
    input sel_a;
    input sel_b;
    input clk;
    input rst_n;
    //输出
    output [W_RESULT_A-1:0] result_a;
    output [W_RESULT_B-1:0] result_b;
    reg [W_RESULT_A-1:0] result_a;
    reg [W_RESULT_B-1:0] result_b;
    //中间变量
    reg sel_tmp;//sel_a和sel_b的并
    reg sel_switch_tmp;//sel_a和sel_b经过触发器
    reg[W_SWITCH-1:0] switch_tmp;//选择器输出
    reg [W_RESULT_A-1:0] result_a_tmp;
    reg [W_RESULT_B-1:0] result_b_tmp;
    
    always@(*) begin
        sel_tmp = sel_a&&sel_b;
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            sel_switch_tmp <= 0;
        end
        else begin
            sel_switch_tmp <= sel_tmp;
        end
    end
    
    always@(*)begin 
        if(sel_switch_tmp==0)begin
            switch_tmp = din_c;
        end
        else begin
            switch_tmp = din_d;
        end
    end
    
    mul_module#(.B_W(W_B)) mul_4_2(//注意此处参数例化B_W变成2
        .mul_a (din_b),
        .mul_b (switch_tmp),
        .clk (clk),
        .rst_n (rst_n),
        .mul_result (result_b_tmp)
    );
    mul_module mul_4_3(//注意此处参数例化B_W变成2
        .mul_a (din_A),
        .mul_b (switch_tmp),
        .clk (clk),
        .rst_n (rst_n),
        .mul_result (result_a_tmp)
    );

    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            result_a <= 0;
        end
        else begin
            result_a <= result_a_tmp;
        end
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            result_b <= 0;
        end
        else begin
            result_b <= result_b_tmp;
        end
    end
endmodule

生成的RTL
Verilog语法——3.模块设计实战_第5张图片

  • 自己写代码才能遇到坑:
  • 引用模块产生的输出需要传到wire类型定义的变量中,使用reg类型会报错

3.2.3 标准答案

设计思路:从结果倒推设计过程

  1. 结果result_a和result_b由两个D触发器产生,D触发器输入未命名,令为result_a_tmp和result_b_tmp
  2. 模块mul_4_2和mul_4_3的一个输入来自选择器,该输入未命名,令为sel_dout
  3. 选择器的一个输入未命名,该输入同时也是D触发器的输出,令为sel
    Verilog语法——3.模块设计实战_第6张图片
    标准答案代码
module mul2port(
    din_a,//输入a
    din_b,//输入b
    din_c,//输入c
    din_d,//输入d
    sel_a,//输入选择信号a
    sel_b,//输入选择信号b
    clk,//时钟
    rst_n,//复位
    result_a,//输出a
    result_b//输出b
    );
    //宏定义
    parameter W_A = 3;//输入a位宽
    parameter W_B = 2;//输入b位宽
    parameter W_SWITCH = 4;//输入c位宽或输入d位宽
    parameter W_RESULT_A = W_A + W_SWITCH;//输出a位宽
    parameter W_RESULT_B = W_B + W_SWITCH;//输出b位宽
    //输入
    input[W_A-1:0] din_a;
    input[W_B-1:0] din_b;
    input[W_SWITCH-1:0] din_c;
    input[W_SWITCH-1:0] din_d;
    input sel_a;
    input sel_b;
    input clk;
    input rst_n;
    //输出
    output [W_RESULT_A-1:0] result_a;
    output [W_RESULT_B-1:0] result_b;
    reg [W_RESULT_A-1:0] result_a;
    reg [W_RESULT_B-1:0] result_b;
    //中间变量
    reg sel_tmp;//sel_a和sel_b的并
    reg sel;//sel_a和sel_b经过触发器
    reg[W_SWITCH-1:0] sel_dout;//选择器输出
    wire [W_RESULT_A-1:0] result_a_tmp;//例化模块得到,使用wire
    wire [W_RESULT_B-1:0] result_b_tmp;//例化模块得到,使用wire
    
	always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            result_a <= 0;
        end
        else begin
            result_a <= result_a_tmp;
        end
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            result_b <= 0;
        end
        else begin
            result_b <= result_b_tmp;
        end
    end
	//例化两个模块
    mul_module#(.A_W(W_B),.B_W(W_SWITCH)) mul_4_2(//注意此处参数例化,个人编码练习中参数例化错误
        .mul_a (din_b),
        .mul_b (sel_dout),
        .clk (clk),
        .rst_n (rst_n),
        .mul_result (result_b_tmp)
    );
    mul_module#(.A_W(W_A),.B_W(W_SWITCH)) mul_4_3(//注意此处参数例化,个人编码练习中参数例化错误
        .mul_a (din_A),
        .mul_b (sel_dout),
        .clk (clk),
        .rst_n (rst_n),
        .mul_result (result_a_tmp)
    );
	//选择器
	always@(*)begin 
        if(sel==0)begin
            sel_dout = din_c;
        end
        else begin
            sel_dout = din_d;
        end
    end


    always@(*) begin
        sel_tmp = sel_a&sel_b;//
    end
    
    always@(posedge clk or negedge rst_n)begin
        if(rst_n==1'b0)begin
            sel <= 0;
        end
        else begin
            sel <= sel_tmp;
        end
    end    

endmodule

对照标准答案发现的错误

  • 个人编码练习的代码中没有把中间变量result_a_tmp和result_b_tmp改成wire型
  • 个人编码练习的代码没有正确引用模块mul_module,即参数例化错误,在mul2port模块中,输入a和输入b分别是3位和2位,对应着mul_4_3和mul_4_2的输入a,因此要对应例化,输入b都是4位,也需要参数例化
  • 与门只需要一个&
//2024.1.10:虽然什么都没干,今天还是累了,明天起码更新两篇!!
//2024.1.11:坏了,明天一定全力以赴,今天写好了复杂的电路,明天对答案吧
//2024.1.12:完成此篇博文

你可能感兴趣的:(FPGA,fpga开发)