基于状态机的简易RISC CPU设计

目录

一、什么是CPU?

二、RISC CPU结构

1.时钟发生器

2.指令寄存器

3.累加器

4.RISC CPU算术逻辑运算单元

5.数据控制器

6.状态控制器

7.程序计数器

8.地址多路器

9.外围模块

10.地址译码器

a.RAM

b.ROM

三、RISC CPU中各部件的相互连接关系

四、RISC CPU和它的外围电路

五、RISC CPU的寻址方式和指令系统

六、RISC CPU的操作和时序

正文

一、什么是CPU?

CPU 即中央处理单元的英文缩写,它是计算机的核心部件。计算机进行信息处理可分为两个步骤:

  1. 将数据和程序(即指令序列)输入到计算机的存储器中。
  2. 从第一条指令的地址起开始执行该程序,得到所需结果,结束运行。CPU的作用是协调并控制计算机的各个部件执行程序的指令序列,使其有条不紊地进行。因此它必须具有以下基本功能:
    • a)取指令:当程序已在存储器中时,首先根据程序入口地址取出一条程序,为此要发出指令地址及控制信号。
    • b)分析指令:即指令译码。是对当前取得的指令进行分析,指出它要求什么操作,并产生相应的操作控制命令。
    • c)执行指令:根据分析指令时产生的“操作命令”形成相应的操作控制信号序列,通过运算器,存储器及输入/输出设备的执行,实现每条指令的功能,其中包括对运算结果的处理以及下条指令地址的形成。

将其功能进一步细化,可概括如下:

  1. 能对指令进行译码并执行规定的动作;
  2. 可以进行算术和逻辑运算;
  3. 能与存储器,外设交换数据;
  4. 提供整个系统所需要的控制;

尽管各种CPU的性能指标和结构细节各不相同,但它们所能完成的基本功能相同。由功能分析,可知任何一种CPU内部结构至少应包含下面这些部件:

  1. 算术逻辑运算部件(ALU),
  2. 累加器,
  3. 程序计数器,
  4. 指令寄存器,译码器,
  5. 时序和控制部件。

RISC 即精简指令集计算机(Reduced Instruction Set Computer)的缩写。它是一种八十年代才出现的CPU,与一般的CPU 相比不仅只是简化了指令系统,而且是通过简化指令系统使计算机的结构更加简单合理,从而提高了运算速度。从实现的途径看,RISC_CPU与一般的CPU的不同处在于:它的时序控制信号形成部件是用硬布线逻辑实现的而不是采用微程序控制的方式。所谓硬布线逻辑也就是用触发器和逻辑门直接连线所构成的状态机和组合逻辑,故产生控制序列的速度比用微程序控制方式快得多,因为这样做省去了读取微指令的时间。RISC_CPU也包括上述这些部件,下面就详细介绍一个简化的用于教学目的的RISC_CPU的可综合VerilogHDL模型的设计和仿真过程。

二、RISC CPU结构

RISC_CPU是一个复杂的数字逻辑电路,但是它的基本部件的逻辑并不复杂。可把它分成八个基本部件:

  1. 时钟发生器
  2. 指令寄存器
  3. 累加器
  4. RISC CPU算术逻辑运算单元
  5. 数据控制器
  6. 状态控制器
  7. 程序计数器
  8. 地址多路器

其中时钟发生器利用外来时钟信号进行分频生成一系列时钟信号,送往其他部件用作时钟信号。各部件之间的相互操作关系则由状态控制器来控制。下面逐一介绍各部件的具体结构和逻辑关系。

1 时钟发生器

时钟发生器 clkgen 利用外来时钟信号clk 来生成一系列时钟信号clk1、fetch、alu_clk 送往CPU的其他部件。其中fetch是外来时钟 clk 的八分频信号。利用fetch的上升沿来触发CPU控制器开始执行一条指令,同时fetch信号还将控制地址多路器输出指令地址和数据地址。clk1信号用作指令寄存器、累加器、状态控制器的时钟信号。alu_clk 则用于触发算术逻辑运算单元。时钟发生器clkgen的波形见下图所示:

