数字前端设计——CPU设计(2)
作者:互联网
存储器与控制器(单周期CPU取指译码)
介绍
CPU的流程可分为取指、译码、执行、访存、回写(Instruction Fetch,Decode,Execution,Memory Request,Write Back)五阶段。实验一完成了执行阶段的ALU部分,并进行了简单的访存实验,本实验将实现取指、译码两个阶段的功能。
存储器和控制器的实验内容
依据取指、译码阶段的需求,分别需要实现以下模块:
1、PC:D触发器结构,用于储存PC(一个周期)。需实现2个输入,分别为clk,rst,分别连接时钟和复位信号;需实现2个输出,分别为pc,inst_ce,分别连接指令存储器的addra,ena端口。其中addra位数依据coe文件中指令数定义;
2、加法器:用于计算下一条指令地址,需实现2个输入,1个输出,输入值分别为当前指令地址PC、32’h4;
3、Controller:其中包含两部分:
a).main_decoder。负责判断指令类型,并生成相应的控制信号。需实现1个输入,为指令inst的高6位op,输出分为2部分,控制信号有多个,可作为多个输出,也作为一个多位输出,具体参照3进行设计;aluop,传输至alu_decoder,使alu_decoder配合inst低6位funct,进行ALU模块控制信号的译码。
b).alu_decoder。负责ALU模块控制信号的译码。需实现2个输入,1个输出,输入分别为funct,aluop;输出位alucontrol信号。
c).除上述两个组件,需设计controller文件调用两个decoder,对应实现op.funct输入信号,并传入调用模块;对应实现控制信号及alucontrol,并连接至调用模块相应端口。
4、指令存储器:使用Block Memory Generator IP构造。
注意:Basic中Generate address interface with 32 bits 选项不选中;PortA Options中Enable Port Type 选择为Use ENA Pin
5、时钟分频器:将板载100Mhz频率降低为1hz,连接PC、指令存储器时钟信号clk。
实验要求
取值阶段原理
PC为32bit(1word)的寄存器,其存放指令地址,每条指令执行完毕后,增加4,即为下一条指令存放地址。指令地址传入指令存储器,即可取出相应地址存放的指令。
(注意:MIPS架构中,采用字节读写,132bit word=4byte,故需要地址+4来获取下一条指令)
取指译码原理
32位MIPS指令在不同类型指令中分别有不同结构。但[31:16]表示的opcode,以及[5:0]表示的funct,为译码阶段明确指令控制信号的主要字段。表3为opcode及funct 识别得到的部分信号。
opcode | aluop | operation | funct | alu function | alucontrol |
---|---|---|---|---|---|
lw | 00 | Load word | XXXXXX | Add | 010 |
sw | 00 | Store word | XXXXXX | Add | 010 |
beq | 01 | Branch equal | XXXXXX | Subtract | 110 |
R-type | 10 | add | 100000 | Add | 010 |
R-type | 10 | subtrate | 100010 | Subtract | 110 |
R-type | 10 | and | 100100 | And | 000 |
R-type | 10 | or | 100101 | Or | 001 |
R-type | 10 | set-on-less-than | 101010 | SLT | 111 |
依据取指译码原理图,ALU control代码如下:
module alu_dec (
input wire [5:0] funct,
input wire [1:0] aluop,
output wire [2:0] alucontrol
);
assign alucontrol = (aluop == 2'b00)? 3'b010://lw sw
(aluop == 2'b01)? 3'b110://beq
(aluop == 2'b10)?
(funct == 6'b100000) ? 3'b010 :// add
(funct == 6'b100010) ? 3'b110 :// sub
(funct == 6'b100100) ? 3'b000 :// and
(funct == 6'b100101) ? 3'b001 :// or
(funct == 6'b101010) ? 3'b111 ://slt
3'b000 : 3'b000;
endmodule
依据取指译码原理图,main_Decoder代码如下:
module maindec(
input wire[5:0] op,
output wire memtoreg,memwrite,
output wire branch,alusrc,
output wire regdst,regwrite,
output wire jump,
output wire[1:0] aluop
);
reg[8:0] controls;
assign {regwrite,regdst,alusrc,branch,memwrite,memtoreg,jump,aluop} = controls;
always @(*) begin
case (op)
6'b000000:controls <= 9'b110000010;//R-TYRE
6'b100011:controls <= 9'b101001000;//LW
6'b101011:controls <= 9'b001010000;//SW
6'b000100:controls <= 9'b000100001;//BEQ
6'b001000:controls <= 9'b101000000;//ADDI
6'b000010:controls <= 9'b000000100;//J
default: controls <= 9'b000000000;//illegal op
endcase
end
endmodule
控制器实现原理
控制器输出的控制信号,用于控制器件的使能和多路选择器的选择,因此,根据不同指令的功能分析其所需要的路径,即可得到信号所对应的值。在此之前,参照下表对各个控制信号的含义进行理解。
信号 | 含义 |
---|---|
memtoreg | 回写的数据来自于ALU计算的结果/存储器读取的数据 |
memwrite | 是否需要写数据存储器 |
pcsrc | 下一个PC值是PC+4/跳转的新地址 |
alusrc | 送入ALUB端口的值是立即数的32位扩展/寄存器堆读取的值 |
regdst | 写入寄存器堆的地址是rt还是rd,0为rt,1为rd是否需要写寄存器堆 |
regwrite | 是否为branch指令,且满足branch的条件 |
branch | 是否为jump指令 |
jump | ALU控制信号,代表不同的运算类型 |
分析数据通路图,判断指令是否需要写寄存器、访存等等操作,以产生相应的控制信号。下面给出参考信号表:
instruction | op[5:0] | regwrite | regdst | alusrc | branch | memtoreg | aluop[1:0] |
---|---|---|---|---|---|---|---|
R-type | 000000 | 1 | 1 | 0 | 0 | 0 | 10 |
lw | 100011 | 1 | 0 | 1 | 0 | 1 | 00 |
sw | 101011 | 0 | X | 1 | 0 | X | 00 |
beq | 000100 | 0 | X | 0 | 1 | X | 01 |
addi | 001000 | 1 | 0 | 1 | 0 | 0 | 00 |
j | 000010 | 0 | X | X | X | X | XX |
依据取指译码原理图,Controller代码如下:
module controller(
input wire[5:0] op,funct,
input wire zero,
output wire memtoreg,memwrite,
output wire pcsrc,alusrc,
output wire regdst,regwrite,
output wire jump,
output wire[2:0] alucontrol
);
wire[1:0] aluop;
wire branch;
maindec md(op,memtoreg,memwrite,branch,alusrc,regdst,regwrite,jump,aluop);
aludec ad(funct,aluop,alucontrol);
assign pcsrc = branch & zero;
endmodule
这篇笔记参考网上众多资料实验并整理而成,如果涉及侵权烦请请告知,我将第一时间处理。
标签:aluop,wire,funct,前端,译码,指令,output,设计,CPU 来源: https://blog.csdn.net/qq_40051553/article/details/121180957