1.1.RISCV CPU概述
RISC-V(读作“RISC-FIVE”)是基于精简指令集计算(RISC)原理建立的开放指令集架构(ISA),V表示为第五代RISC(精简指令集计算机),表示此前已经四代RISC处理器原型芯片。由加州大学伯克利分校的David A. Patterson教授带领下完成。与大多数ISA相反,RISC-V ISA可以免费地用于所有希望的设备中,允许任何人设计、制造和销售RISC-V芯片和软件。它是第一个被设计成可以根据具体场景可以选择适合的指令集的指令集架构。基于RISC-V指令集架构可以设计服务器CPU,家用电器cpu,工控cpu和用在比指头小的传感器中的cpu。
1.2 RV32I 基本整数指令集RV32I
被设计成足以构建一个编译器目标机,并支持现代操作系统环境。这个 ISA 也被设计成在最小实现时减少所需的硬件。RV32I 包括了 47 条单独的指令,可以仿真几乎所有其他的 ISA 扩展。
1.3 基本指令格式
在所有格式中,RISC-V ISA将源寄存器rs1和rs2,和目标寄存器rd固定在同样的位置,以简化指令译码。在指令中,立即数imm被打包,朝着最左边可用位的方向,并且是分配好的,以减少硬件复杂度。所有立即数的符号位总是在指令的第31位,以加速符号扩展电路。 Opcode为指令操作码,每条指令都是由一个相应的opcode和对应的funct来定义。
1.4 计算机简单组成模型
计算机有三大组成部分,分别是,处理器(CPU)、输入输出(I/O)、存储器(Memory)。处理器从存储器中获取指令,然后按照指令执行一定的操作。输入/输出用来提供运算数据以及显示运算结果。
2.1 计算机组成原理的简单电路设计
本节将设计一个简化的处理器取指令电路,取指令模块为CPU其中一个组件,通过这个例子体会Verilog HDL的使用。处理器中的PC寄存器存储着指令地址,在正常运行过程中,PC的值会随着时间增加,同时从指令存储器中取出对应地址的指令。本次处理器取指电路包含两部分:PC模块、指令存储器ROM。
2.2 PC模块的设计和实现
PC模块的功能是给出取指令地址,同时每个时钟周期取指令地址递增。其接口设计如图所示。其左侧为输入右侧为输出。接口描述如表所示。
module pc_reg(
input wire clk,
input wire rst,
output reg[5:0] pc,
output reg ce
);
always @ (posedge clk) begin
if (ce == 1'b0) begin
pc <= 6'h00;
end else begin
pc <= pc + 1'b1;
end
end
always @ (posedge clk) begin
if (rst == 1'b1) begin
ce <= 1'b0;
end else begin
ce <= 1'b1;
end
end
endmodule
在时钟上升沿触发,如果rst使能,则使能信号ce为0,否则使能信号ce为1。当ce为1时pc寄存器开始在每个时钟上升沿时加1。
2.3 指令存储器ROM的设计与实现
指令存储器的作用是存储指令,并依据输入的地址,给出对应的指令。
module rom(
input wire ce,
input wire[5:0] addr,
output reg[31:0] inst
);
reg[31:0] rom[63:0];
initial $readmemh ( "rom.data", rom );
always @ (*) begin
if (ce == 1'b0) begin
inst <= 32'h0;
end else begin
inst <= rom[addr];
end
end
endmodule
使用二维向量定义存储器rom,深度是64,每个元素的宽度是32,因此addr取6位地址来构成2^6 = 64位的寄存器。在使能信号有效时,给出地址addr对应的指令,否则使能信号无效,给出数据0。$readmemh()为系统函数,用来读取data文件中的指令码并放入到rom中。
2.4 顶层模块
顶层模块将pc模块和rom模块进行例化如图所示
`
module inst_fetch(
input wire clk,
input wire rst,
output wire[31:0] inst_o
);
wire[5:0] pc;
wire rom_ce;
//pc_reg例化
pc_reg pc_reg0(
.clk(clk),
.rst(rst),
.pc(pc),
.ce(rom_ce)
);
rom rom0(
.ce(rom_ce),
.addr(pc),
.inst(inst_o)
);
endmodule`
顶层模块是将两个子模块进行例化。
2.5 编写TestBench
顶层模块只有两个输入,分别是rst和clk,对这两个输入信号设置激励,从而观察整个电路中各个寄存器中的数值。
module inst_fetch_tb;
reg CLOCK_50;
reg rst;
wire[31:0] inst;
initial begin
CLOCK_50 = 1'b0;
forever #10 CLOCK_50 = ~CLOCK_50;
end
initial begin
rst = 1'b1;
#195 rst= 1'b0;
#1000 $stop;
end
inst_fetch inst_fetch0(
.clk(CLOCK_50),
.rst(rst),
.inst_o(inst)
);
endmodule
3.1 仿真结果
首先编写一个后缀为.data的文件来存指令码如图所示
将写好的.v文件和.data文件导入Vivado,编译后点击Run Simulation查看仿真结果。