http://group.ednchina.com/1375/21236.aspx
实验五、16位乘法器芯片设计
    这个实验不需要上板子调试,只是纯粹的做一些verilog代码方面的设计,希望对大家学习有所帮助。
工程源码:  
乘法器是众多数字系统中的基本模块。从原理上说它属于组合逻辑范畴;但从工程实际设计上来说,它往往会利用时序逻辑设计的方法来实现,属于时序逻辑范畴。
通过这个实验使大家能够掌握利用FPGA/CPLD设计乘法器的思想,并且能够将我们设计的乘法器应用到实际工程中。下面我们分别列举了十进制乘法运算和二进制乘法运算的例子。下面这种计算乘法的方式是大家非常熟悉的:乘积项与乘数相应位对齐(即将乘积项左移),加法运算的数据宽度与被乘数的数据位宽相同。
下面例子中的被乘数和乘数都是无符号的整数,对于有符号数的乘法,可以将符号与数据绝对值分开处理,即绝对值相乘,符号异或。乘法器的设计方法有两种:组合逻辑设计方法和时序逻辑设计方法。采用组合逻辑设计方法,电路事先将所有的乘积项全部计算出来,最后加法运算。采用时序逻辑设计方法,电路将部分已经得到的乘积结果右移,然后与乘积项相加并保存和值,反复迭代上述步骤直到计算出最终乘积。
在本次实验中我们就利用时序逻辑设计方法来设计一个16位乘法器,既然是利用时序逻辑设计方法那么我们就得利用时钟信号控制乘法器运算,那么这样用时序逻辑设计方法与用组合逻辑设计方法比较,它有什么好处呢?利用时序逻辑设计方法可以使整体设计具备流水线结构的特征,能适用在实际工程设计中。
IO口定义:
clk:芯片的时钟信号。
rst_n:低电平复位、清零信号。定义为0表示芯片复位;定义为1表示复位信号无效。
start: 芯片使能信号。定义为0表示信号无效;定义为1表示芯片读入输入管脚得乘数和被乘数,并将乘积复位清零。
ain:输入a(被乘数),其数据位宽为16bit.
bin:输入b(乘数),其数据位宽为16bit.
yout:乘积输出,其数据位宽为32bit.
done:芯片输出标志信号。定义为1表示乘法运算完成,yout端口的数据稳定,得到最终的乘积;定义为0表示乘法运算未完成,yout端口的数据不稳定。
数据吞吐量的计算:
数据吞吐量使指芯片在一定时钟频率条件下所能处理的有效数据量。
假设本实验设计的芯片时钟频率可达300MHz,那么该芯片的数据吞吐量是多少呢?
由于芯片完成一次乘法运算需要1个以上的时钟周期,因此,即使芯片采用300MHz的时钟频率,它每秒钟所能处理的有效数据吞吐量也一定小于300M。对于16位乘法器而言,ain和bin均为0xFFFF时,芯片的运算量最大,计算所需的时间也最长,这种情况才能作为我们计算数据吞吐量的依据。
假设芯片在200MHz的条件下ain和bin均为0xFFFF时需要16个时钟周期才能得到乘法结果,那么芯片在200MHz的条件下的数据吞吐量就为:200M/16=12.5M 。
仿真波形:
完成一个256×16928=4333568的运算,约16个时钟周期以后done置高,表示运算结束,结果输出。
 
