Bootstrap

计算机组成实验——课程设计——简化计算机系统的设计

实现简单的指令集的处理器和存储器连接形成简单的计算机系统。

按照给出的指令集和实例程序实现。

指令集

示例程序

一、实验分析与设计

程序设计主要包括两部分: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

;