Advertisement

verilog 实现9位有符号乘法器

阅读量:

一、移位相加乘法器

移位相加的原理

从被乘数的最低位开始检查每一位,若当前位为1,则将乘数向左移动i位(其中i从0开始,依次递增至width-1),然后将其结果与上一次的累加和相加;若当前位为0,则将乘数向左移动i位后,用0进行累加,直到处理完被乘数的最高位。

实际是由移位运算和加法运算构成。比较高速。

优点:
占用资源较少,主要在低速信号处理中

缺点:
串行乘法器的运行速度较慢,完成一个结果输出所需时钟周期数量较多,尤其在高位宽的乘法运算中表现得尤为明显。因此,可以采用改进的流水线架构来实现移位累加。

1、串行形式,使用状态机来实现

复制代码
    module multiply1#(
            parameter DATAWIDTH=9
    )(clk, x, y, result);
    
    parameter s0 = 0, s1 = 1, s2 = 2;
    
    input clk;
    input      [DATAWIDTH-1:0] x, y;
    output   [DATAWIDTH*2-2:0] result;
    
    reg   [DATAWIDTH*2-2:0] result_reg;
    
    
    reg  [DATAWIDTH-1:0] count = 0;
    reg  [1:0] state = 0;
    reg  [DATAWIDTH*2-3:0] P, T;
    wire [DATAWIDTH-2:0] x_reg;
    reg   [DATAWIDTH-2:0] y_reg;
    reg   msb=0;
    
    always @(posedge clk) begin
        case (state)
            s0: begin
                y_reg<=(y[DATAWIDTH-1]==0)?y[DATAWIDTH-2:0]:~y[DATAWIDTH-2:0]+1'b1; 
                msb <= x[DATAWIDTH-1] ^ y[DATAWIDTH-1];
                count <= 0;
                P <= 0;
                T <= {{(DATAWIDTH-1){1'b0}}, x_reg};
                state <= s1;
            end
            s1: begin
                if(count == (DATAWIDTH-1))
                    state <= s2;
                else begin
                    if(y_reg[0] == 1'b1)
                        P <= P + T;
                    else
                        P <= P;
                    y_reg <= y_reg >> 1;
                    T <= T << 1;
                    count <= count + 1;
                    state <= s1;
                end
            end
            s2: begin
                result_reg <= {msb,P[DATAWIDTH*2-3:0]};
                state <= s0;
            end
            default: ;
        endcase
    end
       assign x_reg = (x[DATAWIDTH-1]==0)?  x[DATAWIDTH-2:0]  : ~x[DATAWIDTH-2:0]+1'b1;
       assign result = (result_reg[DATAWIDTH*2-2]==0)? result_reg : 
       				{result_reg[DATAWIDTH*2-2],~result_reg[DATAWIDTH*2-3:0]+1'b1};
    
    endmodule
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

这里需要说明的是,最初我把x_reg放置于always模块中,即与当前的y_reg进行赋值操作的同时进行。随后,代码中有一行T <= {{(DATAWIDTH-1){1'b0}}, x_reg};,由于该赋值是非阻塞操作,因此此时T中的x_reg实际上是上一个时钟周期的值。而Ty_reg的赋值分别位于状态机的下一状态,因此在乘法器计算输入数据时,出现了时序错位。即最终计算出的是上一个周期的x与当前周期的y的乘积。

我将x_reg置于always模块之外,这样就能减少一个延时,从而确保乘积计算时输入数据不会出现错误。当然,你可以采用其他方法,但必须确保输入数据在时序上没有错位。

仿真程序

复制代码
    `timescale 1ns / 1ps
    
    module tb_multiply1();
    
    parameter DATAWIDTH=9;
    reg clk;
    
    reg   [DATAWIDTH-1:0] Ain,Bin;
    
    wire   [DATAWIDTH*2-2:0] result;
    initial
    	begin
    		Ain = 5;
    		Bin = 3;
    		clk = 0;
    	end
    always #5 clk = ~clk;
    always @(posedge clk)
    	begin
    		#110
    		Ain = Ain-2;
    		Bin = Bin+1;
    	end
    multiply1 #(.DATAWIDTH( DATAWIDTH)) u1(clk,Ain,Bin,result);
    endmodule
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

仿真模块中,需要注意以下几点:基于状态机的设计,系统通过程序判断输出结果相较于输入数据存在10个时钟周期的延迟。随后,系统将在输入数据的第11个时钟周期进入第一个状态,以读取下一组输入数据。这意味着,在这期间会有9个时钟周期的输入数据无法被读取,而下一个输出结果将基于第11个时钟周期的输入数据。例如图中所示:

仿真结果

在这里插入图片描述

所以,为了解决这个问题,可以在仿真过程中,在testbench程序中进行人工干预,将相邻两组输入数据之间延时n个时钟周期,只要其达到11个时钟周期的目标,就能确保在采样后获取下一组数据。通过仿真波形,可以直观地验证这种方法的正确性:

在这里插入图片描述

2、流水线形式

我就不建议将该形式修改为具有输入数据宽度参数的通用程序。原因在于,不同位宽的输入数据需要定义不同数量的变量,而变量数量的控制也并非易事。不过,确实是有办法实现的,你可以自行尝试一下。

一般的快速乘法器通常采用逐位并行的迭代阵列结构,将每个操作数的N位同时输入到乘法器中进行处理。然而,对于FPGA设备而言,进位的速率快于加法的速率,这使得传统的并行阵列结构在FPGA实现中存在效率瓶颈。因此,可以采用多级流水线的优化方案,将相邻部分乘积的结果依次累加到最终的输出乘积上,从而形成一个二叉树形式的级联结构。这种优化方法使得N位乘法器所需的级数减少为log2(N)级,从而显著提升了运算效率。

在进行有符号数相乘运算时,我首先计算了符号位的信息。接着,我利用该流水线处理输入数据的低8位部分,计算出无符号乘积的结果。最后,将符号位的信息整合进去,从而得到最终的有符号乘积结果。需要注意的是,各变量的位宽选择要恰当,以避免运算错误。

复制代码
    module multiply2 (
                                  mul_a,
                                  mul_b,
                                  mul_out,
                                  clk,
                                  rst_n
                                  );
                        
       parameter   MUL_WIDTH  = 9;
       parameter   MUL_RESULT = 17;
      
       input [MUL_WIDTH-1:0]   mul_a;
       input [MUL_WIDTH-1:0]   mul_b;
       input                   clk;
       input                   rst_n;
      
       output [MUL_RESULT-1:0]   mul_out;
      
       wire [MUL_RESULT-1:0]   mul_out;
       wire [MUL_RESULT-1:0]   mul_out_reg;
       reg                    msb;
       reg                    msb_reg_0;
       reg                    msb_reg_1;
       reg                    msb_reg_2;
       reg [MUL_WIDTH-1:0]   mul_a_reg;
       reg [MUL_WIDTH-1:0]   mul_b_reg;
      
       reg [MUL_RESULT-2:0]   stored0;
       reg [MUL_RESULT-2:0]   stored1;
       reg [MUL_RESULT-2:0]   stored2;
       reg [MUL_RESULT-2:0]   stored3;
       reg [MUL_RESULT-2:0]   stored4;
       reg [MUL_RESULT-2:0]   stored5;
       reg [MUL_RESULT-2:0]   stored6;
       reg [MUL_RESULT-2:0]   stored7;
       reg [MUL_RESULT-2:0]   out1,out2;
       reg [MUL_RESULT-2:0]   add1,add2,add3,add4;
       reg [MUL_RESULT-2:0]   add;
     
     always @ ( posedge clk or negedge rst_n )
     begin
    if ( !rst_n )
       begin
    
          stored0 <= 16'b0;
          stored1 <= 16'b0;
          stored2 <= 16'b0;
          stored3 <= 16'b0;
          stored4 <= 16'b0;
          stored5 <= 16'b0;
          stored6 <= 16'b0;
          stored7 <= 16'b0;
          mul_a_reg<=9'b0;
          mul_b_reg<=9'b0;
          add<=16'b0;
    
          msb<=0;
          msb_reg_0<=0;
          msb_reg_1<=0;
          msb_reg_2<=0;
          add1 <= 16'b0;
    		  add2 <= 16'b0;
    		  add3 <= 16'b0;
    		  add4 <= 16'b0;
          
       
       end
    else
       begin           
         //注意,下面两句是没有延迟的,因为他们的右侧的mul_a,mul_b是输入信号
          mul_a_reg <= (mul_a[8]==0)?  mul_a : {mul_a[8],~mul_a[7:0]+1'b1};        
          mul_b_reg <= (mul_b[8]==0)?  mul_b : {mul_b[8],~mul_b[7:0]+1'b1};        
          
          msb_reg_0 <= mul_a_reg[8] ^ mul_b_reg[8];
          msb_reg_1<=msb_reg_0;
          msb_reg_2<=msb_reg_1;
          msb<=msb_reg_2;
          
          stored0 <= mul_b_reg[0] ? {8'b0,mul_a_reg[7:0]}       : 16'b0;
          stored1 <= mul_b_reg[1] ? {7'b0,mul_a_reg[7:0],1'b0}  : 16'b0;
          stored2 <= mul_b_reg[2] ? {6'b0,mul_a_reg[7:0],2'b0}  : 16'b0;
          stored3 <= mul_b_reg[3] ? {5'b0,mul_a_reg[7:0],3'b0}  : 16'b0;
          stored4 <= mul_b_reg[4] ? {4'b0,mul_a_reg[7:0],4'b0}  : 16'b0;
          stored5 <= mul_b_reg[5] ? {3'b0,mul_a_reg[7:0],5'b0}  : 16'b0;
          stored6 <= mul_b_reg[6] ? {2'b0,mul_a_reg[7:0],6'b0}  : 16'b0;
          stored7 <= mul_b_reg[7] ? {1'b0,mul_a_reg[7:0],7'b0}  : 16'b0;
          add1 <= stored1 + stored0;
          add2 <= stored3 + stored2;
          add3 <= stored5 + stored4;
          add4 <= stored6 + stored7;
          out1 <= add1 + add2;
          out2 <= add3 + add4;
          add <= out1 + out2;
    
     end
    
     end
    
     assign mul_out_reg = {msb,add[15:0]};
     assign mul_out=(mul_out_reg[16]==0)?mul_out_reg:{mul_out_reg[16],~mul_out_reg[15:0]+1'b1};
    
     endmodule
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

仿真程序

复制代码
    `timescale 1ns / 1ps
    
    module tb_multiply2();
    reg   clk,rst_n;
    reg   [8:0] Ain,Bin;
    wire  [16:0] result;
    initial
    	begin
    		#1
    		Ain = 5;
    		Bin = 2;
    		clk = 0;
    		rst_n=0;
    		#3
    		rst_n=1;
    	end
    always #5 clk = ~clk;
    always @(posedge clk)
    	begin
    		#1
    		Ain = Ain - 2;
    		Bin = Bin + 1;
    	end
    multiply2 u2(Ain,Bin,result,clk,rst_n);
    endmodule
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

仿真结果

在这里插入图片描述

从仿真结果的验证来看,计算结果的正确性得到了充分的确认。需要注意的是,由于采用了三级流水线结构,并且在mul_a_regmul_b_reg组件中各引入了一级时延,总共造成了4个时钟周期的延迟。因此,为了确保计算结果符号位的准确性,我们需要在msb端增加四级时延,这样可以使msb的延时与result的延时达到一致,从而保证最终输出结果的符号位不会出现错误。

你可以自己改变一下msb的延迟周期,看一下计算结果是不是正确的。

二、并行乘法器

通过乘法运算符来实现,代码中实现了8位无符号数的乘法运算。进行有符号数乘法时,需将数据声明为signed类型。

基于并行乘法设计的乘法器,采用*符号在Verilog语言中进行乘法运算。该方法所得到的乘法器设计需要依赖综合工具来完成运算,通常这类算法的表现并不十分理想。

特点:
由乘法运算符描述、由EDA软件综合

运算速度快、耗用资源多

复制代码
    module multiply3(rst_n,
                            clk,
                            a,
                            b,
                            out
                                 );
    parameter DATA_SIZE = 8;
    
    input rst_n;
    input clk;
    input signed [DATA_SIZE - 1 : 0] a;
    input signed [DATA_SIZE - 1 : 0] b;
    
    output signed [2*DATA_SIZE - 1 : 0] out;
    
    reg signed [DATA_SIZE - 1 : 0] a_r;
    reg signed [DATA_SIZE - 1 : 0] b_r;
    
    wire signed [2*DATA_SIZE - 1 : 0] out_tmp;
    reg signed [2*DATA_SIZE - 1 : 0] out;
    
    //输入数据打一拍
    always@(posedge clk)
    if(!rst_n)
        begin
            a_r <= 8'd0;
            b_r <= 8'd0;
        end
    else
        begin
            a_r <= a;
            b_r <= b;
        end
    //只能做无符号数的相乘,若要做有符号数乘法,需将数据声明为signed类型
    assign out_tmp = a_r*b_r;  
    
    //输出数据打一拍
    always@(posedge clk)
    if(!rst_n)
        begin
            out <= 16'd0;
        end
    else
        begin
            out <= out_tmp;
        end
    
    endmodule
    
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

仿真程序

复制代码
    `timescale 1ns / 1ps
    
    module tb_multiply3();
    reg clk,rst_n;
    reg signed [7:0] Ain,Bin;
    wire signed [15:0] result;
    initial
    	begin
    		#1
    		Ain = 6;
    		Bin = 7;
    		clk = 0;
    		rst_n=0;
    		#3
    		rst_n=1;
    		
    	end
    always #5 clk = ~clk;
    always @(posedge clk)
    	begin
    		#1
    		Ain = Ain-2;
    		Bin =Bin+3;
    	end
    multiply3 u3(rst_n,clk,Ain,Bin,result);
    endmodule
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

仿真结果

在这里插入图片描述

可以看出,和程序中的描述方式一致,输出比输入延迟了一个时钟周期!!!


附录 :例化8位无符号乘法器实现9位有符号乘法器


一、前言

这里与上文内容相近,主要区别在于将无符号乘法器独立设计为一个专用模块,在有符号数乘积的计算过程中对该模块进行复制以实现功能。

二、移位相加乘法器—串行形式

1、8位无符号乘法器

复制代码
    module unsigned_mul_8bit #(
            parameter DATAWIDTH=8
    )(clk, x, y, result);
    
    parameter s0 = 0, s1 = 1, s2 = 2;
    
    input clk;
    input    [DATAWIDTH-1:0] x, y;
    output   [DATAWIDTH*2-1:0] result;
    
    reg      [DATAWIDTH*2-1:0] result;
    
    
    reg  [DATAWIDTH-1:0] count = 0;
    reg  [1:0] state = 0;
    reg  [DATAWIDTH*2-1:0] P, T;
    reg  [DATAWIDTH-1:0] y_reg;
    
    always @(posedge clk) begin
        case (state)
            s0: begin
                count <= 0;
                P <= 0;
                y_reg <= y;
                T <= {{DATAWIDTH{1'b0}}, x};
                state <= s1;
            end
            s1: begin
                if(count == 8)
                    state <= s2;
                else begin
                    if(y_reg[0] == 1'b1)
                        P <= P + T;
                    else
                        P <= P;
                    y_reg <= y_reg >> 1;
                    T <= T << 1;
                    count <= count + 1;
                    state <= s1;
                end
            end
            s2: begin
                result <= P;
                state <= s0;
            end
            default: ;
        endcase
    end
      
    endmodule
    
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

2、9位有符号乘法器(例化8位无符号乘法器)

复制代码
    module signed_mul_9bit(clk, x, y, result);
    parameter in_width=9,
              result_width=2*in_width-1;
    
    input   clk;
    input   [in_width-1:0] x, y;
    output  [result_width-1:0] result;
    wire    [result_width-1:0] result_reg;
    
    wire    [2*(in_width-1)-1:0] out;
      
    wire    [in_width-2:0] x_reg;
    wire    [in_width-2:0] y_reg;
    reg                    msb=0;
    reg                    msb_reg_0=0;
    reg                    msb_reg_1=0;
    reg                    msb_reg_2=0;
    reg                    msb_reg_3=0;
    reg                    msb_reg_4=0;
    reg                    msb_reg_5=0;
    reg                    msb_reg_6=0;
    reg                    msb_reg_7=0;
    reg                    msb_reg_8=0;
    reg                    msb_reg_9=0;
    assign   x_reg = (x[8]==0)?  x[7:0]  : ~x[7:0]+1'b1;
    assign   y_reg = (y[8]==0)?  y[7:0]  : ~y[7:0]+1'b1; 
    
    always @(posedge clk) begin
            msb_reg_0 <=x[8] ^ y[8];
            msb_reg_1<=msb_reg_0;
            msb_reg_2<=msb_reg_1;
            msb_reg_3<=msb_reg_2; 
            msb_reg_4<=msb_reg_3; 
            msb_reg_5<=msb_reg_4; 
            msb_reg_6<=msb_reg_5; 
            msb_reg_7<=msb_reg_6; 
            msb_reg_8<=msb_reg_7; 
            msb_reg_9<=msb_reg_8; 
            msb<=msb_reg_9;
            
    end
    
    unsigned_mul_8bit #(.DATAWIDTH( in_width-1)) u1(clk, x_reg, y_reg, out);
    
    assign result_reg = {msb,out[15:0]};
       
    assign result=(result_reg[16]==0)?result_reg:{result_reg[16],~result_reg[15:0]+1'b1};
    
    endmodule
    
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

这里由于msb延后了10个时钟周期,是因为输出比输入延后了10个时钟周期。因此,为了确保输出结果的符号正确,我们需要让msb与输出数据保持对齐。

3、仿真程序

复制代码
    `timescale 1ns / 1ps
    
    module tb_m1();
    reg clk;
    
    reg   [8:0] Ain,Bin;
    
    wire   [16:0] result;
    initial
    	begin
    		Ain = 5;
    		Bin = 3;
    		clk = 0;
    	end
    always #5 clk = ~clk;
    always @(posedge clk)
    	begin
    		#110
    		Ain = Ain-2;
    		Bin = Bin+1;
    	end
    signed_mul_9bit u1(clk,Ain,Bin,result);
    endmodule
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

4、仿真结果

在这里插入图片描述
三、移位相加乘法器—流水线形式

1、8位无符号乘法器

复制代码
    module un_signed_mul_8bit(
             mul_a,
             mul_b,
             mul_out,
             clk,
             rst_n
             );
                        
       parameter   MUL_WIDTH  = 8;
       parameter   MUL_RESULT = 16;
      
       input [MUL_WIDTH-1:0]   mul_a;
       input [MUL_WIDTH-1:0]   mul_b;
       input                   clk;
       input                   rst_n;
      
       output [MUL_RESULT-1:0]   mul_out;
      
       reg [MUL_RESULT-1:0]   mul_out;
    
       reg [MUL_RESULT-1:0]   stored0;
       reg [MUL_RESULT-1:0]   stored1;
       reg [MUL_RESULT-1:0]   stored2;
       reg [MUL_RESULT-1:0]   stored3;
       reg [MUL_RESULT-1:0]   stored4;
       reg [MUL_RESULT-1:0]   stored5;
       reg [MUL_RESULT-1:0]   stored6;
       reg [MUL_RESULT-1:0]   stored7;
       reg [MUL_RESULT-1:0]   out1,out2;
       reg [MUL_RESULT-1:0]   add1,add2,add3,add4;
     
     always @ ( posedge clk or negedge rst_n )
     begin
    if ( !rst_n )
       begin
    
          stored0 <= 14'b0;
          stored1 <= 14'b0;
          stored2 <= 14'b0;
          stored3 <= 14'b0;
          stored4 <= 14'b0;
          stored5 <= 14'b0;
          stored6 <= 14'b0;
          out1<= 14'b0;
          out2<= 14'b0;
    
          add1 <= 14'b0;
    		  add2 <= 14'b0;
    		  add3 <= 14'b0;
    		  add4 <= 14'b0;
          
       
       end
    else
       begin           
         //注意,下面两句是没有延迟的,因为他们的右侧的mul_a,mul_b是输入信号
    
          stored0 <= mul_b[0] ? {8'b0,mul_a}       : 16'b0;
          stored1 <= mul_b[1] ? {7'b0,mul_a,1'b0}  : 16'b0;
          stored2 <= mul_b[2] ? {6'b0,mul_a,2'b0}  : 16'b0;
          stored3 <= mul_b[3] ? {5'b0,mul_a,3'b0}  : 16'b0;
          stored4 <= mul_b[4] ? {4'b0,mul_a,4'b0}  : 16'b0;
          stored5 <= mul_b[5] ? {3'b0,mul_a,5'b0}  : 16'b0;
          stored6 <= mul_b[6] ? {2'b0,mul_a,6'b0}  : 16'b0;
          stored7 <= mul_b[7] ? {1'b0,mul_a,7'b0}  : 16'b0;
          add1 <= stored1 + stored0;
          add2 <= stored3 + stored2;
          add3 <= stored5 + stored4;
          add4 <= stored6 + stored7;
          out1 <= add1 + add2;
          out2 <= add3 + add4;
          mul_out <= out1 + out2;
    
     end
    
     end
    
     endmodule
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

2、9位有符号乘法器(例化8位无符号乘法器)

复制代码
    module signed_mul_9bit(x, y, result,clk, rst_n);
    parameter in_width=9,
    result_width=2*in_width-1;
    
    input   clk,rst_n;
    input   [in_width-1:0] x, y;
    output  [result_width-1:0] result;
    wire    [result_width-1:0] result_reg;
    
    wire    [2*(in_width-1)-1:0] out;
      
    wire    [in_width-2:0] x_reg;
    wire    [in_width-2:0] y_reg;
    reg                    msb=0;
    reg                    msb_reg_0=0;
    reg                    msb_reg_1=0;
    reg                    msb_reg_2=0;
    assign   x_reg = (x[8]==0)?  x[7:0]  : ~x[7:0]+1'b1;
    assign   y_reg = (y[8]==0)?  y[7:0]  : ~y[7:0]+1'b1; 
    
    always @(posedge clk) begin
    
          msb_reg_0 <=x[8] ^ y[8];
          msb_reg_1<=msb_reg_0;
          msb_reg_2<=msb_reg_1;
          msb<=msb_reg_2;
    end
    
    
    un_signed_mul_8bit u1(x_reg, y_reg, out,clk, rst_n);
    
    assign result_reg = {msb,out[15:0]};
       
    assign result=(result_reg[16]==0)?result_reg:{result_reg[16],~result_reg[15:0]+1'b1};
    
    endmodule
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

由于这里之所以使msb被延迟3个时钟周期,是因为输出比输入也被延迟了3个时钟周期。因此,为了确保输出结果的符号正确无误,我们需要让msb与输出数据实现对齐。

3、仿真程序

复制代码
    `timescale 1ns / 1ps
    
    module tb_m2();
    reg   clk,rst_n;
    reg   [8:0] Ain,Bin;
    wire  [16:0] result;
    initial
    	begin
    		#1
    		Ain = 5;
    		Bin = 2;
    		clk = 0;
    		rst_n=0;
    		#3
    		rst_n=1;
    	end
    always #5 clk = ~clk;
    always @(posedge clk)
    	begin
    		#1
    		Ain = Ain - 2;
    		Bin = Bin + 1;
    	end
    signed_mul_9bit u1(Ain,Bin,result,clk,rst_n);
    endmodule
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

4、仿真结果

在这里插入图片描述

全部评论 (0)

还没有任何评论哟~