计算机组成原理实验 - 实验五:CPU寄存器组的设计
实验内容
实验要求:用VDH语言设计CPU寄存器组,其包括4个8位通用寄存器(R0~R3)和一个8位专用寄存器PC, R0-R3&PC 操作方式见下表格,之后要将PC和R0-R3(其中一个)输出并用4个数码管显示。 R0-R3:
| 寄存器 | 控制信号 RA1 RA0 Wr Rd | 操作 | 
|---|---|---|
| R0 | 0 0 0 1 | 写入 | 
| R0 | 0 0 1 0 | 读出 | 
| R1 | 0 1 0 1 | 写入 | 
| R1 | 0 1 1 0 | 读出 | 
| R2 | 1 0 0 1 | 写入 | 
| R2 | 1 0 1 0 | 读出 | 
| R3 | 1 1 0 1 | 写入 | 
| R3 | 11 1 0 | 读出 | 
RA控制R0~R3的选择,Wr和Rd控制输入和输出。
PC:
| 寄存器 | 控制信号 M1 M0 | 操作 | 
|---|---|---|
| PC | 0 0 | 置数 | 
| PC | 0 1 | 加一计数 | 
| PC | 1 0 | 减一计数 | 
| PC | 1 1 | 保持 | 
reset为低电平有效的PC清零信号。
实验代码
顶层设计 exp5
module exp5(
	input clk,
	input [3:0] KEY_C,
	input clr, //K[0]
	output [3:0] KEY_R,
	output [7:0] seg,
	output [2:0] sel,
	
	input [1:0] M,RA, // k[6:7] K[2:3]
	input wr,rd,reset, // K[4] k[5] k[8]
	
	output [7:0] PC,res,
	
	output [7:0] R0,R1,R2,R3,
	output [15:0] key_out
);
keymodule(clk,KEY_C,clr,KEY_R,key_out);
CPU_register_group(M,RA,key_out[7:0],wr,rd,reset,clk,PC,res,R0,R1,R2,R3);
segment_displays( clk,{key_out,PC,res},seg,sel);
endmoduleCPU寄存器 CPU_register_group
注:l用于分频,clk_alt是分频时钟信号。仿真时设置clk_alt<=l[0],实验时clk_alt<=l[9],l[9]可能还是太快了,可以设置的更高。
module CPU_register_group(
	input [1:0] M,RA,
	input [7:0] D,
	input wr,rd,reset,
	input clk,
	output reg [7:0] PC,res,
	output reg[7:0] R0,R1,R2,R3
);
reg clk_alt;
reg [9:0] l;
always@(negedge clk) //分频
begin
	l<=l+1;
	clk_alt<=l[9];
end
always @(negedge clk_alt or negedge reset) //处理PC的值
begin
	if(!reset)
		PC = 0;
	else
	begin
		case(M)
		0:PC = D;
		1:PC=PC+1;
		2:PC=PC-1;
		default:PC = PC;
		endcase
	end
end
always @(negedge clk) //处理寄存器的值
begin
	case(RA)
	0:begin
		if(wr==0&&rd==1)
			R0=D;
		else if(wr==1&&rd==0)
			res=R0;
	end
	1:begin
		if(wr==0&&rd==1)
			R1=D;
		else if(wr==1&&rd==0)
			res=R1;
	end
	2:begin
		if(wr==0&&rd==1)
			R2=D;
		else if(wr==1&&rd==0)
			res=R2;
	end
	3:begin
		if(wr==0&&rd==1)
			R3=D;
		else if(wr==1&&rd==0)
			res=R3;
	end
	endcase
end
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
);
parameter COUNT_MAX = 32'd1000; //没有按键按下的延迟时间
reg [1:0] cnt = 2'd0;
reg [4:0] num =5'd16;
reg [31:0] count_num=COUNT_MAX;
initial
	KEY_R = 4'b1110;
