注:单周期CPU设计请移步我的另一篇博文:
单周期CPU设计(Verilog)
(1) 认识和掌握多周期数据通路原理及其设计方法;
(2) 掌握多周期CPU的实现方法,代码实现方法;
(3) 编写一个编译器,将MIPS汇编程序编译为二进制机器码;
(4) 掌握多周期CPU的测试方法。
设计一个多周期CPU,该CPU至少能实现以下指令功能操作。需设计的指令与格式如下:
(说明:操作码按照以下规定使用,都给每类指令预留扩展空间,后续实验相同。)
多周期CPU指的是将整个CPU的执行过程分成几个阶段,每个阶段用一个时钟去完成,然后开始下一条指令的执行,而每种指令执行时所用的时钟数不尽相同,这就是所谓的多周期CPU。CPU在处理指令时,一般需要经过以下几个阶段:
(1) 取指令(IF):根据程序计数器pc中的指令地址,从存储器中取出一条指令,同时,pc根据指令字长度自动递增产生下一条指令所需要的指令地址,但遇到“地址转移”指令时,则控制器把“转移地址”送入pc,当然得到的“地址”需要做些变换才送入pc。
(2) 指令译码(ID):对取指令操作中得到的指令进行分析并译码,确定这条指令需要完成的操作,从而产生相应的操作控制信号,用于驱动执行状态中的各种操作。
(3) 指令执行(EXE):根据指令译码得到的操作控制信号,具体地执行指令动作,然后转移到结果写回状态。
(4) 存储器访问(MEM):所有需要访问存储器的操作都将在这个步骤中执行,该步骤给出存储器的数据地址,把数据写入到存储器中数据地址所指定的存储单元或者从存储器中得到数据地址单元中的数据。
(5) 结果写回(WB):指令执行的结果或者访问存储器中得到的数据写回相应的目的寄存器中。
实验中就按照这五个阶段进行设计,这样一条指令的执行最长需要五个(小)时钟周期才能完成,但具体情况怎样?要根据该条指令的情况而定,有些指令不需要五个时钟周期的,这就是多周期的CPU。
特别提示,图上增加IR指令寄存器,目的是使指令代码保持稳定,pc写使能控制信号PCWre,是确保pc适时修改,原因都是和多周期工作的CPU有关。ADR、BDR、ALUoutDR、DBDR四个寄存器不需要写使能信号,其作用是切分数据通路,将大组合逻辑切分为若干个小组合逻辑,大延迟变为多个分段小延迟。
相关部件及引脚说明:
PC机一台,BASYS 3 实验板一块,Xilinx Vivado 开发软件一套。
代码放的次序有点乱,实现模块的顺序可以参见我的实验过程设计,也就是第五部分!
// 顶层模块的实现
module Main(CLK, RST, outside_pc, ins, now_pc);
input CLK, RST;
input [31:0] outside_pc;
output [31:0] ins, now_pc;
parameter endReg = 5'b11111; // 31号寄存器
// 数据通路
wire [31:0] pc, pc0, pc4, i_IR, instruction, pcChoose3, pcChoose1, extendData, ALUResult, WriteData, ReadData1, ReadData2, DataOut;
wire [31:0] o_ADR, o_BDR, o_ALUout, i_ALUM2DR,i_ALUData1,i_ALUData2;
wire zero;
// 控制信号
wire [2:0] ALUOp;
wire [1:0] ExtSel, RegDst, PCSrc;
wire PCWre, IRWre, InsMemRW, WrRegData, RegWre, ALUSrcB, DataMemRW, DBDataSrc;
// 数据选择输出
wire [4:0] fiveChooseData;
wire [31:0] InputWriteData1;
// 引脚输出
assign ins = instruction;
assign now_pc = pc0;
PC PC(CLK, pc, PCWre, RST, outside_pc, pc0); // 添加了外部pc
PCAddFour PCAddFour(pc0, pc4);
InstructionMEM InstructionMEM(pc0, InsMemRW, i_IR); // 添加了外部pc
IR IR(i_IR, CLK, IRWre, instruction);
PCJump PCJump(pc0, instruction[25:0], pcChoose3);
DataSelector_3to1 DataSelector_3to1(endReg, instruction[20:16], instruction[15:11], RegDst, fiveChooseData);
RegFile RegFile(instruction[25:21], instruction[20:16], fiveChooseData, WriteData, RegWre, CLK, ReadData1, ReadData2);
ADR ADR(ReadData1, CLK, o_ADR);
BDR BDR(ReadData2, CLK, o_BDR);
SignExtend SignExtend(instruction[15:0], ExtSel, extendData);
DataSelector_2to1_sa DataSelector_2to1_1(o_ADR, instruction[10:6] , ALUSrcA, i_ALUData1);
DataSelector_2to1 DataSelector_2to1_2(o_BDR, extendData, ALUSrcB, i_ALUData2);
ALU ALU(i_ALUData1, i_ALUData2, ALUOp, zero, ALUResult);
ALUoutDR ALUoutDR(ALUResult, CLK, o_ALUout);
DataMEM DataMEM(o_BDR, o_ALUout, DataMemRW, DataOut);
DataSelector_2to1 DataSelector_2to1_3(ALUResult, DataOut, DBDataSrc, i_ALUM2DR);
DBDR DBDR(i_ALUM2DR, CLK, InputWriteData1);
DataSelector_2to1 DataSelector_2to1_4(pc4, InputWriteData1, WrRegData, WriteData);
PCAddImm PCAddImm(pc4, extendData, pcChoose1);
DataSelector_4to1 DataSelector_4to1(pc4, pcChoose1, ReadData1, pcChoose3, PCSrc, pc);
ControlUnit ControlUnit(instruction[31:26], CLK, RST, zero, PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcA, ALUSrcB, DataMemRW, DBDataSrc, ExtSel, RegDst, PCSrc, ALUOp);
endmodule
// PC模块的实现
// @param clk 时钟信号
// @param pcWre信号
// @param reset信号
// @param i_pc 输入的pc值
// @param o_pc 输出的pc值
// @param outside_pc ???
module PC(clk, i_pc, pcWre, reset, outside_pc, o_pc);
input wire clk, pcWre, reset;
input wire [31:0] i_pc, outside_pc;
output reg [31:0] o_pc;
always @(pcWre or reset) begin // 这里和单周期不太一样,存在延迟的问题,只有当pcWre改变的时候或者reset改变的时候再检测
// reset
if (reset) begin
o_pc = outside_pc;
end else if (pcWre) begin
o_pc = i_pc;
end else if (!pcWre) begin
o_pc = o_pc;
end
end
endmodule
// 实现PC递增
// @param i_pc 输入的pc值
// @param o_pc 输出的pc值
module PCAddFour(i_pc, o_pc);
input wire [31:0] i_pc;
output wire [31:0] o_pc;
assign o_pc[31:0] = i_pc[31:0] + 4;
endmodule
// 指令存储单元的实现
// @param InsMemRW 指令存储单元信号
// @param addr pc上指令的地址
// @param outside_pc 获取初始化的pc
// @param instruction 取得的指令
module InstructionMEM (addr, InsMemRW, instruction);
input InsMemRW;
input [31:0] addr;
output reg [31:0] instruction;
// 8位内存单元,每条指令的二进制代码占四个内存单元
reg [7:0] mem [0:127];
initial begin
//$readmemb("D:/Xilinx/VivadoProject/MulticycleCPU/instructions.txt", mem);
mem[0]=8'b11100000;
mem[1]=8'b00000000;
mem[2]=8'b00000000;
mem[3]=8'b00000010;
mem[4]=8'b11100111;
mem[5]=8'b11100000;
mem[6]=8'b00000000;
mem[7]=8'b00000000;
mem[8]=8'b00001000;
mem[9]=8'b00000001;
mem[10]=8'b00000000;
mem[11]=8'b00000100;
mem[12]=8'b00001000;
mem[13]=8'b00000010;
mem[14]=8'b00000000;
mem[15]=8'b00001000;
mem[16]=8'b11000000;
mem[17]=8'b01000010;
mem[18]=8'b00000000;
mem[19]=8'b00000000;
mem[20]=8'b00000000;
mem[21]=8'b01000001;
mem[22]=8'b00011000;
mem[23]=8'b00000000;
mem[24]=8'b00000100;
mem[25]=8'b01100001;
mem[26]=8'b00011000;
mem[27]=8'b00000000;
mem[28]=8'b11010000;
mem[29]=8'b01000011;
mem[30]=8'b11111111;
mem[31]=8'b11111110;
mem[32]=8'b01001000;
mem[33]=8'b00100001;
mem[34]=8'b00000000;
mem[35]=8'b00000001;
mem[36]=8'b01000000;
mem[37]=8'b01000001;
mem[38]=8'b00011000;
mem[39]=8'b00000000;
mem[40]=8'b00000000;
mem[41]=8'b01000000;
mem[42]=8'b00011000;
mem[43]=8'b00000000;
mem[44]=8'b01000100;
mem[45]=8'b01100010;
mem[46]=8'b00001000;
mem[47]=8'b00000000;
mem[48]=8'b01100000;
mem[49]=8'b00000010;
mem[50]=8'b00001000;
mem[51]=8'b10000000;
mem[52]=8'b10011000;
mem[53]=8'b00100010;
mem[54]=8'b00110000;
mem[55]=8'b00000000;
mem[56]=8'b10011000;
mem[57]=8'b01000001;
mem[58]=8'b00111000;
mem[59]=8'b00000000;
mem[60]=8'b10011100;
mem[61]=8'b00100110;
mem[62]=8'b00000000;
mem[63]=8'b00000001;
mem[64]=8'b10011100;
mem[65]=8'b11000111;
mem[66]=8'b00000000;
mem[67]=8'b00000001;
mem[68]=8'b11101000;
mem[69]=8'b00000000;
mem[70]=8'b00000000;
mem[71]=8'b00000001;
mem[72]=8'b11000100;
mem[73]=8'b01000100;
mem[74]=8'b00000000;
mem[75]=8'b00000000;
mem[76]=8'b11111100;
mem[77]=8'b00000000;
mem[78]=8'b00000000;
mem[79]=8'b00000000;
instruction = 0;
end
always @(addr or InsMemRW)
if (InsMemRW) begin
instruction[31:24] = mem[addr];
instruction[23:16] = mem[addr+1];
instruction[15:8] = mem[addr+2];
instruction[7:0] = mem[addr+3];
end
endmodule
// 用于临时存储指令的二进制形式
// @param i_data 输入的数据
// @param clk 时钟信号
// @param IRWre 输入IR的控制信号
// @param o_data 输出的数据
module IR(i_data, clk, IRWre, o_data);
input clk, IRWre;
input [31:0] i_data;
output reg[31:0] o_data;
always @(negedge clk) begin // 存在延迟的问题,所以用下降沿触发,对数据传输没有什么影响
if (IRWre) begin
o_data = i_data;
end
end
endmodule
// pc跳转调用子程序
// @param pc 执行该指令时pc的值
// @param i_addr 输入的地址
// @param o_addr 输出的地址
module PCJump(pc, i_addr, o_addr);
input [31:0] pc;
input [25:0] i_addr;
output reg[31:0] o_addr;
reg [27:0] mid; // 用于存放中间值
// 输出地址的前四位来自pc[31:28],中间26位来自i_addr[27:2], 后两位是0
always @(i_addr) begin
mid = i_addr << 2;
o_addr <= {pc[31:28], mid[27:0]};
end
endmodule
// 三选一数据选择器的实现
// @param A 输入1
// @param B 输入2
// @param C 输入3
// @param Control 选择器的控制信号
// @param Result 选择的结果
module DataSelector_3to1(A, B, C, Control, Result);
input [4:0] A, B, C;
input [1:0] Control;
output reg[4:0] Result;
always @(Control or A or B or C) begin
case(Control)
2'b00:Result = A;
2'b01:Result = B;
2'b10:Result = C;
default: Result = 0;
endcase
end
endmodule
// 寄存器组的实现
// @param rs 输入数据源1所在的寄存器号
// @param rt 输入数据源2所在的寄存器号
// @param rd 结果存储的寄存器号
// @param i_data 输入的数据
// @param RegWre 输入寄存器组的控制信号
// @param clk 时钟信号
// @param o_data_1 输出数据1
// @param o_data_2 输出数据2
module RegFile (rs, rt, rd, i_data, RegWre, clk, o_data_1, o_data_2);
input [4:0] rs, rt, rd;
input [31:0] i_data;
input RegWre, clk;
output [31:0] o_data_1, o_data_2;
reg [31:0] register [0:31];
initial begin
// 只需要确定零号寄存器的值就好,$0恒等于0
register[0] = 0;
end
assign o_data_1 = register[rs];
assign o_data_2 = register[rt];
always @(i_data or rd) begin
// rd != 0 是确保零号寄存器不会改变的作用
if ((rd != 0) && (RegWre == 1)) begin
register[rd] = i_data;
end
end
endmodule
// 切割数据通路
// @param i_data 输入的数据
// @param o_data 输出的数据
// @param clk 时钟信号
module ADR(i_data, clk, o_data);
input clk;
input [31:0] i_data;
output reg[31:0] o_data;
always @(posedge clk) begin
o_data = i_data;
end
endmodule
// 切割数据通路
// @param i_data 输入的数据
// @param o_data 输出的数据
// @param clk 时钟信号
module BDR(i_data, clk, o_data);
input clk;
input [31:0] i_data;
output reg[31:0] o_data;
always @(posedge clk) begin
o_data = i_data;
end
endmodule
// 符号扩展单元的实现
// @param i_num 输入的数据
// @param ExtSel 控制符号扩展单元的信号
// @param o_num 输出的数据
module SignExtend(i_num, ExtSel, o_num);
input [15:0] i_num;
input [1:0] ExtSel;
output reg[31:0] o_num;
initial begin
o_num = 0;
end
always @(i_num or ExtSel) begin
case(ExtSel)
// ExtSel 为00时,sa位扩展
2'b00: o_num <= {{27{0}}, i_num[10:6]};
// ExtSel 为01时,无符号立即数扩展
2'b01: o_num <= {{16{0}}, i_num[15:0]};
// ExtSel 为10时,有符号立即数扩展
2'b10: o_num <= {{16{i_num[15]}}, i_num[15:0]};
// 其它情况默认有符号立即数扩展
default: o_num <= {{16{i_num[15]}}, i_num[15:0]}; // 默认符号扩展
endcase
end
endmodule
// ALU A输入端口前二选一选择器实现
// @param A 输入1
// @param B 输入2
// @param Control 选择器的控制信号
// @param Result 结果
module DataSelector_2to1_sa(A, B, Control, Result);
input [31:0] A;
input [4:0] B;
input Control;
output [31:0] Result;
assign Result = (Control == 1'b0 ? A : {{27{0}}, B[4:0]});
endmodule
// 二选一数据选择器实现
// @param A 输入1
// @param B 输入2
// @param Control 选择器的控制信号
// @param Result 结果
module DataSelector_2to1(A, B, Control, Result);
input [31:0] A, B;
input Control;
output [31:0] Result;
assign Result = (Control == 1'b0 ? A : B);
endmodule
module ALU(A, B, ALUOp, zero, result);
input [31:0] A, B;
input [2:0] ALUOp;
output zero;
output reg [31:0] result;
initial begin
result = 0;
end
assign zero = (result? 0 : 1);
always @(A or B or ALUOp) begin
case(ALUOp)
3'b000: result = A + B;
3'b001: result = A - B;
3'b010: begin
if (A < B &&(( A[31] == 0 && B[31]==0) || (A[31] == 1 && B[31]==1))) result = 1;
else if (A[31] == 0 && B[31]==1) result = 0;
else if (A[31] == 1 && B[31]==0) result = 1;
else result = 0;
end
3'b011: result = (A < B ? 1 : 0);
3'b100: result = B << A;
3'b101: result = A | B;
3'b110: result = A & B;
3'b111: result = (~A & B) | (A & ~B);
default: result = 0;
endcase
end
endmodule
// 切割数据通路
// @param i_data 输入的数据
// @param o_data 输出的数据
// @param clk 时钟信号
module ALUoutDR(i_data, clk, o_data);
input clk;
input [31:0] i_data;
output reg[31:0] o_data;
always @(posedge clk) begin
o_data = i_data;
end
endmodule
// 数据存储器的实现
// @param i_data 输入的数据
// @param addr 输入的地址
// @param DataMemRW 输入数据存储器的信号,用1代表/WR信号,用0代表/RD信号,我将这两个信号合为一个
// @param o_data 读取的数据
module DataMEM (i_data, addr, DataMemRW, o_data);
input [31:0] i_data;
input [31:0] addr;
input DataMemRW;
output reg [31:0] o_data;
reg [7:0] memory [0:63];
initial begin
o_data = 0;
end
// 使用大端方式储存,这里有更改(不需要乘4)
always @(addr or i_data or DataMemRW) begin
if (DataMemRW) begin // 1 为 /WR
memory[addr] = i_data[31:24];
memory[addr+1] = i_data[23:16];
memory[addr+2] = i_data[15:8];
memory[addr+3] = i_data[7:0];
end else begin // 0 为 /RD
o_data[31:24] = memory[addr];
o_data[23:16] = memory[addr+1];
o_data[15:8] = memory[addr+2];
o_data[7:0] = memory[addr+3];
end
end
endmodule
// 切割数据通路
// @param i_data 输入的数据
// @param o_data 输出的数据
// @param clk 时钟信号
module DBDR(i_data, clk, o_data);
input clk;
input [31:0] i_data;
output reg[31:0] o_data;
always @(posedge clk) begin
o_data = i_data;
end
endmodule
// PC 加立即数
// @param now_pc 当前pc值
// @param o_pc 输出pc值
// @param imm 立即数
module PCAddImm(now_pc, imm, o_pc);
input [31:0] now_pc, imm;
output [31:0] o_pc;
// 内存单元是以字节为单位的,32位地址大小为4个字节,所以pc=pc+imm*4
assign o_pc = now_pc + (imm << 2);
endmodule
// 四选一数据选择器的实现
// @param A 输入1
// @param B 输入2
// @param C 输入3
// @param D 输入4
// @param Control 数据选择器的控制信号
// @param Result 选择的结果
module DataSelector_4to1(A, B, C, D, Control, Result);
input [31:0] A, B, C, D;
input [1:0]Control;
output reg[31:0] Result;
always @(Control or A or B or C or D) begin
case(Control)
2'b00: Result = A;
2'b01: Result = B;
2'b10: Result = C;
2'b11: Result = D;
default: Result = 0;
endcase
end
endmodule
// 控制单元CU的实现
// @param opcode 操作码
// @param zero 输入的zero信号
// @param clk 时钟信号
// @param reset 重置信号
// @param PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcB, DataMemRW, ALUM2Reg,ExtSel, RegOut, PCSrc,ALUOp 控制信号
module ControlUnit(opcode, clk, reset, zero, PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcA, ALUSrcB, DataMemRW, ALUM2Reg, ExtSel, RegOut, PCSrc, ALUOp);
input [5:0]opcode;
input zero, clk, reset;
output PCWre, InsMemRW, IRWre, WrRegData, RegWre,ALUSrcA, ALUSrcB, DataMemRW, ALUM2Reg;
output [1:0]ExtSel, RegOut, PCSrc;
output [2:0]ALUOp;
wire [2:0]i_state, o_state;
DFlipFlop DFlipFlop(i_state, reset, clk, o_state);
NextState NextState(o_state, opcode, i_state);
OutputFunc OutputFunc(o_state, opcode, zero, PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcA, ALUSrcB, DataMemRW, ALUM2Reg, ExtSel, RegOut, PCSrc, ALUOp);
endmodule
// D触发器的实现
// @param i_state 输入的状态,也就是下一个状态
// @param reset 重置信号
// @param clk 时钟信号
// @param o_state 输出的状态
module DFlipFlop(i_state, reset, clk, o_state);
input [2:0]i_state;
input reset, clk;
output reg[2:0]o_state;
always @(posedge clk) begin
if (reset) o_state = 3'b000;
else o_state = i_state;
end
endmodule
// NextState模块的实现
// @param i_state 输入的状态
// @param opcode 输入的操作码
// @param next_state 下一状态
module NextState(i_state, opcode, next_state);
input [2:0]i_state;
input [5:0]opcode;
output reg[2:0]next_state;
parameter [2:0] IF = 3'b000, // IF状态
ID = 3'b001, // ID状态
aEXE = 3'b110, // 第一条分支的EXE状态
bEXE = 3'b101, // 第二条分支的EXE状态
cEXE = 3'b010, // 第三条分支的EXE状态
MEM = 3'b011, // MEM状态
aWB = 3'b111, // 第一个分支的WB状态
cWB = 3'b100; // 第三个分支的WB状态
always @(i_state or opcode) begin
case (i_state)
IF: next_state = ID;
ID: begin
case (opcode[5:3])
3'b110: begin
if (opcode == 6'b110100) next_state = bEXE; // beq指令
else next_state = cEXE; // sw, lw指令
end
3'b111: next_state = IF; // j, jal, jr, halt指令
default: next_state = aEXE; // add, sub等指令
endcase
end
aEXE: next_state = aWB;
bEXE: next_state = IF;
cEXE: next_state = MEM;
MEM: begin
if (opcode == 6'b110001) next_state = cWB; // lw指令
else next_state = IF; // sw指令
end
aWB: next_state = IF;
cWB: next_state = IF;
default: next_state = IF;
endcase
end
endmodule
// NextState模块的实现
// @param i_state 输入的状态
// @param opcode 输入的操作码
// @param next_state 下一状态
module NextState(i_state, opcode, next_state);
input [2:0]i_state;
input [5:0]opcode;
output reg[2:0]next_state;
parameter [2:0] IF = 3'b000, // IF状态
ID = 3'b001, // ID状态
aEXE = 3'b110, // 第一条分支的EXE状态
bEXE = 3'b101, // 第二条分支的EXE状态
cEXE = 3'b010, // 第三条分支的EXE状态
MEM = 3'b011, // MEM状态
aWB = 3'b111, // 第一个分支的WB状态
cWB = 3'b100; // 第三个分支的WB状态
always @(i_state or opcode) begin
case (i_state)
IF: next_state = ID;
ID: begin
case (opcode[5:3])
3'b110: begin
if (opcode == 6'b110100) next_state = bEXE; // beq指令
else next_state = cEXE; // sw, lw指令
end
3'b111: next_state = IF; // j, jal, jr, halt指令
default: next_state = aEXE; // add, sub等指令
endcase
end
aEXE: next_state = aWB;
bEXE: next_state = IF;
cEXE: next_state = MEM;
MEM: begin
if (opcode == 6'b110001) next_state = cWB; // lw指令
else next_state = IF; // sw指令
end
aWB: next_state = IF;
cWB: next_state = IF;
default: next_state = IF;
endcase
end
endmodule
// 输出函数模块的实现
// @param state 当前状态
// @param opcode 操作码
// @param PCWre PC的控制信号
// @param InsMemRW 指令存储器的控制信号
// @param IRWre IR的控制信号
// @param WrRegData 控制寄存器组写数据端口的数据选择器
// @param RegWre 寄存器组的控制信号
// @param ALUSrcA 控制ALU的A输入端口的数据选择器
// @param ALUSrcB 控制ALU的B输入端口的数据选择器
// @param DataMemRW 数据存储器的控制信号
// @param DBDataSrc 控制数据存储器输出端口的数据选择器
// @param ExtSel 符号扩展单元的控制信号
// @param RegDst 控制寄存器组写寄存器端口的数据选择器
// @param PCSrc 四选一选择器的控制信号
// @param ALUOp ALU的控制信号
module OutputFunc(state, opcode, zero, PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcA, ALUSrcB, DataMemRW, DBDataSrc, ExtSel, RegDst, PCSrc, ALUOp);
input [2:0]state;
input [5:0]opcode;
input zero;
output reg PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcA, ALUSrcB, DataMemRW, DBDataSrc;
output reg[1:0]ExtSel, RegDst, PCSrc;
output reg[2:0]ALUOp;
parameter [2:0] IF = 3'b000, // IF状态
ID = 3'b001, // ID状态
aEXE = 3'b110, // 第一支路的EXE状态
bEXE = 3'b101, // 第二支路的EXE状态
cEXE = 3'b010, // 第三支路的EXE状态
MEM = 3'b011, // MEM状态
aWB = 3'b111, // 第一支路的WB状态
cWB = 3'b100; // 第三支路的WB状态
parameter [5:0] addi = 6'b000010,
ori = 6'b010010,
sll = 6'b011000,
add = 6'b000000,
sub = 6'b000001,
slt = 6'b100110,
slti = 6'b100111,
sw = 6'b110000,
lw = 6'b110001,
beq = 6'b110100,
j = 6'b111000,
jr = 6'b111001,
Or = 6'b010000,
And = 6'b010001,
jal = 6'b111010,
halt = 6'b111111;
always @(state) begin
// 对PCWre定值
if (state == IF && opcode != halt) PCWre = 1;
else PCWre = 0;
// 对InsMemRW定值
InsMemRW = 1;
// 对IRWre定值
if (state == IF) IRWre = 1;
else IRWre = 0;
// 对WrRegData定值
if (state == aWB || state == cWB) WrRegData = 1;
else WrRegData = 0;
// 对RegWre定值
if (state == aWB || state == cWB || opcode == jal) RegWre = 1;
else RegWre = 0;
// 对ALUSrcA定值
if (opcode == sll) ALUSrcA = 1;
else ALUSrcA = 0;
// 对ALUSrcB定值
if (opcode == addi || opcode == ori || opcode == slti|| opcode == sw || opcode == lw) ALUSrcB = 1;
else ALUSrcB = 0;
// 对DataMemRW定值
if (state == MEM && opcode == sw) DataMemRW = 1;
else DataMemRW = 0;
// 对 DBDataSrc定值
if (state == cWB) DBDataSrc = 1;
else DBDataSrc = 0;
// 对ExtSel定值
if (opcode == ori) ExtSel = 2'b01;
else if (opcode == sll) ExtSel = 2'b00;
else ExtSel = 2'b10;
// 对RegDst定值
if (opcode == jal) RegDst = 2'b00;
else if (opcode == addi || opcode == ori || opcode == lw) RegDst = 2'b01;
else RegDst = 2'b10;
// 对PCSrc定值
case(opcode)
j: PCSrc = 2'b11;
jal: PCSrc = 2'b11;
jr: PCSrc = 2'b10;
beq: begin
if (zero) PCSrc = 2'b01;
else PCSrc = 2'b00;
end
default: PCSrc = 2'b00;
endcase
// 对ALUOp定值
case(opcode)
sub: ALUOp = 3'b001;
Or: ALUOp = 3'b101;
And: ALUOp = 3'b110;
ori: ALUOp = 3'b101;
slt: ALUOp = 3'b010;
slti: ALUOp = 3'b010;
sll: ALUOp = 3'b100;
beq: ALUOp = 3'b001;
default: ALUOp = 3'b000;
endcase
// 防止在IF阶段写数据
if (state == IF) begin
RegWre = 0;
DataMemRW = 0;
end
end
endmodule
module cpu_sim;
// Inputs
reg CLK;
reg RST;
reg [31:0] outside_pc;
// Outputs
wire [31:0] ins, now_pc;
// Instantiate the Unit Under Test (UUT)
Main uut (
.CLK(CLK),
.RST(RST),
.outside_pc(outside_pc),
.ins(ins),
.now_pc(now_pc)
);
initial begin
// Initialize Inputs
CLK = 0;
RST = 1;
outside_pc = 0; // 这里设置外部pc
#50; // 刚开始设置pc为0
CLK = !CLK;
#50;
RST = 0;
forever #50 begin // 产生时钟信号
CLK = !CLK;
end
end
以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!