cpu设计和实现(取指)
创始人
2024-01-29 14:21:30
0

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        cpu设计的本质是数字电路的设计。要是没有verilog、vhdl这些语言,那么剩下来使用的方法基本只有卡诺图这一种了。在数字电路中,有两种基本的电路,一种是逻辑电路,一种是时序电路。两者的区别在于,逻辑电路随着输入而变化,而时序电路只有在时钟边沿触发的时候才能变化,其他时刻都会保持这一电路。

        听上去或许有一点拗口,我们可以通过一个示例代码来进行说明。假设有这么一个文件test.v,

module test(clk, rst, in, out_a, out_b);input wire clk;
input wire rst;
input wire in;output wire out_a;
output reg out_b;assign out_a = in;always@(posedge clk or posedge rst) beginif(rst) out_b <= 1'b0;else out_b <= in;
endendmodule

        从上面的代码可以看出来,有5个信号,3个是输入信号,2个是输出信号。输入信号中,一个时钟clk,一个复位rst,一个输入信号in。输出信号中,一个是组合逻辑输出out_a,一个时序逻辑输出out_b。对于时序逻辑out_b,可以看到在复位发生的时候,信号输出为0,其他时刻只有在时钟上升沿的时候,电路才会把信号in传递给out_b。

        为了测试test.v,我们需要编译一个激励模块test_tb.v,


`timescale 1ns/1ps
module test_tb();reg clock;
reg rst;
reg in;
wire out_a;
wire out_b;initial beginclock = 1'b0;forever #5 clock = ~clock;
endinitial beginrst = 1'b0;#1 rst = 1'b1;#11 rst = 1'b0;#1000 $stop;
endinitial beginin = 1'b1;#17 in  = 1'b0;#19 in  = 1'b1;#21 in  = 1'b0;
endtest test0(.clk(clock),.rst(rst),.in(in),.out_a(out_a),.out_b(out_b)
);initial
begin$dumpfile("hello.vcd");$dumpvars(0, test_tb);
endendmodule

        在激励模块中,我们定义了clk、rst、in,下面就观察out_a和out_b是如何变化的了。借助于iverilog和gtkwave工具,结果我们可以分析下,

        从上面的信号不难看出,out_a和in的信号是时刻保持一致的。而对于信号out_b而言,在复位这一段时间,一直保持在0的状态。等到复位结束之后,在第一个clk上升沿到来的时候,此时in处在1的状态,那么out_b翻转为1。接着,in又继续调整为0,但是此刻out_b具有记忆功能,并且只在clk上升沿到来的时候处理信号,所以out_b继续保持为1,直到下一个clk时刻发现in已经是0的情况下,才会跟随in调整为0。

        上面这段代码只是一个插曲。这段代码保存在github上,https://github.com/feixiaoxing/design_mips_cpu/tree/master/exercise。

        回归正题,今天讨论的主要是取指这个部分。顾名思义,那就应该有两个部分,一个是pc地址的生成,一个是rom指令的读取。本次代码主要参考了《自己动手写cpu》这本书,有兴趣的朋友可以找来看看。

        首先看一下pc_reg.v,


module pc_reg(input wire clk,input wire rst,output reg[5:0] pc,output reg ce
);always @(posedge clk)
beginif(rst == 1'b1) begince <= 1'b0;end else begince <= 1'b1;end
endalways @(posedge clk)
beginif(ce == 1'b0) beginpc <= 6'h00;end else  beginpc <= pc + 1'b1;end
endendmodule

         代码中主要有pc和ce两个寄存器。pc当然是指令地址的意思,而ce则是chip enable的意思。从代码上看,pc只有ce不是0的时候,才会开始自增。而ce变成1,需要等到rst结束之后的第一个clk上升沿才会变成1,因此pc也会顺延一个clk,才会开始地址自增。


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@(*)if(ce == 1'b0) begininst <= 32'h0;end else begininst <= rom[addr];endendmodule

        取指令这部分代码是组合逻辑的代码,这从always(*)可以看的出来。需要稍微注意的是其中initial的部分,在真实的asic芯片中,也会存在把一部分代码固化在chip上的情况。当然这里使用了readmemh读取指令文件,主要还是为了测试的方便。指令文件rom.data就是文本文件,

00000000
01010101
02020202
03030303
04040404
05050505

        准备好了pc_reg.v和rom.v之后,接下来就应该将二者组合在一起了,生成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_reg pc_reg0(.clk(clk),.rst(rst),.pc(pc),.ce(rom_ce));rom rom0(.ce(rom_ce),.addr(pc),.inst(inst_o));endmodule

        这部分的代码也不复杂,最主要的工作就是创建pc和rom_ce连线,这样可以将两个module示例串联在一起。当然,为了测试还需要编写一个激励模inst_fetch_tb.v,

`timescale 1ns/1ps
module inst_fetch_tb;reg clock;
reg rst;
wire[31:0] inst;initial beginclock = 1'b0;forever #10 clock = ~clock;
endinitial beginrst = 1'b1;#195 rst = 1'b0;#1000 $stop;
endinitial
begin$dumpfile("hello.vcd");$dumpvars(0, inst_fetch_tb);
endinst_fetch inst_fetch0(.clk(clock),.rst(rst),.inst_o(inst)
);endmodule

        激励模块中只要正常给出clk和rst即可,主要就是看输出的inst中,有没有和我们之前期望的一样,可以在inst寄存器当中出现rom.data保存的那些指令数据。如果有,则代表我们的设计是正确的。反之,则代表verilog代码还是有问题的。所有的这些文件都准备妥当之后,就可以用iverilog和gtkwave仿真测试了,

        从信号仿真来看,整个设计还是符合要求的。首先rst一直处于复位的时候,ce为0。等rst结束,ce在第一个clk上升沿的时候调整为1。ce调整为1后,pc在下一个clk上升沿的时候开始自增。此外,由于rom.v是一个组合逻辑,所以pc发生改变之后,inst立马就发生了变化。所以从一开始inst是0x00000000之后,随着pc的改变,指令也开始一个一个读进来了。

        大家可以自己试试,代码链接地址在这,

 https://github.com/feixiaoxing/design_mips_cpu/tree/master/rtl/day02