//根据按钮的列扫描信号和行输入信号判断按钮是否被按下
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_C, KEY_R})
			 8'b_1110_1011: num = 5'd0;
			 8'b_0111_0111: num = 5'd1;
			 8'b_0111_1011: num = 5'd2;
			 8'b_0111_1101: num = 5'd3;
			 
			 8'b_1011_0111: num = 5'd4;
			 8'b_1011_1011: num = 5'd5;
			 8'b_1011_1101: num = 5'd6;
			 8'b_1101_0111: num = 5'd7;  
			 
			 8'b_1101_1011: num = 5'd8;
			 8'b_1101_1101: num = 5'd9;
			 8'b_0111_1110: num = 5'd10;
			 8'b_1011_1110: num = 5'd11;  
			 
			 8'b_1101_1110: num = 5'd12;
			 8'b_1110_1110: num = 5'd13;
			 8'b_1110_0111: num = 5'd14;
			 8'b_1110_1101: 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数码管输出 segment_displays
module segment_displays(
	input clk,
	input [31:0] N,
	output reg [7:0] seg,
	output reg [2:0] sel
);
	
reg [3:0] num;
always@(posedge clk)
begin
	sel=sel+1;
	case(sel)
		3'b000:num=N[31:28];
		3'b001:num=N[27:24];
		3'b010:num=N[23:20];
		3'b011:num=N[19:16];
		3'b100:num=N[15:12];
		3'b101:num=N[11:8];
		3'b110:num=N[7:4];
		3'b111:num=N[3:0];
	endcase
end
always@(num)
begin
	case(num)
		4'h0:seg=8'b00111111;	//"0"
		4'h1:seg=8'b00000110;	//"1"
		4'h2:seg=8'b01011011;	//"2"
		4'h3:seg=8'b01001111;	//"3”
		4'h4:seg=8'b01100110;	//"4"
		4'h5:seg=8'b01101101;	//"5"
		4'h6:seg=8'b01111101;	//"6"
		4'h7:seg=8'b00000111;	//"8"
		4'h8:seg=8'b01111111;	//"8"
		4'h9:seg=8'b01101111;	//"9"
		4'hA:seg=8'b01110111;	//"A"
		4'hB:seg=8'b01111100;	//"b"
		4'hC:seg=8'b00111001;	//"c"
		4'hD:seg=8'b01011110;	//"d"
		4'hE:seg=8'b01111001;	//"E"
		4'hF:seg=8'b01110001;	//"F"
		default:seg=8'b00000000;	//"dark"
	endcase
end
	
endmodule仿真波形
引脚配置
| 信号 | 输出/输出 | 引脚 | 信号 | 输出/输出 | 引脚 | 
|---|---|---|---|---|---|
| KEY_C[3] | Input | PIN_AE14 | rd | Input | PIN_AC5 | 
| KEY_C[2] | Input | PIN_AF13 | reset | Input | PIN_AA10 | 
| KEY_C[1] | Input | PIN_AD12 | seg[7] | Output | PIN_M21 | 
| KEY_C[0] | Input | PIN_AD11 | seg[6] | Output | PIN_G12 | 
| KEY_R[3] | Output | PIN_AE11 | seg[5] | Output | PIN_G14 | 
| KEY_R[2] | Output | PIN_AF11 | seg[4] | Output | PIN_G15 | 
| KEY_R[1] | Output | PIN_AE12 | seg[3] | Output | PIN_G18 | 
| KEY_R[0] | Output | PIN_AE13 | seg[2] | Output | PIN_F18 | 
| M[1] | Input | PIN_AF12 | seg[1] | Output | PIN_G17 | 
| M[0] | Input | PIN_AG12 | seg[0] | Output | PIN_G16 | 
| RA[1] | Input | PIN_AA8 | sel[2] | Output | PIN_G9 | 
| RA[0] | Input | PIN_AB8 | sel[1] | Output | PIN_D22 | 
| clk | Input | PIN_A14 | sel[0] | Output | PIN_C22 | 
| clr | Input | PIN_AH12 | wr | Input | PIN_AE4 | 
解释说明