CPU 取指过程涉及 3 个主要部件:PC 寄存器、Memory 和增 1 加法器。假设指令是 16 位等长,存储器采用字节编址,增加 1 个指令字地址使 PC 指向下一条指令地址。可通过矩阵键盘输入调整PC的值。
一、实验分析与设计
由实验内容可将程序分为:外部输入模块、PC模块、存储器模块、外部显示模块。
外部输入模块:通过矩阵键盘获取值D,可改变PC的值。可参考本专栏文章
PC模块:实现PC值加一、减一、置数。将PC值作为地址传入存储器模块。
存储器模块:在256×16的存储器中先存入值,通过PC作为地址取存储器值q。可参考本专栏文章
外部显示模块:将外部输入值D,PC值,存储器值q显示在数码管上。
二、程序代码
由于顶层采用原理图的方式,所以需将Verilog HDL编写的模块符号化,再在原理图中调用。
顶层原理图
外部输入模块
module sy7_input(clk,key_R,key_C,D);
input clk;
input[3:0]key_R;
output reg[3:0]key_C;
output reg[7:0]D;
reg flag;
reg [1:0]row;
reg [3:0]Q;
always @(posedge clk)
begin
if(key_R==4'b1111)
flag=0;
else
flag=1;
if(flag==0)
row=row+1;
end
always @(posedge clk)
begin
case(row)
0:key_C=4'b1110;
1:key_C=4'b1101;
2:key_C=4'b1011;
3:key_C=4'b0111;
endcase
end
always @(posedge clk)
begin
case({key_C,key_R})
8'b11101110:Q=4'hd;
8'b11101101:Q=4'hf;
8'b11101011:Q=4'h0;
8'b11100111:Q=4'he;
8'b11011110:Q=4'hc;
8'b11011101:Q=4'h9;
8'b11011011:Q=4'h8;
8'b11010111:Q=4'h7;
8'b10111110:Q=4'hb;
8'b10111101:Q=4'h6;
8'b10111011:Q=4'h5;
8'b10110111:Q=4'h4;
8'b01111110:Q=4'ha;
8'b01111101:Q=4'h3;
8'b01111011:Q=4'h2;
8'b01110111:Q=4'h1;
endcase
end
reg [1:0]state=2'b00;
integer k = 0;
always @(posedge clk)
begin
if(state == 2'b00 && flag)
begin
k = 0;
D[7:4] = Q;
state = 2'b01;
end
else if(state == 2'b01)
begin
if(k > 100000) state = 2'b10;
else k = k + 1;
end
else if(state == 2'b10 && flag)
begin
k = 0;
D[3:0] = Q;
state = 2'b11;
end
else if(state == 2'b11)
begin
if(k > 100000) state = 2'b00;
else k = k + 1;
end
end
endmodule
PC模块
module sy7_PC(clk,D,Sel,PC);
input clk;
input [7:0]D;
input [1:0]Sel;
output reg[7:0]PC;
integer k = 1;
always@(posedge clk)
begin
if(k < 100000) k = k + 1;
else
begin
k = 1;
end
end
always@(posedge clk)
begin
case(Sel)
2'b00 : PC = PC;
2'b01 : //PC+1
begin
if(k == 100000) PC = PC + 1'b1;
end
2'b10 : //PC-1
begin
if(k == 100000) PC = PC - 1'b1;
end
2'b11 : PC = D; //置数D
endcase
end
endmodule
外部显示模块
module sy7_show(clk,D,PC,M,SEL,code);
input clk;
input [7:0]D,PC;
input [15:0]M;
output reg[2:0]SEL;
output reg[7:0]code;
reg[4:0]Data;
always@(posedge clk)
begin
if(SEL < 3'b111) SEL = SEL + 1;
else SEL = 3'b000;
end
always@(SEL)
begin
case(SEL)
3'b000 : Data = D[7:4];
3'b001 : Data = D[3:0];
3'b010 : Data = PC[7:4];
3'b011 : Data = PC[3:0];
3'b100 : Data = M[15:12];
3'b101 : Data = M[11:8];
3'b110 : Data = M[7:4];
3'b111 : Data = M[3:0];
endcase
end
always @(Data)
begin
case(Data)
4'd0 : code = 8'h3f;
4'd1 : code = 8'h06;
4'd2 : code = 8'h5b;
4'd3 : code = 8'h4f;
4'd4 : code = 8'h66;
4'd5 : code = 8'h6d;
4'd6 : code = 8'h7d;
4'd7 : code = 8'h07;
4'd8 : code = 8'h7f;
4'd9 : code = 8'h6f;
4'd10: code = 8'h77;
4'd11: code = 8'h7c;
4'd12: code = 8'h39;
4'd13: code = 8'h5e;
4'd14: code = 8'h79;
4'd15: code = 8'h71;
default : code = 8'bx;
endcase
end
endmodule
引脚分配图