FPGA verilog代码:原码除法器设计

FPGA verilog代码:原码除法器设计

一、模块功能

用于实现FPGA中两个8位有符号数的除法,已经过验证。

二、模块接口:

1、clk: 输入时钟,用于同步模块的操作。
2、rst: 复位信号,高电平有效
3、x: 8位宽的输入线,表示被除数。
4、y: 8位宽的输入线,表示除数。
5、start: 启动信号,当它被激活时,模块开始执行除法操作。
6、z: 8位宽的输出线,表示除法操作的结果。
7、r: 8位宽的寄存器输出,根据注释,它似乎用于存储除法操作的中间结果或最终结果的一部分。
8、busy: 1位宽的寄存器输出,表示模块是否正在忙碌处理除法操作。当busy为高时,表示模块正在执行除法操作。

三、模块代码

 `timescale 1ns / 1ps

module divider (
    input  wire       clk,
    input  wire       rst,
    input  wire [7:0] x,
    input  wire [7:0] y,
    input  wire       start,
    output wire [7:0] z,
    output reg  [7:0] r=0,
    output reg        busy=0
);

    // TODO
 parameter               N=8;
localparam                  S=N<<1; 
reg [N-1:0]                 tempa=0;
reg [N-1:0]                 tempb=0;
reg [S-1:0]                 temp_a=0;
reg [S-1:0]                 temp_b=0; 
reg [5:0]                   st=0;
localparam                  st_idle = 6'b000000;
localparam                  st_init = 6'b000001;
localparam                  st_calc1 = 6'b000010;
localparam                  st_calc2 = 6'b000100;
localparam                  st_done = 6'b001000;
 
reg [N-1:0] i=0;
 
reg[N-1:0] z_reg=0;
wire       sign    ; 

assign  sign = (x[N-1] ^ y[N-1]);


assign z = z_reg ; 
always @(posedge clk) begin
    if(rst) begin
        busy <= 1'b0;
        st <= st_idle;
    end else begin
        case (st)
        st_idle: begin
         
            i <= 1'h0;
            if(start)   begin
                busy <= 1'b1;
//                tempa <= {x[N-1] == 1'd1}? {1'd0,~x[N-2:0]+1'd1} :{1'd0,x[N-2:0]}; 
//                tempb <= {y[N-1] == 1'd1}? {1'd0,~y[N-2:0]+1'd1} :{1'd0,y[N-2:0]};
                  tempa <= x[N-2:0] ;     
                  tempb <= y[N-2:0] ;     
                st <= st_init;
            end else begin
                st <= st_idle;
            end
        end
            
        st_init:  begin
            temp_a <= {{N{1'b0}},tempa};
            temp_b <= {tempb,{N{1'b0}}};
            st <= st_calc1;
              busy <= 1'b1;
        end
        st_calc1: begin
          busy <= 1'b1;
            if(i < N) begin
                temp_a <= {temp_a[S-2:0],1'b0};
                st <= st_calc2;
            end else  begin
                st <= st_done;
            end
        end
            
        st_calc2: begin
          busy <= 1'b1;
            if(temp_a[S-1:N] >= tempb) begin
                    temp_a <= temp_a - temp_b + 1'b1;
            end else begin
                    temp_a <= temp_a;
            end
            i <= i + 1'b1;    
            st <= st_calc1;
        end
        
        st_done: begin
//            z_reg <= (x[N-1]^y[N-1] == 1'd1)? {1'd1,~temp_a[N-2:0]+1'd1}:temp_a[N-1:0]   ;   
//            r <= (x[N-1] == 1'B1) ? { 1'd1,~temp_a[S-2:N]+1'd1 }    :temp_a[S-1:N]; 
            z_reg <= (x[N-1]^y[N-1] == 1'd1)? {1'd1, temp_a[N-2:0] }:temp_a[N-1:0]   ;   
            r <= (x[N-1] == 1'B1) ? { 1'd1, temp_a[S-2:N] }    :temp_a[S-1:N];            
            
             busy <= 1'b0;
            st <= st_idle;
        end
        
        default:  begin
            st <= st_idle;
        end
        endcase
    end
end
endmodule

四、模块例化

    divider DUT (
        .clk    (tb_clk),
        .rst    (tb_rst),
        .x      (dut_x),
        .y      (dut_y),
        .start  (dut_start),
        .z      (dut_z),
        .r      (dut_r),
        .busy   (dut_busy)
    );

五、模块代码分析

1、内部信号和寄存器

(1)tempa, tempb: 8位宽的寄存器,用于存储除法操作中的临时值。
(2)temp_a, temp_b: 16位宽的寄存器,是tempa和tempb的扩展,用于存储更宽的数值。
(3)st: 6位宽的寄存器,用于存储当前状态机的状态。
(4)i: 8位宽的寄存器,用作循环计数器。
(5)z_reg: 8位宽的寄存器,用于存储最终的输出结果。
(6)sign: 1位宽的线信号,用于判断x和y的符号是否相同。

2、参数和局部参数:
(1)N: 参数,定义了操作数的位数,这里设置为8。
(2)S: 局部参数,是N的两倍,用于定义扩展操作数的位数。

六、总结

该除法器模块是一个实用的FPGA设计组件,它接收两个8位的输入x和y,以及一个启动信号start。当启动信号被激活时,模块开始执行除法操作,并将结果输出到z。模块还包含一个busy信号,表示模块是否正在忙碌处理除法操作。

该博客为原创文章,未经过博主同意不得转载。
本文的博客地址为:https://blog.csdn.net/qq_34895681/article/details/141279845?spm=1001.2014.3001.5501

七、附录

模块的仿真代码如下所示:
`timescale 1ns / 1ps

