将陆续上传本人写的新书《自己动手写处理器》(尚未出版),今天是第八篇,我尽量每周四篇
2.7电路设计举例
本节将设计一个简化的处理器取指令电路,通过这个例子体会Verilog HDL的使用。
处理器内部一般有一个PC寄存器,其中存储指令地址,正常运行过程中,PC的值会随时间增加,同时从指令存储器中取出对应地址的指令。所以,本节实现的处理器取指令电路,包含两部分:PC模块、指令存储器。
1、PC模块的设计与实现
PC模块的功能就是给出取指令地址,同时每个时钟周期取指令地址递增。其接口设计如图2-13所示。采用左边是输入接口,右边是输出接口的方式绘制,这样便于理解。接口作用描述如表2-5所示。
此处定义指令地址pc的宽度为6,PC模块的主要代码如下,可以参考本书光盘Code\Chapter2目录下的pc_reg.v文件。
module pc_reg(
input wire clk,
input wire rst,
output reg[5:0] pc,
output reg ce
);
always @ (posedge clk) begin //在时钟信号上升沿触发
if (rst == 1'b1) begin
ce <= 1'b0; //复位信号有效的时候,指令存储器使能信号无效
end else begin
ce <= 1'b1; //复位信号无效的时候,指令存储器使能信号有效
end
end
always @ (posedge clk) begin //在时钟信号上升沿触发
if (ce == 1'b0) begin
pc <= 6'h00; //指令存储器使能信号无效的时候,pc保持为0
end else begin
pc <= pc + 1'b1; //指令存储器使能信号有效的时候,pc在每个时钟加1
end
end
endmodule
2、指令存储器ROM的设计与实现
指令存储器ROM的作用是存储指令,并依据输入的地址,给出对应地址的指令。其接口如图2-14所示,还是采用左边是输入接口,右边是输出接口的方式绘制,这样便于理解。接口描述如表2-6所示。
此处定义指令的宽度为32,指令存储器ROM的主要代码如下,可以参考在本书光盘Code\Chapter2目录下的rom.v文件。
module rom(
input wire ce,
input wire[5:0] addr,
output reg[31:0] inst
);
reg[31:0] rom[63:0]; //使用二维向量定义存储器
always @ (*) begin
if (ce == 1'b0) begin
inst <= 32'h0; //使能信号无效时,给出的数据是0
end else begin
inst <= rom[addr]; //使能信号有效时,给出地址addr对应的指令
end
end
endmodule
其中使用了一个二维向量定义存储器,深度是64,每个元素的宽度是32,这也是使用6位地址即可的原因。
3、顶层文件
先介绍元件例化的知识,在一个复杂电路的实现过程中,可以将其分割成多个功能单元分别实现,然后在一个顶层文件中通过调用各个功能单元,将其按照一定方式连接在一起,从而实现最终电路。其中调用功能单元的过程就称为元件例化。元件例化的格式如图2-15所示。
经过上面两步,我们分别实现了PC模块、指令存储器ROM,现在可以编写顶层文件将两者连接起来。连接方式如图2-16所示。
PC模块的输出pc连接到指令存储器ROM的地址接口addr,PC模块输出的使能信号ce连接到ROM的使能信号接口ce。顶层模块对应的模块名为inst_fetch,有三个接口,接口描述如表2-7所示。
inst_fetch模块的主要代码如下,其中例化了PC模块、指令存储器ROM。可以参考本书光盘Code\Chapter2目录下的inst_fetch.v文件。
module inst_fetch(
input wire clk,
input wire rst,
output wire[31:0] inst_o
);
wire[5:0] pc;
wire rom_ce;
//PC模块的例化
pc_reg pc_reg0(.clk(clk), .rst(rst),
.pc(pc), .ce(rom_ce));
//指令存储器ROM的例化
rom rom0( .ce(rom_ce), .addr(pc), .inst(inst_o));
endmodule
PC模块的输出pc、ROM模块的输入addr都连接到变量pc,所以两者连接在一起;PC模块的输出ce、ROM模块的输入ce都连接到rom_ce,所以两者连接在一起。这样就实现了图2-16所示的连接关系。
下一次将介绍如何仿真,未完待续!