计算机组成原理实验 - 实验四:算数逻辑单元设计
实验内容
请使用文本输入方式(Verilog HDL)设计一个8位算术逻辑单元,包括控制信号与相关功能,具体如表2所示。假设暂存器A、B中的操作数均为8位补码,包含一位符号位,并使用双符号位补码进行算术加法运算,需要判断运算结果是否溢出,考虑低位进位输入Cin。如果运算结果溢出,则需要将溢出标志位Overflow置为1,否则置为0。在逻辑运算时,Overflow均置为0。对于算术右移操作,需要按照补码的算术右移规则执行。
控制信号 s2 s1 s0 | 实现功能 |
---|---|
000 | F清零 |
001 | A与B逻辑乘(&) |
010 | A与B逻辑加(|) |
011 | A与B逻辑异或(^) |
100 | A与B算数加 |
101 | A逻辑左移一位 |
110 | A逻辑右移一位 |
111 | A算数右移一位 |
将8位ALU的运算结果输出到七位数码管,Overflow绑定到LED灯
Sel用于选择数据写入啷个暂存器,Wt用于控制是否读入数据。本文使用矩阵键盘输入A和B。
实验代码
顶层设计 exp_4
module exp_4(
input clk,
input sel,
input wt,
input clr,
input [3:0] KEY_R,
output [3:0] KEY_C,
input [2:0] s,
input cin,
output overflow,
output [7:0] LED_seg,
output [2:0] LED_sel,
output [7:0] A,
output [7:0] B,
output [7:0] F,
output [15:0] indata,
output [3:0] num,
output [31:0] N
);
keymodule (clk,KEY_R,clr,KEY_C,indata); //键盘输入
midware (clk,indata,sel,wt,A,B);
ALU (clk,s,cin,A,B,overflow,F);
assign N = {A,B,8'h0,F};
segment_displays(clk,N,LED_seg,LED_sel,num);
endmodule
矩阵键盘 keymodule
注:COUNT_MAX用于防抖,当其小于10左右会出现抬起抖动读取,建议在实验时设置为100或1000;在仿真时设置为1。
module keymodule(
input clk,
input [3:0] KEY_C,
input clr,
output reg[3:0] KEY_R,
output reg[15:0] out
);
reg [1:0] cnt = 2'd0;
reg[4:0] num=5'd16;
reg[31:0] count_num=32'd0;
parameter COUNT_MAX = 32'd100; //没有按键按下的延迟时间
initial
begin
KEY_R = 4'b0111;
count_num = COUNT_MAX; //让第一次就能读取
end
//根据按钮的列扫描信号和行输入信号判断按钮是否被按下
always @(posedge clk,posedge clr)
begin
if(clr)
begin
cnt<=2'b0;
out<=16'h0000;
count_num<=COUNT_MAX; //让下一次就能读取
end
else
begin
if(KEY_C==4'b1111)
begin
//num = 5'd16;
cnt = cnt + 1'b1;
case (cnt)
2'b00: KEY_R <= 4'b1110;
2'b01: KEY_R <= 4'b1101;
2'b10: KEY_R <= 4'b1011;
2'b11: KEY_R <= 4'b0111;
endcase
//计数分频防止位移过快
if(count_num < COUNT_MAX)
count_num = count_num + 1'b1;
end
else
begin
case ({KEY_R, KEY_C})
8'b1011_1110: num = 5'd0;
8'b0111_0111: num = 5'd1;
8'b1011_0111: num = 5'd2;
8'b1101_0111: num = 5'd3;
8'b0111_1011: num = 5'd4;
8'b1011_1011: num = 5'd5;
8'b1101_1011: num = 5'd6;
8'b0111_1101: num = 5'd7;
8'b1011_1101: num = 5'd8;
8'b1101_1101: num = 5'd9;
8'b1110_0111: num = 5'd10;
8'b1110_1011: num = 5'd11;
8'b1110_1101: num = 5'd12;
8'b1110_1110: num = 5'd13;
8'b0111_1110: num = 5'd14;
8'b1101_1110: num = 5'd15;
endcase
if(count_num >= COUNT_MAX) //没有按键按下的空闲时间够长(防抖)
begin
count_num = 32'b0;
//移位
out=out<<4;
out[3:0] = num[3:0];
end
end //end KER_R!=4'b1111
end //end if(clr) else
end //end always
endmodule
暂存器 midware
module midware(
input clk,
input [15:0]in,
input sel,
input wt,
output reg [7:0] X,
output reg [7:0] Y
);
always @(posedge clk)
begin
if(wt)
if(sel)
X = in[7:0];
else
Y = in[7:0];
end
endmodule
数码管输出 segment_displays
module segment_displays(
input clk,
input [31:0] N,
output reg [7:0] seg,
output reg [2:0] sel,
output reg [3:0] num
);
always@(posedge clk)
begin
sel=sel+1;
case(sel)
3'b111:num=N[3:0];
3'b110:num=N[7:4];
3'b101:num=N[11:8];
3'b100:num=N[15:12];
3'b011:num=N[19:16];
3'b010:num=N[23:20];
3'b001:num=N[27:24];
3'b000:num=N[31:28];
endcase
end
always@(num)
begin
case(num)
4'b0000:seg=8'b00111111; //"0"
4'b0001:seg=8'b00000110; //"1"
4'b0010:seg=8'b01011011; //"2"
4'b0011:seg=8'b01001111; //"3”
4'b0100:seg=8'b01100110; //"4"
4'b0101:seg=8'b01101101; //"5"
4'b0110:seg=8'b01111101; //"6"
4'b0111:seg=8'b00000111; //"8"
4'b1000:seg=8'b01111111; //"8"
4'b1001:seg=8'b01101111; //"9"
4'b1010:seg=8'b01110111; //"A"
4'b1011:seg=8'b01111100; //"b"
4'b1100:seg=8'b00111001; //"c"
4'b1101:seg=8'b01011110; //"d"
4'b1110:seg=8'b01111001; //"E"
4'b1111:seg=8'b01110001; //"F"
default:seg=8'b00000000; //"dark"
endcase
end
endmodule
仿真波形
引脚配置
解释说明
注:有很多没有分配引脚的输出信号是为了方便在仿真的时候调试,可以把他们移除输出,改为wire。