计算机组成原理实验 - 实验四:算数逻辑单元设计

实验内容

请使用文本输入方式(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。

RTL