16位乘法器学习笔记(Verilog语言源程序+仿真程序)

16位乘法器学习笔记(Verilog语言源程序+仿真程序)
16位乘法器学习笔记(Verilog语言源程序+仿真程序)

LCD1602显示源程序如下:

module lcd1602(input clk, //60M

input rst_n,

output lcd_p, //Backlight Source + lcd屏幕背光

output lcd_n, //Backlight Source -

output reg lcd_rs, //0:write order; 1:write data

output lcd_rw, //0:write data; 1:read data

output reg lcd_en, //negedge 在lcd_en下降沿需保证数据有效

output reg [7:0] lcd_data);

mux16

mul(.rst_n(rst_n),.clk(clk),.start(start),.ain(data0),.bin(data1),.yout(data2),.done(done));//端口名称关联

//--------------------lcd1602 order----------------------------

parameter Mode_Set = 8'h31, //功能设置,

Cursor_Set = 8'h0c, //光标设置

Address_Set = 8'h06, //输入模式设置

Clear_Set = 8'h01; //清屏设置

/****************************LCD1602 Display Data****************************/ wire [7:0] data_r0,data_r1,data_r2; //乘数、被乘数

wire [15:0]data0,data1; //结果显示

wire [31:0]data2;

wire [7:0] addr; //write address

wire start,done;

assign data_r0 = 8'h30 + data0[7:0] ; // 8'h30在LCD1602上显示值为0。

assign data_r1 = 8'h30 + data1[7:0] ;

assign data_r2 = 8'h30 + data2[7:0];

//-------------------address------------------

assign addr = 8'h80;

/****************************LCD1602 Driver****************************/

//-----------------------lcd1602 clk_en---------------------

reg [31:0] cnt;

reg lcd_clk_en;

always @(posedge clk or negedge rst_n)

begin

if(!rst_n)

begin

cnt <= 1'b0;

lcd_clk_en <= 1'b0;

end

