用小型的简化的CPU作为verilog的练习,一方面可以学习RISC_CPU的基本结构和原理,进而巩固学习计算机体系结构;另一面可以学习并掌握一些常用的Verilog语法和验证方法。
首先CPU运行的过程分为以下几个流程:1.取指令;2.分析指令;3.执行指令。进一步细化可以分为:1.对指令进行译码;2.可以进行算术和逻辑运算;3.能与存储器和外设交换数据;4.提供整个系统所需要的控制。对应地我们需要指令寄存器,指令译码器,算数逻辑运算部件(ALU),累加器,除此外,为了让整个系统run起来我们需要时序和控制部件,包括时钟发生器,数据控制器,状态控制器,程序计数器,地址多路器等。
1.时钟信号发生器:
用外来的时钟信号生成一系列的时钟信号:fetch,alu_ena。并分别送往地址多路器和状态控制器(fetch)以及算数逻辑运算单元(alu_ena)。fetch为控制信号,是clk得到8分频时钟信号。当fetch为为高电平,触发CPU开始执行一条指令。同时控制地址多路器和输出指令地址和数据地址。clk信号则作用于指令寄存器、累加器、状态控制器的时钟信号。ALU_ENA则用于控制算术逻辑运算。该模块程序如下:
input clk,reset;
output fetch,alu_ena;
wire clk,reset;
reg fetch,alu_ena;
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;
always@(posedge clk)
if(reset)
begin
fetch <= 0;
alu_ena <= 0;
state = idle;
end
else
begin
case(state)
S1:
begin
alu_ena <= 1;
state <= S2;
end
S2:
begin
alu_ena <= 0;
state <= S3;
end
S3:
begin
fetch <= 1;
state <= S4;
end
S4:
begin
state <= S5;
end
S5:
state <= S6;
S6:
state <= S7;
S7:
begin
fetch <= 0;
state <= S8;
end
S8:
begin
state <= S1;
end
idle:
state <= S1;
default:
state <= idle;
endcase
end
endmodule
2.指令寄存器
指令寄存器用于寄存指令,触发时钟为clk,在clk正触发正触发沿下,寄存器将数据总线送来的指令存入高8位或低8位的寄存器中,寄存的时机由CPU状态控制器的load_ir信号控制。每条指令分为两个字节,即16位,高3为操作码,低13位为地址(CPU的总线为13位,寻址空间为8K字节)。本设计的总线为8位,所以每条指令需要取两次,为了区别高8位和低8位,由变量state来记录,该模块的程序如下:
`timescale 1ns/1ns
module register(opc_iraddr,data,ena,clk,rst);
output [15:0] opc_iraddr;
input [7:0] data;
input ena,clk,rst;
reg [15:0] opc_iraddr;
reg state;
always@(posedge clk)
begin
if(rst)
begin
opc_iraddr <= 16'b0000_0000_0000_0000;
state <= 1'b0;
end
else
begin
if(ena)
begin
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'bxxxx_xxxx_xxxx_xxxx;
state <= 1'bx;
end
endcase
end
else
state <= 1'b0;
end
end
endmodule
3.累加器
累加器用于存放当前计算的结果。当累加器通过ena收到来自CPU状态控制器load_acc信号时,在时钟正沿就收到来自数据总线的数据。该模块的程序如下:
module