ALU——调用加法乘法模块
只调用加法模块的仿真图:
(注:alu_control 为十六进制
001高位加载 src2的低16位加载到高16位上
002算数右移 src1算数右移 (高位补1)
004逻辑右移 src1逻辑右移 (逻辑右移直接补0)
008逻辑左移 src1逻辑左移
010异或 020或 040或非 080与
100 无符号比较 小于置位
200 有符号比较 小于置位
400 减法
800 加法
没有调用乘法器的ALU (下面那个调用了)
alu.v
`timescale 1ns / 1psmodule alu(input [11:0] alu_control, input [31:0] alu_src1, input [31:0] alu_src2,output [31:0] alu_result );reg [31:0] alu_result;wire alu_add; //加法wire alu_sub; //减法wire alu_slt; //有符号比较,小于置位wire alu_sltu; //无符号比较,小于置位wire alu_and; //按位与wire alu_nor; //按位或非wire alu_or; //按位或 wire alu_xor; //按位异或wire alu_sll; //逻辑左移wire alu_srl; //逻辑右移wire alu_sra; //算数右移wire alu_lui; //高位加载assign alu_mult = alu_control[11];assign alu_add = alu_control[11];assign alu_sub = alu_control[10];assign alu_slt = alu_control[ 9];assign alu_sltu = alu_control[ 8];assign alu_and = alu_control[ 7];assign alu_nor = alu_control[ 6];assign alu_or = alu_control[ 5];assign alu_xor = alu_control[ 4];assign alu_sll = alu_control[ 3];assign alu_srl = alu_control[ 2];assign alu_sra = alu_control[ 1];assign alu_lui = alu_control[ 0];wire [31:0] add_sub_result; //加减结果,减法用加法来实现wire [31:0] slt_result; //wire [31:0] sltu_result; //wire [31:0] and_result;wire [31:0] nor_result;wire [31:0] or_result;wire [31:0] xor_result;wire [31:0] sll_result;wire [31:0] srl_result;wire [31:0] sra_result; wire [31:0] lui_result;wire signed [31:0] temp_src1; //带符号数的临时变量assign temp_src1 = alu_src1; //方便后面对alu_src1进行算数右移assign and_result = alu_src1 & alu_src2; //按位与assign or_result = alu_src1 | alu_src2; //按位或assign nor_result = ~or_result; //或非assign xor_result = alu_src1 ^ alu_src2; //异或assign lui_result = {alu_src2[15:0], 16'd0}; //高位加载,第二个操作数的低十六位加载到高十六位上assign sll_result = alu_src1 << alu_src2; //逻辑左移assign srl_result = alu_src1 >> alu_src2; //逻辑右移assign slt_result = adder_result[31] ? 1'b1 : 1'b0; // 带符号数小于置位assign sltu_result = adder_cout ? 1'b0 : 1'b1; //无符号数小于置位assign sra_result = temp_src1 >>> alu_src2; //算数右移wire [31:0] adder_operand1;wire [31:0] adder_operand2;wire adder_cin ;wire [31:0] adder_result ;wire adder_cout ;assign adder_operand1 = alu_src1; assign adder_operand2 = alu_add ? alu_src2 : ~alu_src2; //默认进行减法,为slt和sltu服务assign adder_cin = ~alu_add; //巧妙到我都以为代码有bugadder adder_module( //调用加法模块.A(adder_operand1),.B(adder_operand2),.Cin (adder_cin ),.S (adder_result ),.Cout (adder_cout ));
assign add_sub_result = adder_result;always@(*)beginif(alu_add | alu_sub)alu_result <= add_sub_result;else if(alu_slt)alu_result <= slt_result;else if(alu_sltu)alu_result <= sltu_result;else if(alu_and)alu_result <= and_result;else if(alu_nor)alu_result <= nor_result;else if(alu_or)alu_result <= or_result;else if(alu_xor)alu_result <= xor_result;else if(alu_sll)alu_result <= sll_result;else if(alu_srl)alu_result <= srl_result;else if(alu_sra)alu_result <= sra_result;else if(alu_lui)alu_result <= lui_result;end
endmodule
testbench.v
`timescale 1ns / 1psmodule tb;// Inputsreg clk;reg [11:0] alu_control;reg [31:0] alu_src1;reg [31:0] alu_src2;// Outputswire [31:0] alu_result;// Instantiate the Unit Under Test (UUT)
//alu al(
// input [11:0] alu_control,
// input [31:0] alu_src1,
// input [31:0] alu_src2,
// output [31:0] alu_result
// );
alu alu_module(.alu_control(alu_control),.alu_src1 (alu_src1 ),.alu_src2 (alu_src2 ),.alu_result (alu_result ));initial begin// Initialize Inputsclk = 0;alu_control = 0;alu_src1 = 32'H10001111;alu_src2 = 32'H00000004;// Wait 100 ns for global reset to finish#100;alu_control = 12'b0000_0000_0001;#400;alu_control = 12'b0000_0000_0010;#500;alu_control = 12'b0000_0000_0100;#400;alu_control = 12'b0000_0000_1000;#500;alu_control = 12'b0000_0001_0000;#400;alu_control = 12'b0000_0010_0000;#500;alu_control = 12'b0000_0100_0000;#400;alu_control = 12'b0000_1000_0000;#400;alu_control = 12'b0001_0000_0000;#400;alu_control = 12'b0010_0000_0000;#400;alu_control = 12'b0100_0000_0000;#400;alu_control = 12'b1000_0000_0000;// Add stimulus hereendalways #5 clk = ~clk;
endmodule
alu_display.v
module alu_display(//时钟与复位信号input clk,input resetn, //后缀"n"代表低电平有效//拨码开关,用于选择输入数input [1:0] input_sel, //00:输入为控制信号(alu_control)//10:输入为源操作数1(alu_src1)//11:输入为源操作数2(alu_src2)//触摸屏相关接口,不需要更改output lcd_rst,output lcd_cs,output lcd_rs,output lcd_wr,output lcd_rd,inout[15:0] lcd_data_io,output lcd_bl_ctr,inout ct_int,inout ct_sda,output ct_scl,output ct_rstn);
//-----{调用ALU模块}beginreg [11:0] alu_control; // ALU控制信号reg [31:0] alu_src1; // ALU操作数1reg [31:0] alu_src2; // ALU操作数2wire [31:0] alu_result; // ALU结果alu alu_module(.alu_control(alu_control),.alu_src1 (alu_src1 ),.alu_src2 (alu_src2 ),.alu_result (alu_result ));
//-----{调用ALU模块}end//---------------------{调用触摸屏模块}begin--------------------//
//-----{实例化触摸屏}begin
//此小节不需要更改reg display_valid;reg [39:0] display_name;reg [31:0] display_value;wire [5 :0] display_number;wire input_valid;wire [31:0] input_value;lcd_module lcd_module(.clk (clk ), //10Mhz.resetn (resetn ),//调用触摸屏的接口.display_valid (display_valid ),.display_name (display_name ),.display_value (display_value ),.display_number (display_number),.input_valid (input_valid ),.input_value (input_value ),//lcd触摸屏相关接口,不需要更改.lcd_rst (lcd_rst ),.lcd_cs (lcd_cs ),.lcd_rs (lcd_rs ),.lcd_wr (lcd_wr ),.lcd_rd (lcd_rd ),.lcd_data_io (lcd_data_io ),.lcd_bl_ctr (lcd_bl_ctr ),.ct_int (ct_int ),.ct_sda (ct_sda ),.ct_scl (ct_scl ),.ct_rstn (ct_rstn ));
//-----{实例化触摸屏}end//-----{从触摸屏获取输入}begin
//根据实际需要输入的数修改此小节,
//建议对每一个数的输入,编写单独一个always块//当input_sel为00时,表示输入数控制信号,即alu_controlalways @(posedge clk)beginif (!resetn)beginalu_control <= 12'd0;endelse if (input_valid && input_sel==2'b00)beginalu_control <= input_value[11:0];endend//当input_sel为10时,表示输入数为源操作数1,即alu_src1always @(posedge clk)beginif (!resetn)beginalu_src1 <= 32'd0;endelse if (input_valid && input_sel==2'b10)beginalu_src1 <= input_value;endend//当input_sel为11时,表示输入数为源操作数2,即alu_src2always @(posedge clk)beginif (!resetn)beginalu_src2 <= 32'd0;endelse if (input_valid && input_sel==2'b11)beginalu_src2 <= input_value;endend
//-----{从触摸屏获取输入}end//-----{输出到触摸屏显示}begin
//根据需要显示的数修改此小节,
//触摸屏上共有44块显示区域,可显示44组32位数据
//44块显示区域从1开始编号,编号为1~44,always @(posedge clk)begincase(display_number)6'd1 :begindisplay_valid <= 1'b1;display_name <= "SRC_1";display_value <= alu_src1;end6'd2 :begindisplay_valid <= 1'b1;display_name <= "SRC_2";display_value <= alu_src2;end6'd3 :begindisplay_valid <= 1'b1;display_name <= "CONTR";display_value <={20'd0, alu_control};end6'd4 :begindisplay_valid <= 1'b1;display_name <= "RESUL";display_value <= alu_result;enddefault :begindisplay_valid <= 1'b0;display_name <= 40'd0;display_value <= 32'd0;endendcaseend
//-----{输出到触摸屏显示}end
//----------------------{调用触摸屏模块}end---------------------//
endmodule
调用乘法器的ALU(代码扔到末尾)
这里结果我不知道怎么只显示希望的结果(出现了0,这个是个过程值,当时做乘法器的时候,看仿真的时候是配合着mult_end信号看的,我也不会把这个end信号调出来)
slt sltu没看明白:(手册里有以后看 挖坑)
小于置位指令(SLT,SLTI,SLTU,SLTIU)比较两个操作数然后设置目的寄存器,
如果小于就设置为1,否则就将目的寄存器设置为0。
alu.v
`timescale 1ns / 1psmodule alu(input clk,input [12:0] alu_control, input [31:0] alu_src1, input [31:0] alu_src2,output [31:0] alu_result );reg [31:0] alu_result;wire alu_mul;//乘法wire alu_add; //加法wire alu_sub; //减法wire alu_slt; //有符号比较,小于置位wire alu_sltu; //无符号比较,小于置位wire alu_and; //按位与wire alu_nor; //按位或非wire alu_or; //按位或 wire alu_xor; //按位异或wire alu_sll; //逻辑左移wire alu_srl; //逻辑右移wire alu_sra; //算数右移wire alu_lui; //高位加载assign alu_mul = alu_control[12];assign alu_add = alu_control[11];assign alu_sub = alu_control[10];assign alu_slt = alu_control[ 9];assign alu_sltu = alu_control[ 8];assign alu_and = alu_control[ 7];assign alu_nor = alu_control[ 6];assign alu_or = alu_control[ 5];assign alu_xor = alu_control[ 4];assign alu_sll = alu_control[ 3];assign alu_srl = alu_control[ 2];assign alu_sra = alu_control[ 1];assign alu_lui = alu_control[ 0];wire [31:0] mul_result;wire [31:0] add_sub_result; //加减结果,减法用加法来实现wire [31:0] slt_result; wire [31:0] sltu_result; wire [31:0] and_result;wire [31:0] nor_result;wire [31:0] or_result;wire [31:0] xor_result;wire [31:0] sll_result;wire [31:0] srl_result;wire [31:0] sra_result; wire [31:0] lui_result;wire signed [31:0] temp_src1; //带符号数的临时变量assign temp_src1 = alu_src1; //方便后面对alu_src1进行算数右移assign and_result = alu_src1 & alu_src2; //按位与assign or_result = alu_src1 | alu_src2; //按位或assign nor_result = ~or_result; //或非assign xor_result = alu_src1 ^ alu_src2; //异或assign lui_result = {alu_src2[15:0], 16'd0}; //高位加载,第二个操作数的低十六位加载到高十六位上assign sll_result = alu_src1 << alu_src2; //逻辑左移assign srl_result = alu_src1 >> alu_src2; //逻辑右移assign slt_result = adder_result[31] ? 1'b1 : 1'b0; // 带符号数小于置位assign sltu_result = adder_cout ? 1'b0 : 1'b1; //无符号数小于置位assign sra_result = temp_src1 >>> alu_src2; //算数右移wire [31:0] adder_operand1;wire [31:0] adder_operand2;wire adder_cin ;wire [31:0] adder_result ;wire adder_cout ;assign adder_operand1 = alu_src1; assign adder_operand2 = alu_add ? alu_src2 : ~alu_src2; //默认进行减法,为slt和sltu服务assign adder_cin = ~alu_add; //巧妙到我都以为代码有bugadder adder_module( //调用加法模块.A(adder_operand1),.B(adder_operand2),.Cin (adder_cin ),.S (adder_result ),.Cout (adder_cout ));
assign add_sub_result = adder_result;wire clk; // 时钟// wire mult_begin; // 乘法开始信号wire [31:0] mult_op1; // 乘法源操作数1wire [31:0] mult_op2; // 乘法源操作数2wire [63:0] product; // 乘积wire mult_end ; // 乘法结束信号assign mult_op1 = alu_src1; assign mult_op2 =alu_src2;assign mult_begin=1;multiply multiply_module//调用乘法模块 ( .clk(clk),.mult_begin(mult_begin),.mult_op1 (alu_src1 ),.mult_op2 (alu_src2 ),.product ( product ),.mult_end ());assign mul_result =product ;always@(*)beginif(alu_add | alu_sub)alu_result <= add_sub_result;else if(alu_mul)alu_result =mul_result;else if(alu_slt)alu_result <= slt_result;else if(alu_sltu)alu_result <= sltu_result;else if(alu_and)alu_result <= and_result;else if(alu_nor)alu_result <= nor_result;else if(alu_or)alu_result <= or_result;else if(alu_xor)alu_result <= xor_result;else if(alu_sll)alu_result <= sll_result;else if(alu_srl)alu_result <= srl_result;else if(alu_sra)alu_result <= sra_result;else if(alu_lui)alu_result <= lui_result;end
endmodule
alu.display (就改了个信号数组的范围)
module alu_display(//时钟与复位信号input clk,input resetn, //后缀"n"代表低电平有效//拨码开关,用于选择输入数input [1:0] input_sel, //00:输入为控制信号(alu_control)//10:输入为源操作数1(alu_src1)//11:输入为源操作数2(alu_src2)//触摸屏相关接口,不需要更改output lcd_rst,output lcd_cs,output lcd_rs,output lcd_wr,output lcd_rd,inout[15:0] lcd_data_io,output lcd_bl_ctr,inout ct_int,inout ct_sda,output ct_scl,output ct_rstn);
//-----{调用ALU模块}beginreg [12:0] alu_control; // ALU控制信号reg [31:0] alu_src1; // ALU操作数1reg [31:0] alu_src2; // ALU操作数2wire [31:0] alu_result; // ALU结果alu alu_module(.alu_control(alu_control),.alu_src1 (alu_src1 ),.alu_src2 (alu_src2 ),.alu_result (alu_result ));
//-----{调用ALU模块}end//---------------------{调用触摸屏模块}begin--------------------//
//-----{实例化触摸屏}begin
//此小节不需要更改reg display_valid;reg [39:0] display_name;reg [31:0] display_value;wire [5 :0] display_number;wire input_valid;wire [31:0] input_value;lcd_module lcd_module(.clk (clk ), //10Mhz.resetn (resetn ),//调用触摸屏的接口.display_valid (display_valid ),.display_name (display_name ),.display_value (display_value ),.display_number (display_number),.input_valid (input_valid ),.input_value (input_value ),//lcd触摸屏相关接口,不需要更改.lcd_rst (lcd_rst ),.lcd_cs (lcd_cs ),.lcd_rs (lcd_rs ),.lcd_wr (lcd_wr ),.lcd_rd (lcd_rd ),.lcd_data_io (lcd_data_io ),.lcd_bl_ctr (lcd_bl_ctr ),.ct_int (ct_int ),.ct_sda (ct_sda ),.ct_scl (ct_scl ),.ct_rstn (ct_rstn ));
//-----{实例化触摸屏}end//-----{从触摸屏获取输入}begin
//根据实际需要输入的数修改此小节,
//建议对每一个数的输入,编写单独一个always块//当input_sel为00时,表示输入数控制信号,即alu_controlalways @(posedge clk)beginif (!resetn)beginalu_control <= 12'd0;endelse if (input_valid && input_sel==2'b00)beginalu_control <= input_value[11:0];endend//当input_sel为10时,表示输入数为源操作数1,即alu_src1always @(posedge clk)beginif (!resetn)beginalu_src1 <= 32'd0;endelse if (input_valid && input_sel==2'b10)beginalu_src1 <= input_value;endend//当input_sel为11时,表示输入数为源操作数2,即alu_src2always @(posedge clk)beginif (!resetn)beginalu_src2 <= 32'd0;endelse if (input_valid && input_sel==2'b11)beginalu_src2 <= input_value;endend
//-----{从触摸屏获取输入}end//-----{输出到触摸屏显示}begin
//根据需要显示的数修改此小节,
//触摸屏上共有44块显示区域,可显示44组32位数据
//44块显示区域从1开始编号,编号为1~44,always @(posedge clk)begincase(display_number)6'd1 :begindisplay_valid <= 1'b1;display_name <= "SRC_1";display_value <= alu_src1;end6'd2 :begindisplay_valid <= 1'b1;display_name <= "SRC_2";display_value <= alu_src2;end6'd3 :begindisplay_valid <= 1'b1;display_name <= "CONTR";display_value <={20'd0, alu_control};end6'd4 :begindisplay_valid <= 1'b1;display_name <= "RESUL";display_value <= alu_result;enddefault :begindisplay_valid <= 1'b0;display_name <= 40'd0;display_value <= 32'd0;endendcaseend
//-----{输出到触摸屏显示}end
//----------------------{调用触摸屏模块}end---------------------//
endmodule
testbench.v
`timescale 1ns / 1psmodule tb;// Inputsreg clk;reg [12:0] alu_control;reg [31:0] alu_src1;reg [31:0] alu_src2;// Outputswire [31:0] alu_result;// Instantiate the Unit Under Test (UUT)
//alu al(
// input [11:0] alu_control,
// input [31:0] alu_src1,
// input [31:0] alu_src2,
// output [31:0] alu_result
// );
alu alu_module(.clk(clk),.alu_control(alu_control),.alu_src1 (alu_src1 ),.alu_src2 (alu_src2 ),.alu_result (alu_result ));initial begin// Initialize Inputsclk = 0;alu_control = 0;alu_src1 = 32'H10001111;alu_src2 = 32'H00000004;// Wait 100 ns for global reset to finish#100;alu_control = 13'b00000_0000_0001;#400;alu_control = 13'b00000_0000_0010;#500;alu_control = 13'b00000_0000_0100;#400;alu_control = 13'b00000_0000_1000;#500;alu_control = 13'b00000_0001_0000;#400;alu_control = 13'b00000_0010_0000;#500;alu_control = 13'b00000_0100_0000;#400;alu_control = 13'b00000_1000_0000;#400;alu_control = 13'b00001_0000_0000;#400;alu_control = 13'b00010_0000_0000;#400;alu_control = 13'b00100_0000_0000;#400;alu_control = 13'b01000_0000_0000;#400;alu_control = 13'b10000_0000_0000;// Add stimulus hereendalways #5 clk = ~clk;
endmodule
multiply.v 和 add.v 之前的记录里有。
一般认为“>>>”在Verilog里是算术右移指令,但实操中发现它有时会在右移时仍然补零,即使符号位为1。这是因为“>>>”会先判断这个操作数是否有符号数。如果是无符号数,则补零,是有符号数,才会补符号位。而一般使用的reg operand; 这种变量定义法默认所定义的变量为无符号数,因此只补零。
Result = operandB >>> operandA; //错误示范
解决办法是利用Verilog的内置函数$signed(),将被移位的操作数转为有符号数类型。
Result = ($signed(operandB)) >>> operandA; //更正后
ALU——调用加法乘法模块相关推荐
- java 乘法_java大数加法乘法
java大数加法乘法 前言 正常情况下我们调用加法乘法使用符号就行了,但是如果超出限制了,那就只能调用BigDecimal里面的函数了,但是有的时候oj考察的就是希望自己实现,所以就可以采用别的方法. ...
- Python 3.X 调用多线程C模块,并在C模块中回调python函数的示例
由于最近在做一个C++面向Python的API封装项目,因此需要用到C扩展Python的相关知识.在此进行简要的总结. 此篇示例分为三部分.第一部分展示了如何用C在Windows中进行多线程编程:第二 ...
- SpringCloud实现一个模块调用另一个模块的服务
SpringCloud实现一个模块调用另一个模块的服务 简介 基于SpringCloud框架搭建的项目,不同模块之间是无法调用各自的服务的,但是经常我们需要使用这样的模式去开发,那么如何实现不同模块之 ...
- Python笔记(二)——python调用C/C++模块
前一篇讲了简单的C/C++调用Python脚本模块(.py).既然是用于诸多游戏程序的脚本语言,那肯定是缺不了互调(礼尚往来).因此,本篇讲一个简单的python调用C/C++写的DLL模块,对Pyt ...
- react-native调用Android原生模块
今天学习了一下在react-native中调用原生安卓模块的使用,发现很多网上的文章都是直接照抄的文档,这样会有一些坑,导致最后无法运行或者成功调用,所以写下这个博客来分享,同时也记录一下学习过程,内 ...
- Lua脚本如何调用C/C++模块,Windows以及Linux版本演示
Windows下 我用的是vs2019,由于Windows下不像Linux可以直接直接安装lua程序直接运行lua代码,所以这里我们演示的是,通过c/c++调用lua脚本,lua脚本再调用其他的C/C ...
- Python + opencv 调用工业相机对模块进行拍照扫描并分析内容(一)
** Python + opencv 调用工业相机对模块进行拍照扫描并分析内容(一) ** 利用厂家提供的文档和资料,安装好SDK,将dll文件放入系统位置: 1)Windows 将 JHCap2.d ...
- 计算机用加法乘法实现除法运算的数学原理
数学原理:迭代序列 本篇只讨论加法乘法实现除法的数学原理,并不涉及数据结构. 设已知 c > 0 ,任取 数学归纳法我们有 0 < <1 , 0 < ...
- 计算机底层加法/乘法实现
计算机底层加法/乘法实现 存储方式 原理 加法 乘法 除法 代码实现 加法 乘法 存储方式 计算机底层中存放数字使用二进制形式,负数使用补码(反码+1)来存放. 原理 加法 两个二进制的相加结果是用一 ...
最新文章
- 构建一个分布式操作系统的简单方案—答陈硕的“分布式系统中的进程标识”一文...
- .net中的认证和授权(学习笔记)
- 被围绕的区域(dfs)
- LeetCode 336. 回文对(哈希map/Trie树)
- php生成静态html分页实现方法
- Flutter之_slot 插槽属性详解
- Qt QTableView样式设置
- python写入文件出现空行
- 实时单目物体SLAM Real-time Monocular Object SLAM
- java数组的实例化
- Win10使用说明 - 任务栏设置、触摸板手势和使用偏好
- KUKA机器人资料下载
- Windows 和 Linux 的免费媒体播放器 - SMPlayer
- Excel必知必会——count,counta,countif,countifs
- ArcGIS教程:太阳辐射建模
- 计算机时间怎么改24小时模式,怎么修改电脑的时间为24小时制啊?
- NVIDIA GeForce Experience无法登录
- 电脑开机停在主板logo画面
- oracle linux6 u盘安装,用U盘安装Oracle Linux 6.2
- 138+134 新手寻星,三分钟搞定,呵呵,我明天才!!