相关内容

热门资讯

文明互鉴破隔阂 对话交流凝共识   作者:凌胜利(外交学院国际关系研究所教授、北京对外交流与外事管理研究基地研究员)  7月10日至...
江苏产假多少天2022规定,国...   我们都说女性是最伟大的,尤其是妈妈,所以我们对女性都要尊重和保护。每个人女人生完孩子之后,身体都...
菜鸟驿站寄件收费表,2022菜...   菜鸟驿站是我们离不开的站点了,大家经常网购的话就知道了,一般快递都回放在菜鸟驿站。有时候寄件也会...
自己交五险一金一个月多少钱,个...   五险一金一般在我们工作之后,单位会给我们的福利。不过有些灵活就业的话,这个五险一金一般都是自己缴...
社保卡怎么激活银行卡功能?怎么...   当企业为我们缴纳社保后,当然激活后才能使用,社保对我们来说是非常重要的,在平时生活中也是经常会用...
上海社保查询个人账户缴费明细查...   社保每月都是要缴纳费用的,在生活中大家也是经常会用到,平时看病、拿药等都可以享受到社保的福利,当...
2022年退休人员养老金调整最...   很多人都盼着上海养老金今年的调整方案是怎样的,对养老金的信息是非常关注的。近日,很多城市的养老金...
个人自由跑腿接单软件排行榜,跑...   现如今,人们的生活水平提高了不少,各种各样便捷的生活app也出现在人们的视角里了,同城跑腿大家都...
公积金一年一提和对冲哪个好,提...   公积金是对我们买房子的时候有很大的用处,可以减轻我们的一些负担,可以用公积金占一定金额。所以,有...
社保卡补办需要什么材料,补办社...   俗话说:“不怕一万,就怕万一”,每个人就算是很小心,总会有不小心失神的时候,会不小心丢失自己的东...