实现简单的指令集的处理器和存储器连接形成简单的计算机系统。
按照给出的指令集和实例程序实现。
指令集
示例程序
一、实验分析与设计
程序设计主要包括两部分:CPU设计和存储器设计
连接图
CPU设计参照实验教材上的:指令操作步骤和处理器每一状态下的操作及状态转换。
存储器设计为64×8的RAM存储器,按实例程序写入数据。可参考本专栏文章
二、程序代码
顶层模块及原理图
module Computer(
clk,
reset,
write_read,
overflow,
M_address,
M_data_out,
q
);
input wire clk;
input wire reset;
output wire write_read;
output wire overflow;
output wire [11:0] M_address;
output wire [7:0] M_data_out;
output wire [7:0] q;
wire [11:0] M_address_ALTERA_SYNTHESIZED;
wire [7:0] M_data_out_ALTERA_SYNTHESIZED;
wire [7:0] q_ALTERA_SYNTHESIZED;
wire write_read_ALTERA_SYNTHESIZED;
CPU b2v_inst1(
.clk(clk),
.reset(reset),
.M_data_in(q_ALTERA_SYNTHESIZED),
.write_read(write_read_ALTERA_SYNTHESIZED),
.overflow(overflow),
.M_address(M_address_ALTERA_SYNTHESIZED),
.M_data_out(M_data_out_ALTERA_SYNTHESIZED));
Hex b2v_inst2(
.wren(write_read_ALTERA_SYNTHESIZED),
.clock(clk),
.address(M_address_ALTERA_SYNTHESIZED[5:0]),
.data(M_data_out_ALTERA_SYNTHESIZED),
.q(q_ALTERA_SYNTHESIZED));
assign write_read = write_read_ALTERA_SYNTHESIZED;
assign M_address = M_address_ALTERA_SYNTHESIZED;
assign M_data_out = M_data_out_ALTERA_SYNTHESIZED;
assign q = q_ALTERA_SYNTHESIZED;
endmodule
CPU模块
module CPU(clk,reset,M_data_in,write_read,M_address,M_data_out,overflow);
input clk,reset;
input [7:0]M_data_in;
output reg write_read = 0;
output [11:0]M_address;
output [7:0]M_data_out;
output reg overflow = 0;
//MDR与MAR
reg [7:0]MDR = 8'h00;
reg [11:0]MAR = 12'h000;
assign M_address = MAR;
assign M_data_out = MDR;
reg [7:0]R0=8'h00,R1=8'h00,R2=8'h00,R3=8'h00,PC=8'h00; //寄存器组
reg [7:0]A=8'h00,Rx=8'h00,Ry=8'h00; //运算变量
reg [8:0]RxT=8'h00,AT=8'h00; //双符号位补码加减运算
reg [15:0]IR=8'h00; //指令
reg clk1 = 1'b0;//为使得内存读取速度与程序执行速度匹配,将CPU时钟减慢
always@(posedge clk)
begin
clk1 = ~clk1;
end
reg [2:0]st = 3'b000; //状态
always@(st)
begin
if(st == 3'd3 && IR[15:12] == 4'b1110) write_read = 1;
else write_read = 0;
end
reg step = 1'b0;
always@(clk1,reset)
begin
if(!reset) //清零
begin
R0 = 0; R1 = 0; R2 = 0; R3 = 0; PC = 0;
A = 0; Rx = 0; Ry = 0; IR = 0;
MAR = 0; MDR = 0;
end
else
begin
case(st)
3'd0:
begin
overflow = 0;
if(clk1 && !step) //上升沿
begin
IR = {M_data_in,8'h00}; //当前指令IR与下一地址PC
PC = PC + 1;
case(IR[11:10]) //取Rx
2'b00: Rx = R0;
2'b01: Rx = R1;
2'b10: Rx = R2;
2'b11: Rx = R3;
endcase
case(IR[9:8]) //取Ry
2'b00: Ry = R0;
2'b01: Ry = R1;
2'b10: Ry = R2;
2'b11: Ry = R3;
endcase
step = ~step;
end
if(!clk1 && step) //下降沿
begin
MAR = PC; //PC赋值到MAR,取内存中值到M_data_in中
A = Ry;
st = 3'd1;
RxT = {Rx[7],Rx};
AT = {Ry[7],Ry};
step = ~step;
end
end
3'd1:
begin
if(clk1 && !step) //上升沿
begin
case(IR[15:12]) //加减等运算
4'b0001: R0 = {4'h0,IR[11:8]};
4'b0010: Rx = A;
4'b0011: begin Rx = Rx + A; RxT = RxT + AT; end
4'b0100: begin Rx = Rx - A; RxT = RxT - AT; end
4'b0101: Rx = Rx & A;
4'b0110: Rx = Rx | A;
4'b0111: Rx = Rx ^ A;
4'b1000: Rx = {1'b0,Rx[7:1]};
4'b1001: Rx = {Rx[6:0],1'b0};
endcase
if(IR[15:12] == 4'b0011 || IR[15:12] == 4'b0100) //加减溢出判断
begin
if(RxT[8] != RxT[7]) overflow = 1;
else overflow = 0;
end
if(IR[15:12] <= 4'b1001 && IR[15:12] != 4'b0001) //运算值赋值到Rx位置(IR[11:10])中
begin
case(IR[11:10])
2'b00: R0 = Rx;
2'b01: R1 = Rx;
2'b10: R2 = Rx;
2'b11: R3 = Rx;
endcase
end
else if(IR[15:12] == 4'b1010) //swap指令,Rx赋值到Ry位置(IR[9:8])中
begin
case(IR[9:8])
2'b00: R0 = Rx;
2'b01: R1 = Rx;
2'b10: R2 = Rx;
2'b11: R3 = Rx;
endcase
end
step = ~step;
end
if(!clk1 && step) //下降沿
begin
if(IR[15:12] <= 4'b1001) st = 3'd0; //加减等指令结束,返回st0
else if(IR[15:12] == 4'b1111) st = 3'd1; //stop指令保持当前状态st1
else st = 3'd2; //交换、读写等指令进入下一状态st2
step = ~step;
end
end
3'd2:
begin
if(clk1 && !step) //上升沿
begin
if(IR[15:12] == 4'b1010) //swap指令,Ry(A)赋值到Rx位置(IR[11:10])中
begin
case(IR[11:10])
2'b00: R0 = A;
2'b01: R1 = A;
2'b10: R2 = A;
2'b11: R3 = A;
endcase
end
else
begin //获得指令第二字节。由st0中PC+1->MAR得到M_data_in
IR[7:0] = M_data_in;
PC = PC + 1; //下一地址
if(IR[15:12] == 4'b1110) MDR = R0; //需写入内存的值
end
step = ~step;
end
if(!clk1 && step) //下降沿
begin
if(IR[15:12] == 4'b1010) st = 3'd0; //swap指令结束,返回st0
else
begin
if(IR[15:12] != 4'b1100) //将下一地址赋值给MAR。读、转移是为了获取地址中的值M_data_in;写是将值M_data_out写入该地址MAR。
MAR = IR[11:0];
else
if(R0 == 0) MAR = IR[11:0];
else MAR = PC; //条件转移失败下一地址即PC
st = 3'd3;
end
step = ~step;
end
end
3'd3:
begin
if(clk1 && !step) //上升沿
begin
case(IR[15:12]) //转移指令。修改下一地址PC
4'b1011: PC = IR[11:0];
4'b1100: if(R0 == 0) PC = IR[11:0];
endcase
step = ~step;
end
if(!clk1 && step) //下降沿
begin
if(IR[15:12] <= 4'b1100) st = 3'd0; //转移指令结束
else
begin
MAR = PC; //读写指令。获取下一地址中的值M_data_in(即下一执行指令)。
st = 3'd4;
end
step = ~step;
end
end
3'd4:
begin
if(clk1 && !step) //上升沿
begin
if(IR[15:12] == 4'b1101) R0 = M_data_in; //读值写入R0,此处为3'd2中获取的值,3'd3中的获取值还未到达。(读写延迟)
step = ~step;
end
if(!clk1 && step) //下降沿
begin
st = 3'd0; //读写指令结束,返回st0
step = ~step;
end
end
endcase
end
end
endmodule
可将OP的值用常量表示。
三、ModelSim仿真
Test Bench文件 由于程序已经存入存储器中,所以此处只需要提供时钟信号即可。
`timescale 1 ps/ 1 ps
module Computer_vlg_tst();
reg clk;
reg reset;
// wires
wire [11:0] M_address;
wire [7:0] M_data_out;
wire overflow;
wire [7:0] q;
wire write_read;
Computer i1 (
.clk(clk),
.M_address(M_address),
.M_data_out(M_data_out),
.overflow(overflow),
.q(q),
.reset(reset),
.write_read(write_read)
);
initial
begin
clk = 1'b0;
reset = 1'b1;
$display("Running testbench");
end
always #10 clk = ~clk;
endmodule
仿真波形图:状态st由000->000,则是一条指令执行完毕。
指令1、2、3、4
指令5、6、7、8
指令9、10、11、12、13
指令14、15、16
指令17、18
指令19、17、20