目录一、什么是CPU? 二、RISC CPU结构
三、RISC CPU中各部件的相互连接关系 四、RISC CPU和它的外围电路 五、RISC CPU的寻址方式和指令系统 六、RISC CPU的操作和时序 正文一、什么是CPU?CPU 即中央处理单元的英文缩写,它是计算机的核心部件。计算机进行信息处理可分为两个步骤:
将其功能进一步细化,可概括如下:
尽管各种CPU的性能指标和结构细节各不相同,但它们所能完成的基本功能相同。由功能分析,可知任何一种CPU内部结构至少应包含下面这些部件:
RISC 即精简指令集计算机(Reduced Instruction Set Computer)的缩写。它是一种八十年代才出现的CPU,与一般的CPU 相比不仅只是简化了指令系统,而且是通过简化指令系统使计算机的结构更加简单合理,从而提高了运算速度。从实现的途径看,RISC_CPU与一般的CPU的不同处在于:它的时序控制信号形成部件是用硬布线逻辑实现的而不是采用微程序控制的方式。所谓硬布线逻辑也就是用触发器和逻辑门直接连线所构成的状态机和组合逻辑,故产生控制序列的速度比用微程序控制方式快得多,因为这样做省去了读取微指令的时间。RISC_CPU也包括上述这些部件,下面就详细介绍一个简化的用于教学目的的RISC_CPU的可综合VerilogHDL模型的设计和仿真过程。 二、RISC CPU结构 RISC_CPU是一个复杂的数字逻辑电路,但是它的基本部件的逻辑并不复杂。可把它分成八个基本部件:
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; always@(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.数据控制器其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.地址多路器 其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.程序计数器其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.状态控制器 状态控制器由两部分组成:
状态控制器的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的值就是当前这个指令周期中已经过的时钟数(从零计起)。
状态机的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
|
|