其VerilogHDL 程序见下面的模块:

module clk_gen (clk,reset,clk1,clk2,clk4,fetch,alu_clk);
input clk,reset;
output clk1,clk2,clk4,fetch,alu_clk;
wire clk,reset;
reg clk2,clk4,fetch,alu_clk;
reg[7:0] state;
parameter S1 = 8‘b00000001,
	S2 = 8‘b00000010,
	S3 = 8‘b00000100,
	S4 = 8‘b00001000,
	S5 = 8‘b00010000,
	S6 = 8‘b00100000,
	S7 = 8‘b01000000,
	S8 = 8‘b10000000,
	idle = 8‘b00000000;
assign clk1 = ~clk;

always @(negedge clk)
	if(reset)
		begin
			clk2 <= 0;
			clk4 <= 1;
			fetch <= 0;
			alu_clk <= 0;
			state <= idle;
		end
	else
		begin
			case(state)
			S1:
				begin
					clk2 <= ~clk2;
					alu_clk <= ~alu_clk;
					state <= S2;
				end
			S2:
				begin
					clk2 <= ~clk2;
					clk4 <= ~clk4;
					alu_clk <= ~alu_clk;
					state <= S3;
				end
			S3:
				begin
					clk2 <= ~clk2;
					state <= S4;
				end
			S4:
				begin
					clk2 <= ~clk2;
					clk4 <= ~clk4;
					fetch <= ~fetch;
					state <= S5;
				end
			S5:
				begin
					clk2 <= ~clk2;
					state <= S6;
				end
			S6:
				begin
					clk2 <= ~clk2;
					clk4 <= ~clk4;
					state <= S7;
				end
			S7:
				begin
					clk2 <= ~clk2;
					state <= S8;
				end
			S8:
				begin
					clk2 <= ~clk2;
					clk4 <= ~clk4;
					fetch <= ~fetch;
					state <= S1;
				end
			idle: state <= S1;
			default: state <= idle;
		endcase
	end
endmodule
//--------------------------------------------------------------------------------

由于在时钟发生器的设计中采用了同步状态机的设计方法,不但使clk_gen模块的源程序可以被各种综合器综合,也使得由其生成的clk1、clk2、clk4、fetch、alu_clk 在跳变时间同步性能上有明显的提高,为整个系统的性能提高打下了良好的基础。

2 指令寄存器

顾名思义,指令寄存器用于寄存指令。
       指令寄存器的触发时钟是clk1,在clk1的正沿触发下,寄存器将数据总线送来的指令存入高8位或低8位寄存器中。但并不是每个clk1的上升沿都寄存数据总线的数据,因为数据总线上有时传输指令,有时传输数据。什么时候寄存,什么时候不寄存由CPU状态控制器的load_ir信号控制。load_ir信号通过ena 口输入到指令寄存器。复位后,指令寄存器被清为零。
       每条指令为2个字节,即16位。高3位是操作码,低13位是地址。(CPU的地址总线为13位,寻址空间为8K字节。)本设计的数据总线为8位,所以每条指令需取两次。先取高8位,后取低8位。而当前取的是高8位还是低8位,由变量state记录。state为零表示取的高8位,存入高8位寄存器,同时将变量state置为1。下次再寄存时,由于state为1,可知取的是低8位,存入低8位寄存器中。

其VerilogHDL 程序见下面的模块:

//---------------------------------------------------------------
module register(opc_iraddr,data,ena,clk1,rst);
output [15:0] opc_iraddr;
input [7:0] data;
input ena, clk1, rst;
reg [15:0] opc_iraddr;
reg state;