`define TEST_NUM 8

/* 8 Tests:
    0.  14 /   3 =   4 ...  2
    1. 111 /  31 =   3 ... 18
    2. -73 /   6 = -12 ... -1
    3. -49 /  11 =  -4 ... -5
    4. 120 / -33 =  -3 ... 21
    5.  23 / -15 =  -1 ...  8
    6. -19 / -10 =   1 ... -9
    7. -53 / -25 =   2 ... -3
*/

module div_testbench();

    reg         tb_clk = 0;
    reg         tb_rst = 1;
    reg         dut_start;
    wire [ 7:0] dut_x;
    wire [ 7:0] dut_y;
    wire        dut_busy;
    wire [ 7:0] dut_z;
    wire [ 7:0] dut_r;

    reg  [ 7:0] tb_i;
    reg  [31:0] tb_data [`TEST_NUM-1:0];

    wire [ 7:0] tb_dat1  = tb_data[tb_i][31:24];
    wire [ 7:0] tb_dat2  = tb_data[tb_i][23:16];
    wire [ 7:0] tb_ans_z = tb_data[tb_i][15: 8];
    wire [ 7:0] tb_ans_r = tb_data[tb_i][ 7: 0];

    assign dut_x = tb_dat1;
    assign dut_y = tb_dat2;
    
    localparam S0 = 3'b000;
    localparam S1 = 3'b001;
    localparam S2 = 3'b010;
    localparam S3 = 3'b100;
    reg [2:0] tb_state, tb_nstat;

    wire tb_z_err = (tb_state == S3) && (dut_z != tb_ans_z) ? 1'b1 : 1'b0;
    wire tb_r_err = (tb_state == S3) && (dut_r != tb_ans_r) ? 1'b1 : 1'b0;

    initial begin
        $readmemh("data.txt", tb_data);
        #12 tb_rst = 0;
    end

    always #5 tb_clk = !tb_clk;

    always @(posedge tb_clk or posedge tb_rst) begin
        tb_state <= tb_rst ? S0 : tb_nstat;
    end

    always @(*) begin
        case (tb_state)
            S0: tb_nstat = tb_i < `TEST_NUM ? S1 : S0;
            S1: tb_nstat = S2;
            S2: tb_nstat = dut_busy ? S2 : S3;
            S3: tb_nstat = S0;
            default: tb_nstat = S0;
        endcase
    end

    always @(posedge tb_clk or posedge tb_rst) begin
        if (tb_rst) begin
            dut_start <= 1'b0;
            tb_i      <= 8'h0;
        end else begin
            case (tb_state)
                S0: begin
                    if (!dut_busy)
                        dut_start <= 1'b1;
                end
                S3: begin
                    tb_i <= tb_i + 8'h1;
                    
                    if (!tb_z_err & !tb_r_err)
                        $display("Test %0d passed", tb_i);

                    if (tb_i == `TEST_NUM - 8'h1) begin
                        $display("All tests passed! Congratulations! Good job!");
                        $finish;
                    end

                    if (tb_z_err) begin
                        $display("Test %0d failed: z should be 0x%02x, but yours: 0x%02x", tb_i, tb_ans_z, dut_z);
                        $stop;
                    end

                    if (tb_r_err) begin
                        $display("Test %0d failed: r should be 0x%02x, but yours: 0x%02x", tb_i, tb_ans_r, dut_r);
                        $stop;
                    end
                end
                default: begin
                    dut_start <= 1'b0;
                end
            endcase
        end
    end

    divider DUT (
        .clk    (tb_clk),
        .rst    (tb_rst),
        .x      (dut_x),
        .y      (dut_y),
        .start  (dut_start),
        .z      (dut_z),
        .r      (dut_r),
        .busy   (dut_busy)
    );

endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吾引先森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值