敬请指正~
延迟语句可仿真不可综合
只能在仿真文件加延迟
单指令ori
赋值运算
指令的运行方式:取指令、执行指令循环
指令周期包含的阶段:
取指令IF
指令译码ID
指令执行EXE
存储器访问MEM【w/sw】
结果写回WB【结果保存到寄存器、存储器中】
IF
取指令两件事:取指令、PC+4
ID←ROM[PC]
PC←PC+4
虽然不是所有指令都是顺序执行【大部分是】,PC默认取下一条指令,如果遇到跳转指令再重新修改PC的值
PC+4拿出来【有一位空出来,默认为0
assign pc4 = pc + 4
PC+4在加法器实现:assign pc4 = addr + 4;
pcsource给执行信号默认00 00顺序执行 01 10 11跳转执行
4选一数据选择器,除了默认的顺序执行还有三种跳转情况
ID
A ← RegisterFile[rs]
B ← RegisterFile[rt]
C ← PC+sign_extend(offset)<<2
ID会根据指令产生opcode、func、rs、rd、rt、sa、imm和address信号
CU【控制单元】根据ID提供的opcode、func产生不同的控制信号,这些控制信号会控制寄存器堆、alu和ram执行不同的操作,它们一起协同工作来完成指令的功能。
OP:alu的运算选择 regWE:要不要写
//ID
module InstrumentDecoder(
input [31:0] instrument,
output reg [5:0] pocode,
output reg [5:0] func,
output reg[4:0] rs,
output reg[4:0] rt,
output reg[4:0] rd,
output reg[4:0] sa,
output reg[15:0] immediate,
output reg[25:0] addr
);
always @(*)
begin
opcode <= instrument[31:26]; //高六位固定
rs <= 5'b00000;
rt <= 5'b00000;
rd <= 5'b00000;
sa <= 5'b00000;
immediate <= 15'b0;
addr <= 25'b0;
case(opcode)
6'b000000: //R类型
begin
func <= instrument[5:0];
sa <= instrument[10:6];
rd <= instrument[15:11];
rt <= instrument[20:16];
rs <= instrument[25:21];
end
6'b001000, //I类型
6'b001100,
6'b001101,
6'b001110,
6'b100011,
6'b101011,
6'b000100,
6'b000101,
6'b001111: //前面的指令与此条执行相同的操作
begin
immediate <= instrument[15:0];
rt <= instrument[20:16];
rs <= instrument[25:21];
$monitor($time,,"rt==%b",rt);
end
6'b00010,6'b000011: //J类型
begin
addr <= instrument[25:0];
end
default:rs <= 5'b00000;
endcase
endmodule
//ControlUnit
module controlunit(
input [5:0] opcode, //MIPS指令类型
input [5:0] func, //MIPS指令功能码
input z, //是否为0标志
output reg[1:0] pcsource, //pc值得来源
output reg ram2reg, //是否将数据从ram中写入寄存器中
output reg ramWE, //是否写内存
output reg [3:0] aluOP,//alu得运算类型
output reg regWE, //是否写寄存器
output reg imm, //是否产生立即数
output reg shift, //是否移位
output reg isrt, //目的寄存器地址,=1选择rt,否则选择rd
output reg sign_ext, //立即数扩展,=1为符号扩展,否则为0扩展
output reg jal //是否调用子程序跳转
);
always @(*)
begin
//先设置好默认值
shift <= 1'b0;
ram2reg <= 1'b0;
ramWE <= 1'b0;
imm <= 1'b0;
isrt <= 1'b0;
sign_ext <= 1'b0;
pcsource <= 2'b00;
aluOP <= 4'b0000;
jal <= 1'b0;
case(op)
6'b000000:
begin
case(func)
6'b100000:
begin
aluOP <= 4'b0001;
regWE <= 1'b1;
end
6'b100010:
begin
aluOP <= 4'b0010;
regWE <= 1'b1;
end
6'b000010:
begin
pcsource <= 2'b11; //跳转指令
end
6'b000011:
begin
jal <= 1'b1; //调用指令
regWE <= 1'b1;
pcsource <= 2'b11;
end
EXE
ALU根据指令的不同做不同得工作
需要提供ALU得两个数据输入端和运算控制端【根据指令得类型来判断op/数据来源】
MEM
只有lw、sw指令进入存储器访问阶段MEM
不管是读内存还是写内存都必须有地址和数据
读内存是数据输出,写内存是数据输入