always @(posedge clk1)
begin
	if(rst)
		begin
			opc_iraddr<=16‘b0000_0000_0000_0000;
			state<=1‘b0;
		end
	else
		begin
			if(ena) //如果加载指令寄存器信号load_ir到来,
				begin //分两个时钟每次8位加载指令寄存器
					casex(state) //先高字节,后低字节
						1’b0: begin
							opc_iraddr[15:8]<=data;
							state<=1;
						end
						1’b1: begin
							opc_iraddr[7:0]<=data;
							state<=0;
						end
						default: begin
							opc_iraddr[15:0]<=16‘bxxxxxxxxxxxxxxxx;
							state<=1‘bx;
						end
					endcase
				end
			else
				state<=1‘b0;
		end
end
endmodule
//--------------------------------------------------------

3.累加器

累加器用于存放当前的结果,它也是双目运算其中一个数据来源。复位后,累加器的值是零。当累加器通过ena口收到来自CPU状态控制器load_acc信号时,在clk1时钟正跳沿时就收到来自于数据总线的数据。 
           其VerilogHDL 程序见下面的模块:

//--------------------------------------------------------------
module accum( accum, data, ena, clk1, rst);
output[7:0]accum;
input[7:0]data;
input ena,clk1,rst;
reg[7:0]accum;

[email protected](posedge clk1)
	begin
		if(rst)
			accum<=8‘b0000_0000; //Reset
		else
			if(ena) //当CPU状态控制器发出load_acc信号
				accum<=data; //Accumulate
	end
endmodule

4.算术运算器

算术逻辑运算单元 根据输入的8种不同操作码分别实现相应的加、与、异或、跳转等8种基本操作运算。利用这几种基本运算可以实现很多种其它运算以及逻辑判断等操作。 
       其VerilogHDL 程序见下面的模块:

//------------------------------------------------------------------------------
module alu (alu_out, zero, data, accum, alu_clk, opcode);
output [7:0]alu_out;
output zero;
input [7:0] data, accum;
input [2:0] opcode;
input alu_clk;
reg [7:0] alu_out;

parameter HLT =3’b000,
	SKZ =3’b001,
	ADD =3’b010,
	ANDD =3’b011,
	XORR =3’b100,
	LDA =3’b101,
	STO =3’b110,
	JMP =3’b111;

assign zero = !accum;
always @(posedgealu_clk)
	begin //操作码来自指令寄存器的输出opc_iaddr<15..0>的低3位
		casex (opcode)
			HLT: alu_out<=accum;
			SKZ: alu_out<=accum;
			ADD: alu_out<=data+accum;
			ANDD: alu_out<=data&accum;
			XORR: alu_out<=data^accum;
			LDA: alu_out<=data;
			STO: alu_out<=accum;
			JMP: alu_out<=accum;
			default: alu_out<=8‘bxxxx_xxxx;
		endcase
	end
endmodule
//----------------------------------------------------------------------------

5.数据控制器

数据控制器的作用是控制累加器数据输出,由于数据总线是各种操作时传送数据的公共通道,不同的情况下传送不同的内容。有时要传输指令,有时要传送RAM区或接口的数据。累加器的数据只有在需要往RAM区或端口写时才允许输出,否则应呈现高阻态,以允许其它部件使用数据总线。 所以任何部件往总线上输出数据时,都需要一控制信号。而此控制信号的启、停,则由CPU状态控制器输出的各信号控制决定。数据控制器何时输出累加器的数据则由状态控制器输出的控制信号datactl_ena决定。 
        其VerilogHDL 程序见下面的模块:

//--------------------------------------------------------------------
module datactl (data,in,data_ena);
output [7:0]data;
input [7:0]in;
input data_ena;

assign data = (data_ena)? In : 8‘bzzzz_zzzz;

endmodule
//--------------------------------------------------------------------

6.地址多路器

地址多路器用于选择输出的地址是PC(程序计数)地址还是数据/端口地址。每个指令周期的前4个时钟周期用于从ROM中读取指令,输出的应是PC地址。后4个时钟周期用于对RAM或端口的读写,该地址由指令中给出。地址的选择输出信号由时钟信号的8分频信号fetch提供。

其VerilogHDL 程序见下面的模块:

//------------------------------------------------------------------------------
module adr(addr,fetch,ir_addr,pc_addr);
output [12:0] addr;
input [12:0] ir_addr, pc_addr;
input fetch;