16bit X 16bit无符号数乘法程序:      (说明:start信号置位期间,ain和bin必须保持稳定,如果需要再次进行一次新的运算,则start信号必须重新来一个上升沿。done输出高电平以后需要软件将其重新拉低。)      待解决问题:不知道output口是否能由外部电平拉高或者拉低? module mux16(
                     clk,rst_n,
                     start,ain,bin,yout,done
              );
             
       input clk;        //芯片的时钟信号。
       input rst_n;     //低电平复位、清零信号。定义为0表示芯片复位;定义为1表示复位信号无效。
       input start;     //芯片使能信号。定义为0表示信号无效;定义为1表示芯片读入输入管脚得乘数和被乘数,并将乘积复位清零。
       input[15:0] ain;      //输入a(被乘数),其数据位宽为16bit.
       input[15:0] bin;      //输入b(乘数),其数据位宽为16bit.
       output[31:0] yout;  //乘积输出,其数据位宽为32bit.
       output done;          //芯片输出标志信号。定义为1表示乘法运算完成.
       reg[15:0] areg;       //乘数a寄存器
       reg[15:0] breg;       //乘数b寄存器
       reg[31:0] yout_r;    //乘积寄存器
       reg done_r;
       reg[4:0] i;              //移位次数寄存器
       always@(posedge clk)
       begin
              if(!rst_n) begin
                            areg <= 16'h0000;
                            breg <= 16'h0000;
                            done_r <= 1'b0;
                            yout_r <= 32'h00000000;
                            i <= 5'd0;
                     end
              else if(start)           //启动运算
                     begin
                    
                            if(i < 5'd21) i <= i+1'b1;
                            if(i == 5'd0) begin  //锁存乘数、被乘数
                                          areg <= ain;
                                          breg <= bin;
                                   end
                            else if(i > 5'd0 && i < 5'd16) begin
                                                 if(areg[i-1]) yout_r = {1'b0,yout[30:15]+breg,yout_r[14:1]};    //累加并移位
                                                 else yout_r <= yout_r>>1;     //移位不累加
                                          end
                            else if(i == 5'd16 && areg[15]) yout_r[31:16] <= yout_r[31:16]+breg;    //累加不移位
                            else if(i == 5'd18) done_r <= 1'b1;       //乘完成标志位置位
                            else if(i == 5'd20) done_r <= 1'b0;      //乘完成标志位清除
                     end
               else i <= 5'd0;
       end
      
       assign done = done_r;
       assign yout = yout_r;
endmodule16bit×16bit有符合数乘法程序: module mux_16bit_sign(clk,reset,start,ain,bin,yout,done);     input clk;     input reset;     input start;     input[15:0] ain;     input[15:0] bin;     output[31:0] yout;     output done;     reg[15:0] areg;     reg[15:0] breg;     reg[31:0] yout;     reg done;     integer i;     initial begin         done <= 0;i=0;         yout = 32'h00000000;         areg = 16'h0000;breg = 16'h0000;     end     always@(posedge clk)     begin         if(!reset) begin areg = 16'h0000;breg = 16'h0000;yout = 32'h00000000;i=0;end         else if(start && (!done))             begin                 if(ain[15]) areg = ~ain+1;                 else areg = ain;                 if(bin[15]) breg = ~bin+1;                 else breg = bin;                 if(i==0) yout = 32'h00000000;                 if( (i<16) i="="16)" yout =" ~(yout-1);end" i="0;" i="i" yout="yout">> 1;end             end          else i="0";     end endmodule
以下是采用组合逻辑电路设计的16位乘法器综合结果:(显然的采用了很多的寄存器和加法器进行运算)
 
程序:
module mux(clk,rst_n,en,a,b_in,rdy,mux_out);
input clk;//主时钟信号
input rst_n;//复位信号,低电平有效
input en;//输入使能信号,高电平有效
input[15:0] a,b_in;//两个16位的输入信号
output rdy;//乘法结果输出有效信号,高电平有效
output[31:0] mux_out;//乘法输出结果
reg rdy;
//reg[31:0] mux_out;
reg[15:0] mux_reg0 = 16'd0;
reg[16:0] mux_reg1 = 17'd0;
reg[17:0] mux_reg2 = 18'd0;
reg[18:0] mux_reg3 = 19'd0;
reg[19:0] mux_reg4 = 20'd0;
reg[20:0] mux_reg5 = 21'd0;
reg[21:0] mux_reg6 = 22'd0;
reg[22:0] mux_reg7 = 23'd0;
reg[23:0] mux_reg8 = 24'd0;
reg[24:0] mux_reg9 = 25'd0;
reg[25:0] mux_reg10 = 26'd0;
reg[26:0] mux_reg11 = 27'd0;
reg[27:0] mux_reg12 = 28'd0;
reg[28:0] mux_reg13 = 29'd0;
reg[29:0] mux_reg14 = 30'd0;
reg[30:0] mux_reg15 = 31'd0;
reg[31:0] mux_reg16 = 32'd0;
integer i;
always@(rst_n or a or b_in or en)
begin
       if(!rst_n)begin rdy <= 1'b0;end
       else if(en)
       begin
              if(a[0]) mux_reg0 <= b_in; else mux_reg0 <= 16'd0;
              if(a[1]) mux_reg1 <= {b_in,mux_reg16[0]}; else mux_reg1 <= 17'd0;
              if(a[2]) mux_reg2 <= {b_in,mux_reg16[1:0]}; else mux_reg2 <= 18'd0;
              if(a[3]) mux_reg3 <= {b_in,mux_reg16[2:0]}; else mux_reg3 <= 19'd0;
              if(a[4]) mux_reg4 <= {b_in,mux_reg16[3:0]}; else mux_reg4 <= 20'd0;
              if(a[5]) mux_reg5 <= {b_in,mux_reg16[4:0]}; else mux_reg5 <= 21'd0;         
              if(a[6]) mux_reg6 <= {b_in,mux_reg16[5:0]}; else mux_reg6 <= 22'd0;
              if(a[7]) mux_reg7 <= {b_in,mux_reg16[6:0]}; else mux_reg7 <= 23'd0;
              if(a[8]) mux_reg8 <= {b_in,mux_reg16[7:0]}; else mux_reg8 <= 24'd0;
              if(a[9]) mux_reg9 <= {b_in,mux_reg16[8:0]}; else mux_reg9 <= 25'd0;
              if(a[10]) mux_reg10 <= {b_in,mux_reg16[9:0]}; else mux_reg10 <= 26'd0;   
              if(a[11]) mux_reg11 <= {b_in,mux_reg16[10:0]}; else mux_reg11 <= 27'd0;
              if(a[12]) mux_reg12 <= {b_in,mux_reg16[11:0]}; else mux_reg12 <= 28'd0;
              if(a[13]) mux_reg13 <= {b_in,mux_reg16[12:0]}; else mux_reg13 <= 29'd0;  
              if(a[14]) mux_reg14 <= {b_in,mux_reg16[13:0]}; else mux_reg14 <= 30'd0;
              if(a[15]) mux_reg15 <= {b_in,mux_reg16[14:0]}; else mux_reg15 <= 31'd0;                                                          
       end
       else begin rdy <= 1'b0;end
end
assign mux_out = mux_reg0+mux_reg1+mux_reg2+mux_reg3+mux_reg4+mux_reg5+mux_reg6+mux_reg7+mux_reg8+mux_reg9+mux_reg10+mux_reg11+mux_reg12+mux_reg13+mux_reg14+mux_reg15;
endmodule
没有评论:
发表评论