else if(cnt == 32'h24999) //600us

begin

lcd_clk_en <= 1'b1;

cnt <= 1'b0;

end

else

begin

cnt <= cnt + 1'b1;

lcd_clk_en <= 1'b0;

end

end

//-----------------------lcd1602 display state-------------------------------------------

reg [6:0] state;

always@(posedge clk or negedge rst_n)

begin

if(!rst_n)

begin

state <= 1'b0;

lcd_rs <= 1'b0;

lcd_en <= 1'b0;

lcd_data <= 1'b0;

end

else if(lcd_clk_en)

begin

case(state)

//-------------------init_state---------------------

6'd0: begin

lcd_rs <= 1'b0;

lcd_en <= 1'b1;

lcd_data <= Mode_Set; //进入功能设置模式,“31”:数据总线8位,显示一行。6*7点阵/每字符

state <= state + 1'd1;

end

6'd1: begin

lcd_en <= 1'b0; //lcd_en变低电平,使led_en出现下降沿

state <= state + 1'd1;

end

6'd2: begin

lcd_rs <= 1'b0;

lcd_en <= 1'b1;

lcd_data <= Cursor_Set;//光标设置:光标右移一格,且AC值加1.

state <= state + 1'd1;

end

6'd3: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd4: begin

lcd_rs <= 1'b0;

lcd_en <= 1'b1;

lcd_data <= Address_Set;//模式设置:写入新数据后光标右移,AC自增1

state <= state + 1'd1;

end

6'd5: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd6: begin

lcd_rs <= 1'b0;

lcd_en <= 1'b1;

lcd_data <= Clear_Set;//清屏操作:0x01

state <= state + 1'd1;

end

6'd7: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

//--------------------work state--------------------

6'd8: begin

lcd_rs <= 1'b0;

lcd_en <= 1'b1;

lcd_data <= addr; //write addr

state <= state + 1'd1;

end

6'd9: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd10: begin

lcd_rs <= 1'b1;

lcd_en <= 1'b1;

lcd_data <= "R"; //write data

state <= state + 1'd1;

6'd11: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd12: begin

lcd_rs <= 1'b1;

lcd_en <= 1'b1;

lcd_data <= "E"; //write data

state <= state + 1'd1;

end

6'd13: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd14: begin

lcd_rs <= 1'b1;

lcd_en <= 1'b1;

lcd_data <= "S"; //write data

state <= state + 1'd1;

end

6'd15: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd16: begin

lcd_rs <= 1'b1;

lcd_en <= 1'b1;

lcd_data <= ":"; //write data

state <= state + 1'd1;

end

6'd17: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd18: begin

lcd_rs <= 1'b1;

lcd_en <= 1'b1;

lcd_data <= data_r1; //write data: tens digit

state <= state + 1'd1;

end

6'd19: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

6'd20: begin

lcd_rs <= 1'b1;

lcd_en <= 1'b1;

lcd_data <= "*";

state <= state + 1'd1;

end

6'd21: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd22: begin

lcd_rs <= 1'b1;

lcd_en <= 1'b1;

lcd_data <= data_r0; //write data: single digit

state <= state + 1'd1;

end

6'd23: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd24: begin

lcd_rs <= 1'b1;

lcd_en <= 1'b1;

lcd_data <= "="; //write data: single digit

state <= state + 1'd1;

end

6'd25: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd26: begin

lcd_rs <= 1'b1;

lcd_en <= 1'b1;

lcd_data <= data_r2; //write data: single digit

state <= state + 1'd1;

end

6'd27: begin

lcd_en <= 1'b0;

state <= state + 1'd1;

end

6'd28: begin

lcd_rs <= 1'b1;

lcd_en <= 1'b1;

lcd_data <= "."; //write data: single digit

state <= state + 1'd1;

end

6'd29: begin

lcd_en <= 1'b0;

state <= 6'd8;

end

default: state <= 6'bxxxxxx;

endcase

end

end

assign lcd_rw =1'b0; //only write

//------------------backlight driver----------------

assign lcd_n = 1'b0;

assign lcd_p = 1'b1;

Endmodule

16位乘法器源程序如下:

`timescale 1ns / 1ps

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 or negedge rst_n)

if(!rst_n) i <= 5'd0;

else if(start && i < 5'd17) i <= i+1'b1;

else if(!start) i <= 5'd0;

//------------------------------------------------

//乘法运算完成标志信号产生

always @(posedge clk or negedge rst_n)

if(!rst_n) done_r <= 1'b0;

else if(i == 5'd16) done_r <= 1'b1; //乘法运算完成标志

else if(i == 5'd17) done_r <= 1'b0; //标志位撤销

assign done = done_r;

//------------------------------------------------

//专用寄存器进行移位累加运算

always @(posedge clk or negedge rst_n) begin

if(!rst_n) begin

areg <= 16'h0003;

breg <= 16'h0003;

yout_r <= 32'h00000000;

end

else if(start) begin //启动运算

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;

//累加不移位

end

end

assign yout = yout_r;

endmodule

Modelsim仿真激励文件如下:

`timescale 1ns / 1ps

////////////////////////////////////////////////////////////////////////////////

// Company:

// Engineer:

//

// Create Date: 21:31:52 09/11/2008

// Design Name: test_top

// Module Name: vtf_test1.v

// Project Name: top_dram

// Target Device:

// Tool versions:

// Description:

//

// Verilog Test Fixture created by ISE for module: test_top

//

// Dependencies:

//

// Revision:

// Revision 0.01 - File Created

// Additional Comments:

//

////////////////////////////////////////////////////////////////////////////////

module vtf_test;

reg clk; //芯片的时钟信号。

reg rst_n; //低电平复位、清零信号。定义为0表示芯片复位;定义为1表示复位信号无效。reg start; //芯片使能信号。定义为0表示信号无效;定义为1表示芯片读入输入管脚得乘数和被乘数,并将乘积复位清零。

reg[15:0] ain; //输入a(被乘数),其数据位宽为16bit.

reg[15:0] bin; //输入b(乘数),其数据位宽为16bit.

wire[31:0] yout; //乘积输出,其数据位宽为32bit.

wire done; //芯片输出标志信号。定义为1表示乘法运算完成.

mux16 uut(

.clk(clk),

.rst_n(rst_n),

.start(start),

.ain(ain),

.bin(bin),

.yout(yout),

.done(done)

);

initial begin

clk = 0;

forever

#10 clk = ~clk; //??50MHZ???

end

initial begin

rst_n = 1'b0;

start = 1'b0;

ain = 16'd0;

bin = 16'd0;

#1000;

rst_n = 1'b1; //上电后1us复位信号

#1000;

ain = 16'd89;

bin = 16'd33;

#100;

start = 1'b1;

#4500;

start = 1'b0;

#100;

ain = 16'd75;

bin = 16'd62;

#100;

start = 1'b1;

#4500;

start = 1'b0;

#1000_000;

$stop;

end

endmodule

注:上述程序只是提供大概思路,请根据任务具体要求修改程序!

说明如下:

1、熟悉吞吐量概念

2、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;//累加不移位

对于if(areg[i-1]) yout_r = {1'b0,yout[30:15]+breg,yout_r[14:1]};此句说明如下:

(1)、二进制中16位加上16位结果为17位

(2)、areg[0]为1时,第一次只是加并不右移,后面areg[i-1]再次为1时执行累加并右移命令。右移实现通过{}拼接强制最高位(即第32位)为0实现的。

(3)、else if(i == 5'd16 && areg[15])

yout_r[31:16] <= yout_r[31:16]+breg;//累加不移位

对于此语句当areg[15]即最高位为1且i==16时只进行累加,再次应注意最高位(即第32位)的变化。

3、第2条的思想是基于如下二进制算法实现的:

1101

X 1011

1101

1101

0000

1101

100 01 011

4、尝试结果在LCD1602上面显示出来:

(1)assign data_r2 = 8'h30 + data2[7:0];此语句之所以加上8’h30 是因为8’h30在lcd显示时存放的是0的地址。

(2)问题:现在lcd显示屏只能显示八个字符,暂时不知道为什么?另一个问题就是:此lcd显示两行的时候字符会变暗,显示一行就很正常!!!

只能显示八个的原因是:硬件问题,lcd1602出问题了!(坑了)5、16位乘法器仿真图如下:

从上图中能看到start变为1后的第一个周期内yout为0,从下面一个周期开始yout开始输出值,且移位14次即到第15个周期,一直到第16个时钟周期时,yout输出了最终结果值,done也由0变为了1。

相关主题
相关文档
最新文档