assign addr = fetch? pc_addr : ir_addr;

endmodule
//------------------------------------------------------------------------------

7.程序计数器

程序计数器用于提供指令地址。以便读取指令,指令按地址顺序存放在存储器中。有两种途径可形成指令地址:其一是顺序执行的情况,其二是遇到要改变顺序执行程序的情况,例如执行JMP指令后,需要形成新的指令地址。复位后,指令指针为零,即每次CPU重新启动将从ROM的零地址开始读取指令并执行。每条指令执行完需2个时钟,这时pc_addr已被增2,指向下一条指令。(因为每条指令占两个字节。)如果正执行的指令是跳转语句,这时CPU状态控制器将会输出load_pc信号,通过load口进入程序计数器。程序计数器(pc_addr)将装入目标地址(ir_addr),而不是增2。 
       其VerilogHDL 程序见下面的模块:

//------------------------------------------------------------------------------
module counter ( pc_addr, ir_addr, load, clock, rst);
output [12:0] pc_addr;
input [12:0] ir_addr;
input load, clock, rst;
reg [12:0] pc_addr;

always @( posedge clock or posedge rst )
	begin
		if(rst)
			pc_addr<=13‘b0_0000_0000_0000;
		else
			if(load)
				pc_addr<=ir_addr;
			else
				pc_addr <= pc_addr + 1;
	end
endmodule
//------------------------------------------------------------------------------

8.状态控制器

状态控制器由两部分组成:

  1. 状态机(上图中的MACHINE部分)
  2. 状态控制器(上图中的MACHINECTL部分)

状态机控制器接受复位信号RST,当RST有效时通过信号ena使其为0,输入到状态机中停止状态机的工作。 
         状态控制器的VerilogHDL程序见下面模块:

//------------------------------------------------------------------------------
module machinectl( ena, fetch, rst);
output ena;
input fetch, rst;
reg ena;
always @(posedge fetch or posedge rst)

begin
	if(rst)
		ena<=0;
	else
		ena<=1;
end
endmodule
//------------------------------------------------------------------------------

状态机是CPU的控制核心,用于产生一系列的控制信号,启动或停止某些部件。CPU何时进行读指令读写I/O端口,RAM区等操作,都是由状态机来控制的。状态机的当前状态,由变量state记录,state的值就是当前这个指令周期中已经过的时钟数(从零计起)。

指令周期是由8个时钟周期组成,每个时钟周期都要完成固定的操作。

  1. 第0个时钟,因为CPU状态控制器的输出:rd和load_ir为高电平,其余均为低电平。指令寄存器寄存由ROM送来的高8位指令代码。
  2. 第1个时钟,与上一时钟相比只是inc_pc从0变为1故PC增1,ROM送来低8位指令代码,指令寄存器寄存该8位代码。
  3. 第2个时钟,空操作。
  4. 第3个时钟,PC增1,指向下一条指令。若操作符为HLT,则输出信号HLT为高。如果操作符不为HLT,除了PC增一外(指向下一条指令),其它各控制线输出为零。
  5. 第4个时钟,若操作符为AND、ADD、XOR或LDA,读相应地址的数据;若为JMP,将目的地址送给程序计数器;若为STO,输出累加器数据。
  6. 第5个时钟,若操作符为ANDD、ADD或XORR,算术运算器就进行相应的运算;若为LDA,就把数据通过算术运算器送给累加器;若为SKZ,先判断累加器的值是否为0,如果为0,PC就增1,否则保持原值;若为JMP,锁存目的地址;若为STO,将数据写入地址处。
  7. 第6个时钟,空操作。
  8. 第7个时钟,若操作符为SKZ且累加器值为0,则PC值再增1,跳过一条指令,否则PC无变化。

状态机的VerilogHDL 程序见下面模块:

//------------------------------------------------------------------------------
module machine( inc_pc, load_acc, load_pc, rd,wr, load_ir,
datactl_ena, halt, clk1, zero, ena, opcode );
output inc_pc, load_acc, load_pc, rd, wr, load_ir;
output datactl_ena, halt;
input clk1, zero, ena;
input [2:0] opcode;
reg inc_pc, load_acc, load_pc, rd, wr, load_ir;
reg datactl_ena, halt;
reg [2:0] state;

parameter HLT = 3 ‘b000,
	SKZ = 3 ‘b001,
	ADD = 3 ‘b010,
	ANDD = 3 ‘b011,
	XORR = 3 ‘b100,
	LDA = 3 ‘b101,
	STO = 3 ‘b110,
	JMP = 3 ‘b111;

always @( negedge clk1 )
	begin
		if ( !ena ) //接收到复位信号RST,进行复位操作
			begin
				state<=3‘b000;
				{inc_pc,load_acc,load_pc,rd}<=4‘b0000;
				{wr,load_ir,datactl_ena,halt}<=4‘b0000;
			end
		else
			ctl_cycle;
	end
//-----------------begin of task ctl_cycle---------
task ctl_cycle;
begin
	casex(state)
		3’b000: //load high 8bits in struction
			begin
				{inc_pc,load_acc,load_pc,rd}<=4‘b0001;
				{wr,load_ir,datactl_ena,halt}<=4‘b0100;
				state<=3’b001;
			end
		3’b001: //pc increased by one then load low 8bits instruction
			begin
				{inc_pc,load_acc,load_pc,rd}<=4‘b1001;
				{wr,load_ir,datactl_ena,halt}<=4‘b0100;
				state<=3’b010;
			end
		3’b010: //idle
			begin
				{inc_pc,load_acc,load_pc,rd}<=4‘b0000;
				{wr,load_ir,datactl_ena,halt}<=4‘b0000;
				state<=3’b011;
			end
		3’b011: //next instruction address setup 分析指令从这里开始
			begin
				if(opcode==HLT) //指令为暂停HLT
					begin
						{inc_pc,load_acc,load_pc,rd}<=4‘b1000;
						{wr,load_ir,datactl_ena,halt}<=4‘b0001;
					end
				else
					begin
						{inc_pc,load_acc,load_pc,rd}<=4‘b1000;
						{wr,load_ir,datactl_ena,halt}<=4‘b0000;
					end
				state<=3’b100;
			end
		3’b100: //fetch oprand
			begin
				if(opcode==JMP)
					begin
						{inc_pc,load_acc,load_pc,rd}<=4‘b0010;
						{wr,load_ir,datactl_ena,halt}<=4‘b0000;
					end
				else
				if( opcode==ADD || opcode==ANDD ||
					opcode==XORR || opcode==LDA)
						begin
							{inc_pc,load_acc,load_pc,rd}<=4‘b0001;
							{wr,load_ir,datactl_ena,halt}<=4‘b0000;
						end
				else
					if(opcode==STO)
						begin
							{inc_pc,load_acc,load_pc,rd}<=4‘b0000;
							{wr,load_ir,datactl_ena,halt}<=4‘b0010;
						end
				else
					begin
						{inc_pc,load_acc,load_pc,rd}<=4‘b0000;
						{wr,load_ir,datactl_ena,halt}<=4‘b0000;
				end
				state<=3’b101;
			end
		3’b101: //operation
			begin
				if ( opcode==ADD||opcode==ANDD||opcode==XORR||opcode==LDA )
					begin //过一个时钟后与累加器的内容进行运算
						{inc_pc,load_acc,load_pc,rd}<=4‘b0101;
						{wr,load_ir,datactl_ena,halt}<=4‘b0000;
					end
				else
					if( opcode==SKZ && zero==1)
						begin
							{inc_pc,load_acc,load_pc,rd}<=4‘b1000;
							{wr,load_ir,datactl_ena,halt}<=4‘b0000;
						end
				else
					if(opcode==JMP)
						begin
							{inc_pc,load_acc,load_pc,rd}<=4‘b1010;
							{wr,load_ir,datactl_ena,halt}<=4‘b0000;
						end
				else
					if(opcode==STO)
						begin
							//过一个时钟后把wr变1就可写到RAM中
							{inc_pc,load_acc,load_pc,rd}<=4‘b0000;
							{wr,load_ir,datactl_ena,halt}<=4‘b1010;
						end
				else
					begin
						{inc_pc,load_acc,load_pc,rd}<=4‘b0000;
						{wr,load_ir,datactl_ena,halt}<=4‘b0000;
					end
				state<=3’b110;
			end
	3’b110: //idle
		begin
			if ( opcode==STO )
				begin
					{inc_pc,load_acc,load_pc,rd}<=4‘b0000;
					{wr,load_ir,datactl_ena,halt}<=4‘b0010;
				end
			else
				if ( opcode==ADD||opcode==ANDD||opcode==XORR||opcode==LDA)
					begin
						{inc_pc,load_acc,load_pc,rd}<=4‘b0001;
						{wr,load_ir,datactl_ena,halt}<=4‘b0000;
					end
			else
				begin
					{inc_pc,load_acc,load_pc,rd}<=4‘b0000;
					{wr,load_ir,datactl_ena,halt}<=4‘b0000;
				end
		state<=3’b111;
		end
	3’b111: //
		begin
			if( opcode==SKZ && zero==1 )
				begin
					{inc_pc,load_acc,load_pc,rd}<=4‘b1000;
					{wr,load_ir,datactl_ena,halt}<=4‘b0000;
				end
			else
				begin
					{inc_pc,load_acc,load_pc,rd}<=4‘b0000;
					{wr,load_ir,datactl_ena,halt}<=4‘b0000;
				end
			state<=3’b000;
		end
	default:
		begin
			{inc_pc,load_acc,load_pc,rd}<=4‘b0000;
			{wr,load_ir,datactl_ena,halt}<=4‘b0000;
			state<=3’b000;
		end
	endcase
