基于有限状态机的8位RISC CPU的Verilog实现

8位RISC CPU的Verilog实现

一. 设计需求

当今绝大多数计算机,无论是大型机还是微型机其基本结构都是冯诺依曼体系结构,即计算机由控制器,运算器,存储器,和输入/输出设备五部分组成。指令和程序都是存储在存储器中。

中央处理器,也称微处理器(microprocessor),是计算机系统的核心。主要完成以下任务:(1)从存储器中取指令,指令译码;(2)执行简单的算数逻辑运算;(3)在处理器和存储器或I/O之间传送数据;(4)程序流向控制等[1]。

RISC,reduced instruction set computer,精简指令集计算机相较于CISC,complex instruction set computer,复杂指令集计算机能够在一个时钟周期执行更多的指令,这些指令比CISC的指令集具有更短,功能更简单,指令格式更统一等特点,因此适合流水线处理,加快处理速度。

8位CPU是上世纪70年代开始采用的典型CPU结构,代表产品有因特尔的8080系列[1]。是现代普遍采用的64位,32位总线结构CPU的起始。

本文将基于有限状态机(Finite State Machine, FSM)采用Verilog硬件描述语言对8位RISC架构CPU进行实现。

二. 硬件组成

如图是微型计算机系统中关键组成部分,包含CPU,存储器,数据和地址总线。CPU主要由算数逻辑单元(ALU,Arithmetic Logic Unit),累加器(accumulator),通用寄存器(registers),程序计数器(PC,Program Counter),指令寄存器(IR,Instruction Register),地址选择器(address multiplexer)组成。存储器这里指主存储器,分为随机存取存储器RAM(Radom Access Memory)和只读存储器ROM(Read Only Memory)。主存和CPU之间通过总线访问,总线有地址总线(Address Bus)和数据总线(Data Address)两种。

2.1 存储器

2.1.1 ROM

ROM用于存储要执行的指令,关于指令的介绍见第三章。

Verilog实现:

module rom(data, addr, read, ena);
input read, ena;
input [7:0] addr;
output [7:0] data;
 
reg [7:0] memory[255:0];


// note: Decimal number in the bracket
initial begin
	memory[0] = 8'b000_00000;	//NOP
	... // some instructions
end

assign data = (read&&ena)? memory[addr]:8'hzz;	

endmodule

ROM,只读指令。接受输入地址,当读信号和使能信号高电平时输出对应地址存储的指令,否则输出保持高阻态。地址和数据都是8位,可寻址以及内部存储的大小为256Bytes。

RTL(register-transfer level,寄存器传输级)综合如上图所示。

2.2.2 RAM

存储数据,可读可写。

Verilog实现:

module ram(data, addr, ena, read, write);
input ena, read, write;
input [7:0] addr;
inout [7:0] data;

reg [7:0] ram[255:0];

assign data = (read&&ena)? ram[addr]:8'hzz;		// read data from RAM

always @(posedge write) begin	// write data to RAM
	ram[addr] <= data;
end
endmodule

可读可写,接收8位地址,当读信号和使能信号有效时,输出对应地址存储的数据,否则输出保持高阻态。当写信号上升沿是触发,将输入输出写入地址对应位置。内部存储以及可循址大小也为256Byters。

RTL视图如上。

2.2 CPU

2.2.1 PC

程序计数器,有时也叫做指令地址寄存器(Instruction Address Register, IAR),对应于Intel
X86体系CPU中的指令指针(Instruction pointer)寄存器。其功能是用来存放要执行的下一条指令在现行代码段中的偏移地址。本文中PC由Controller自动修改,使得其中始终存放着下一条将要执行指令的地址。因此,PC是用来控制指令序列执行流程的寄存器[2]。

Verilog实现:

//PC, program counter
module counter(pc_addr, clock, rst, en);
input clock, rst, en;
output reg [7:0] pc_addr;
always @(posedge clock or negedge rst) begin
	if(!rst) pc_addr <= 8'd0;
	else begin
		if(en) pc_addr <= pc_addr+1;
		else pc_addr <= pc_addr;
	end
end
endmodule

异步清零。时钟上升沿触发,高电平使能时程序计数器计数,指向下一条要执行指令的地址。指令存储在ROM中,故每次pc_addr加1。

RTL视图如上。

2.2.2 累加器

累加器,用于储存计算的中间结果。

Verilog实现:

// Accumulator
module accum( in, out, ena, clk, rst); 
// a register, to storage result after computing
input clk,rst,ena;
input [7:0] in;
output reg [7:0] out;

always @(posedge clk or negedge rst) begin	
	if(!rst) out <= 8'd0;
	else begin
		if(ena)	out <= in;
		else	out <= out;
	end
end
endmodule

异步清零。时钟上升沿触发,高电平使能时输出当前输入信号。

RTL视图如上,可以看出其是一个Q触发器来实现。

2.2.3 地址选择器

接受控制使能信号对输入的来自程序计数器和指令寄存器的地址进行选择。

Verilog实现:

// Address multiplexer
module addr_mux(addr, sel, ir_ad, pc_ad); 
// To choose address of instruction register or address of program counter
input [7:0] ir_ad, pc_ad;
input sel;
output [7:0] addr;
assign addr = (sel)? ir_ad:pc_ad;
endmodule

当选择信号为1时,选择来自寄存器输入的地址到数据总线,否则将程序计数器中的地址加载到数据总线。

RTL视图如上。

2.2.4 ALU

算术逻辑运算单元,根据指令类型来决定进行哪种运算,从而将运算结果输出通用寄存器或者累加器中。

module alu(alu_out, alu_in, accum, op);
// Arithmetic logic unit
// to perform arithmetic and logic operations.
input [2:0] op;
input [7:0] alu_in,accum;
output reg [7:0] alu_out;

parameter 	NOP=3'b000,
			LDO=3'b001,
			LDA=3'b010,
			STO=3'b011,
			PRE=3'b100,
			ADD=3'b101,
			LDM=3'b110,
			HLT=3'b111;

always @(*) begin
		casez(op)
		NOP:	alu_out = accum;
		HLT:	alu_out = accum;
		LDO:	alu_out = alu_in;
		LDA:	alu_out = alu_in;
		STO:	alu_out = accum;
		PRE:	alu_out = alu_in;
		ADD:	alu_out = accum+alu_in;
		LDM:	alu_out = accum;
		default:	alu_out = 8'bzzzz_zzzz;
		endcase
end	
endmodule

RTL视图如上。

2.2.5 通用寄存器

通用寄存器,ALU输出结果,指令寄存器输出的操作数都可以存储到寄存器中的特定的地址。输出寄存器中存储的数据到数据总线。

Verilog实现:

module reg_32(in, data, write, read, addr, clk);
input write, read, clk;
input [7:0] in;
input [7:0] addr; 
//!Warning: addr should be reduced to 5 bits width, not 8 bits width.
//input [4:0] addr;

output [7:0] data;

reg [7:0] R[31:0]; //32Byte
wire [4:0] r_addr;

assign r_addr = addr[4:0];
assign data = (read)? R[r_addr]:8'hzz;	//read enable

always @(posedge clk) begin				//write, clk posedge
	if(write)	R[r_addr] <= in; 
end
endmodule

当写信号有效时,将输入数据(来自ALU的输出)存储到寄存器中的特定地址。当读信号有效时,将寄存器中特定位置的数据输出(到数据总线)。寄存器大小为32Bytes。

RTL视图如上。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值