end
endtask
//-----------------end of task ctl_cycle---------
endmodule
//------------------------------------------------------------------------------

9.外围模块

为了对RISC_CPU进行测试,需要有存储测试程序的ROM和装载数据的RAM、地址译码器。下面来简单介绍一下:

地址译码器
module addr_decode( addr, rom_sel, ram_sel);
output rom_sel, ram_sel;
input [12:0] addr;
reg rom_sel, ram_sel;
always @( addr )

begin
	casex(addr)
		13‘b1_1xxx_xxxx_xxxx:{rom_sel,ram_sel}<=2‘b01;
		13‘b0_xxxx_xxxx_xxxx:{rom_sel,ram_sel}<=2‘b10;
		13‘b1_0xxx_xxxx_xxxx:{rom_sel,ram_sel}<=2‘b10;
		default:{rom_sel,ram_sel}<=2‘b00;
	endcase
end
endmodule

地址译码器用于产生选通信号,选通ROM或RAM。 
FFFFH---1800H RAM 
1800H---0000H ROM

RAM
module ram( data, addr, ena, read, write );
inout [7:0] data;
input [9:0] addr;
input ena;
input read, write;
reg [7:0] ram [10‘h3ff:0];

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

always @(posedge write)
begin
	ram[addr]<=data;
end
endmodule
ROM
module rom( data, addr, read, ena );
output [7:0] data;
input [12:0] addr;
input read, ena;
reg [7:0] memory [13‘h1fff:0];
wire [7:0] data;

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

endmodule

ROM用于装载测试程序,可读不可写。RAM用于存放数据,可读可写。

三、RISC CPU中各部件的相互连接关系

四、RISC CPU和它的外围电路

五、RISC CPU的寻址方式和指令系统

RISC_CPU的指令格式一律为:

指令系统仅由8条指令组成:

  • 1) HLT 停机操作。该操作将空一个指令周期,即8个时钟周期。
  • 2) SKZ 为零跳过下一条语句。该操作先判断当前alu中的结果是否为零,若是零就跳过下一条语句,否则继续执行。
  • 3) ADD 相加。该操作将累加器中的值与地址所指的存储器或端口的数据相加,结果仍送回累加器中。
  • 4) AND 相与。该操作将累加器的值与地址所指的存储器或端口的数据相与,结果仍送回累加器中。
  • 5) XOR 异或。该操作将累加器的值与指令中给出地址的数据异或,结果仍送回累加器中。
  • 6) LDA 读数据。该操作将指令中给出地址的数据放入累加器。
  • 7) STO 写数据。该操作将累加器的数据放入指令中给出的地址。
  • 8) JMP 无条件跳转语句。该操作将跳转至指令给出的目的地址,继续执行。

RISC_CPU是8位微处理器,一律采用直接寻址方式,即数据总是放在存储器中,寻址单元的地址由指令直接给出。这是最简单的寻址方式。

六、RISC CPU的操作和时序

一个微机系统为了完成自身的功能,需要CPU执行许多操作。以下是RISC_CPU的主要操作:

  • 1.系统的复位和启动操作
  • 2.总线读操作
  • 3.总线写操作

下面详细介绍一下每个操作:

1.系统的复位和启动操作

RISC_CPU的复位和启动操作是通过rst引脚的信号触发执行的。当rst信号一进入高电平,RISC_CPU就会结束现行操作,并且只要rst停留在高电平状态,CPU就维持在复位状态。在复位状态,CPU各内部寄存器都被设为初值,全部为零。数据总线为高阻态,地址总线为0000H,所有控制信号均为无效状态。rst回到低电平后,接着到来的第一个fetch上升沿将启动RISC_CPU开始工作,从ROM的000处开始读取指令并执行相应操作。波形图如下图所示。虚线标志处为RISC_CPU启动工作的时刻。

RISC_CPU的复位和启动操作波形

2.总线读操作

每个指令周期的前0--3个时钟周期用于读指令,在状态控制器一节中已详细讲述,这里就不再重复。第3.5个周期处,存储器或端口地址就输出到地址总线上,第4--6个时钟周期,读信号rd有效,数据送到数据总线上,以备累加器锁存,或参与算术、逻辑运算。第7个时钟周期,读信号无效,第7.5个周期,地址总线输出PC地址,为下一个指令做好准备。

CPU从存储器或端口读取数据的时序

3写总线操作

每个指令周期的第3.5个时钟周期处,写的地址就建立了,第4个时钟周期输出数据,第5个时钟周期输出写信号。至第6个时钟结束,数据无效,第7.5时钟地址输出为PC地址,为下一个指令周期做好准备。

原文地址:http://blog.csdn.net/ce123_zhouwei/article/details/7180066

时间: 2024-11-13 16:19:37

基于状态机的简易RISC CPU设计的相关文章

基于模型机的Micro cpu设计

第一章    模型机基本结构 由功能分析, 本次组成原理实验中设计的模型机包含下面这些部件:算术逻辑运算部件(ALU).程序计数器(PC).指令寄存器(IR).存储器(RAM).时序和微程序控制部件.模型机的数据通路为单总线结构,总线宽度为8位. 第二章    设计思想 1.基于状态机的模型机 如图1所示,整体模型机的设计采用了状态机的思想,将cpu的取指令.指令译码.指令执行所对应的操作拆分到各个状态中,并由此设计模型机的微操作. 图1 - 时钟控制信号状态机模型示意图 2.周期.节拍.脉冲制

论5级流水32bit risc cpu设计

前段时间用verilog写了一个32bit的risc cpu,五级流水,下板调试已经完全可用,准备后期加入浮点运算器,因为最近事情超级多,因此暂时先把RTL图传上来供大家参考,后面我会讲具体怎么设计.希望大家多多关注 :)

基于Spring的简易SSO设计

通常稍微规模大一些的企业,内部已经有很多的应用系统,多个系统整合首先要解决的便是“统一登录(SSO)”问题,之前写过一篇 利用Membership实现SSO(单点登录) ,java环境下已经有一些开源的成熟sso项目(比如CAS),但如果觉得CAS太麻烦,想自己再造轮子重复发明一个,可以参考下面的思路:(仍然是基于Cookie的实现,只不过安全性上略有加强,cookie端存放的token标识,不再与用户名.密码等这些敏感信息相关) 1.组件图 主要由3大部分组成, 1.1 SSO Client

基于Android 平台简易即时通讯的研究与设计[转]

摘要:论文简单介绍Android 平台的特性,主要阐述了基于Android 平台简易即时通讯(IM)的作用和功能以及实现方法.(复杂的通讯如引入视频音频等可以考虑AnyChat SDK~)关键词:Android 平台:即时通讯 (本文中图表点击附件即可见) 1 Android 平台简介Android 是Google 公司于2007年11月5日推出的手机操作系统,经过2年多的发展,Android平台在智能移动领域占有不小的份额,由Google为首的40 多家移动通信领域的领军企业组成开放手机联盟(

基于Android平台简易即时通讯的研究与设计

1 Android平台简介 Android是Google公司于2007年11月5日推出的手机操作系统,经过2年多的发展,Android平台在智能移动领域占有不小的份额,由Google为首的40多家移动通信领域的领军企业组成开放手机联盟(OHA).Google与运营商.设备制造商.开发商和其他第三方结成深层次的合作伙伴关系,希望通过建立标准化.开放式的移动电话软件平台,在移动产业内形成一个开放式的生态系统.正因如此,Android正在被越来越多的开发者和使用者所接受.近日,Google发言人Ant

基于JAVA的邮件客户端的设计和实现

获取项目源文件,技术交流与指导联系Q:1225467431 摘  要 Java是Sun Microsystem公司推出的新一代面向对象和面向网络的程序设计语言,特别适合于Internet/Intranet上的应用软件开发,因此也把Java语言称为新一代网络程序设计语言.Java语言将面向对象.多线程.安全和网络等特征集于一身,为软件开发人员提供了很好的程序设计环境,当今企业级计算和应用中相当成熟和稳定的平台,在这个领域中不可否认地占据着领导地位.JBuilder是Borland公司推出的Java

CCS2.2基于软件仿真简易教程(汇编)

CCS2.2基于软件仿真简易教程(汇编) Rev 1.0 Writer Nirvana Silence 配置目标芯片 打开此图标 导入配置,生成gel文件,导入点击close 然后关闭 保存changes 启动工程软件 新建工程.asm文件,添加到工程 新建文件 保存为汇编格式 添加到工程 编写程序,编译程序,load程序 在新建的ASM文件中输入以下程序,查看运行后(1030H).(1040H).*AR3,AR4的值 记得助记符前面至少要有一个空格 编译 没有问题,load .out文件 打开

基于JAVA的简易在线聊天系统,觉得挺自豪的一个项目

项目做的比较多,最近,做的一个项目:基于JAVA的简易在线聊天系统,感觉挺自豪的. 这个项目应用JAVA编程语言实现基于网络的文本交互软件的设计和实现,达到多客户端收发文本消息的交互操作.通过服务器端多线程地监控客户端的登陆和退出,实时接收客户端发出的消息并定向发送到指定客户端,以实现在线实时文本消息传输功能:当服务器端运行时,客户端可以随时登陆和退出:客户端登陆时可以设置个人信息,包括用户名和密码:保持一定的系统稳定性,客户端与服务器端的连接稳定. 这个“基于JAVA的简易在线聊天系统”是我在

基于Linux的智能家居的设计(2)

1  系统整体设计方案 智能家居系统的是一个实时查询家庭的温湿度.照明控制.自己主动控制的设定.集家庭娱乐.智能安防为一体,大量数据快处理.可靠的系统,因此在硬件和软件上都有非常大的要求,因此在这里进行了多方面的考虑有下面两个实现方案: 方案一:利用STM32单片机作为手持终端的控制器,使用按键和12864液晶屏作为人机交互的接口.利用51单片机作为房子内部的电灯.空调.门禁等家电的控制器,利用串口实现STM32单片机和51单片机作为传输数据的通道.这个能够实现.可是.机械按键和12864在智能