32位单周期CPU
11条指令的功能
每条指令的第一步都是取指令并PC加4,故除了第一行均省略了
指令集
基本形式
31-26 | 25-21 | 20-16 | 15-11 | 10-6 | 5-0 |
---|---|---|---|---|---|
op(6bits) | rs(5bits) | rt(5bits) | rd(5bits) | shamt(bits) | funct(6bits) |
op | rs | rt | immediate(16bits) | ||
op | target address(26bits) |
11条指令:
指令 | 对应的码 |
---|---|
add | 000000_rs_rt_rd_shamt_100000 |
sub | 000000_rs_rt_rd_shamt_100010 |
subu | 000000_rs_rt_rd_shamt_100011 |
slt | 000000_rs_rt_rd_shamt_101010 |
sltu | 000000_rs_rt_rd_shamt_101011 |
ori | 000001_rt_rs_imm |
addiu | 001000_rt_rs_imm |
lw | 100011_rt_rs_imm |
sw | 101011_rt_rs_imm |
beq | 000100_rs_rt_imm |
j | 000010_addr |
CPU内部的控制信号
变量名 | 含义 |
---|---|
MemToReg | 表明是否从Memory中读取数据并写入Reg,1表示是 |
MemWrite | 是否写内存,1表示是 |
Branch | 分支跳转,将PC更新为计算得出的地址,与ALU输出的Zero配合使用 |
AluSrc | ALU第二个操作数的来源,1为立即数,0为寄存器(rt) |
RegDst | 目的寄存器的选取,1选取rt,0为rd |
RegWrite | 是否写寄存器,1表示是 |
jump | 表明是直接跳转,使用特定的PC更新方式 |
PCsrc | PCsrc=branch&zero,为1时进行分支跳转 |
指令 | OpCode | RegWrite | RegDst | ALUSrc | Branch | MemWrite | MemtoReg | ALUOp |
---|---|---|---|---|---|---|---|---|
R-TYPE | 000000 | 1 | 1 | 0 | 0 | 0 | 0 | 10 |
lw | 100011 | 1 | 0 | 1 | 0 | 0 | 1 | 00 |
sw | 101011 | 0 | X | 1 | 0 | 1 | X | 00 |
beq | 000100 | 0 | X | 0 | 1 | 0 | X | 01 |
addiu | 001000 | 1 | 0 | 1 | 0 | 0 | X | 00 |
ori | 000001 | 1 | 0 | 1 | 0 | 0 | X | 00 |
j | 000010 | 0 | X | 0 | 0 | 0 | 0 | 00 |
注意到lw和sw都需要用到ALU的addu,则可直接根据ALUOp将ALUcth设定为addu
同理,beq拥有唯一的ALUop码01,则可将ALUOp的01对应到sub(相等则Zero置1)
各部件代码
数据通路如图所示:
0.Registers
module Registers(
input clk,
input RegWr, //写使能
input [4:0]Reg1,
input [4:0]Reg2,//读取的两个数据rs,rt,5bits
input [4:0]RegWrite,//被写的寄存器,rd
input [31:0]DataWrite,//写用的数据
output [31:0]Data1,
output [31:0]Data2 //读出的两个数据
);
logic [31:0]RegFile[31:0]; //1024KB,每位32bits
assign RegFile[0] = 32'b0;//0号寄存器恒为0
always @ (posedge clk)
if(RegWr==1&&RegWrite!=0)
begin
RegFile[RegWrite]<=DataWrite;
end
//rd判断,如果rd不为0,则说明需要写入
assign Data1= RegFile[Reg1];
assign Data2 = RegFile[Reg2];
//输出两个寄存器中的值
endmodule
1.DataMemory
module DataMemory(
input logic clk,
input logic MemWr,
input logic [31:0] DataIn,
input logic [31:0] address,
output logic [31:0] DataOut
);
logic [31:0] RAM[63:0];//32*64的内存
assign DataOut=RAM[address[31:2]];//4bits对齐,读取数据
always_ff@(posedge clk)
if(MemWr) RAM[address[31:2]]<= DataIn;//内存写使能为1,则进行写
endmodule
2.imem(指令集)
module imem(
input logic[5:0] address,//0—31
output logic[31:0] out
);//用于读取一条指令
logic [31:0] RAM[63:0];
initial
begin
$readmemh("data.dat",RAM);
end
assign out=RAM[address];
endmodule
3.MainDec(主译码器)
module MainDec(
input logic[5:0]op,//传入指令op码,解码出各个控制关系
output logic MemToReg,MemWrite,//MemToReg为1则从Memory中读取数据,并写入Reg;MemWrite表示写内存
output logic Branch,AluSrc,// Branch表明是分支跳转,将PC更新为计算得出的地址;ALU第二个操作数的来源,为1则为立即数
output logic RegDst,RegWrite,//目的寄存器的选取,为1选取rt,为0选取rd;写寄存器使能
output logic jump,//表明是直接跳转,使用特定的PC更新方式
output logic [1:0] ALUop//ALUop码,具体的运算方式需要结合func来确定
);
logic [8:0] controls;
assign {RegWrite,RegDst,AluSrc,Branch,MemWrite,MemToReg,jump,ALUop} = controls;
always_comb
case(op)
6'b000000:controls<=9'b110000010;//RTYPE
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
6'b000001:controls<=9'b101000011;//ORI
default: controls<=9'bxxxxxxxxx;//illegal op
endcase
endmodule
4.ALUdec(ALU译码器)
module ALUdec(
input logic [5:0] funct,
input logic [1:0] ALUop,
output logic [2:0] ALUcontrol
);
always_comb
case(ALUop)
2'b00:ALUcontrol<=3'b010;//addu (for lw/sw/addi)
2'b01:ALUcontrol<=3'b110;//subu (for beq)
2'b11:ALUcontrol<=3'b001;//or (for ori)
default:case(funct) //R-type
6'b100000:ALUcontrol<=3'b010;//addu
6'b100111:ALUcontrol<=3'b101;//add
6'b100010:ALUcontrol<=3'b110;//subu
6'b100011:ALUcontrol<=3'b100;//sub
6'b100100:ALUcontrol<=3'b000;//and
6'b100101:ALUcontrol<=3'b001;//or
6'b101010:ALUcontrol<=3'b111;//slt
6'b101011:ALUcontrol<=3'b011;//sltu
default: ALUcontrol<=3'bxxx;//?
endcase
endcase
endmodule
5.Controller
module Controller(
input logic[5:0]op,
input logic[5:0]funct,
input logic zero,
output logic MemToReg,MemWrite,
output logic PCsrc,ALUsrc,
output logic RegDst,RegWrite,
output logic jump,
output logic [2:0] ALUctr
);
//用于将输入的指令转换为控制信号
logic[1:0]ALUop;
logic branch;
MainDec MD(op,MemToReg,MemWrite,branch,ALUsrc,RegDst,RegWrite,jump,ALUop);
ALUdec AD(funct,ALUop,ALUctr);
assign PCsrc= branch & zero;
6.DataPath(数据通路)
module DataPath(
input logic clk,reset,
input logic MemToReg,PCsrc,
input logic ALUsrc,RegDst,
input logic RegWrite,jump,
input logic[2:0] ALUcontrol,
output logic Zero,
output logic OF,
output logic SF,
output logic [31:0] PC,
input logic [31:0] Instr,
output logic [31:0] ALUout,WriteData,
input logic [31:0] ReadData
);
logic [4:0] WriteReg;
logic[31:0] PCnext,PCnextBr,PCplus4,PCbranch;
logic[31:0] signimm,signimmsh;
logic[31:0] srcA,srcB;
logic[31:0] result;
//计算下一个PC地址
flopr#(32) PCreg(clk,reset,PCnext,PC);
Adder PCadd1(PC,32'b100,PCplus4);
sl2 immsh(signimm,signimmsh);
Adder PCadd2(PCplus4,signimmsh,PCbranch);
MUX2#(32) PCbrmux(PCplus4,PCbranch,PCsrc,PCnextBr);//branch分支跳转
MUX2#(32) PCmux(PCnextBr,{PCplus4[31:28],Instr[25:0],2'b00},jump,PCnext);//j跳跃
//寄存器文件逻辑
Registers rf(clk,RegWrite,Instr[25:21],Instr[20:16],WriteReg,result,srcA,WriteData);
MUX2 #(5) wrmux(Instr[20:16],Instr[15:11],RegDst,WriteReg);
MUX2 #(32) resmux(ALUout,ReadData,MemToReg,result);
SignExt se(Instr[15:0],signimm);
//ALU逻辑
MUX2#(32) srcBmux(WriteData,signimm,ALUsrc,srcB);
ALU alu(srcA,srcB,ALUcontrol,ALUout,Zero,OF,SF);
7.ALU
module ALU(
input [31:0] Data1,
input [31:0] Data2,
input [2:0] ALUctr,//7个操作
output logic [31:0] result,
output logic ZF,
output logic OF,
output logic SF
);
assign ZF =(result==0)?1:0;
assign SF =result[31];
always@(ALUctr or Data1 or Data2) //有效时运行
begin
case(ALUctr)
//add和sub的OF依然会计算,但是否使用取决于指令(是否判断溢出)
3'b010: begin result=Data1+Data2;OF = 0; end //addu
3'b101: begin result=Data1+Data2;OF = (Data1[31]==Data2[31])&&(Data1[31]!=result[31]); end //add
3'b001: begin OF=0;result = Data1|Data2; end // or
3'b000: begin OF=0;result = Data1&Data2; end // and
3'b110: begin result=Data1-Data2;OF=0;end //subu
3'b100: begin result=Data1-Data2;OF=(Data1[31]!=Data2[31])&&(Data2[31]==result[31]); end //sub
3'b011: begin OF=0;result= Data1<Data2 ; end //sltu
3'b111: begin OF=0;result=((Data1[31]==Data2[31])&&Data1<Data2)|(Data1[31]==1&&Data2[31]==0); end //slt
endcase
end
endmodule
8.flopr
//可复位触发器
module flopr #(parameter WIDTH=8)(
input logic clk,reset,
input logic [WIDTH-1:0] d,
output logic [WIDTH-1:0] q
);
always_ff@(posedge clk,posedge reset)
if(reset) q<=0;
else q<=d;
endmodule
9.Adder
module Adder(
input [31:0] a,b,
output [31:0] y
);
assign y = a+b;
endmodule
10.sl2
module sl2(
input logic[31:0] a,
output logic[31:0] y
);
assign y={a[29:0],2'b00};
endmodule
11.MUX2
module MUX2 #(parameter WIDTH=32)(
input logic[WIDTH-1:0]d0,
input logic[WIDTH-1:0]d1,
input logic s,//判断
output logic [WIDTH-1:0]y
);
assign y=s?d1:d0;//1则选择d1,0则选择d0
endmodule
12.SignExt
module SignExt(
input logic [15:0] a,
output logic [31:0] b
);
assign b = {{16{a[15]}},a};
endmodule
13.相关顶层文件
module Mips(
input logic clk,reset,
output logic [31:0] PC,
input logic [31:0] Instr,
output logic MemWrite,
output logic [31:0] ALUout,WriteData,
input logic [31:0] ReadData
);
logic MemToReg,ALUsrc,RegDst,RegWrite,jump,PCsrc,Zero,OF,SF;
logic [2:0] ALUcontrol;
Controller c(Instr[31:26],Instr[5:0],Zero,MemToReg,MemWrite,PCsrc,ALUsrc,RegDst,RegWrite,jump,ALUcontrol);
DataPath dp(clk,reset,MemToReg,PCsrc,ALUsrc,RegDst,RegWrite,jump,ALUcontrol,Zero,OF,SF,PC,Instr,ALUout,WriteData,ReadData);
endmodule
module CPU_top(
input clk,reset,
output [31:0] WriteData,DataAdr,//ALUout
output MemWrite
);
logic [31:0]PC,Instr,ReadData;
Mips mips (clk,reset,PC,Instr,MemWrite,DataAdr,WriteData,ReadData);
imem imem (PC[7:2],Instr);
DataMemory dm(clk,MemWrite,WriteData,DataAdr,ReadData);
endmodule
data.dat
# | Assembly | Address | Machine |
---|---|---|---|
main: | addi $2,$0,5 | 0 | 2002005 |
addi $3,$0,12 | 4 | 2003000c | |
addi $7, $3,-9 | 8 | 2067fff7 | |
or $4, $7, $2 | c | 00e22025 | |
and $5, $3, $4 | 10 | 00642824 | |
add $5, $5, $4 | 14 | 00a42820 | |
beq $5, $7,end | 18 | 10a7000a | |
slt $4, $3,$4 | 1c | 0064202a | |
beq $4, $0,around | 20 | 10800001 | |
addi $5, $0,0 | 24 | 20050000 | |
around: | slt $5,$7, $2 | 28 | 00e2202a |
add $7, $4, $5 | 2c | 00853820 | |
sub $7, $7, $2 | 30 | 00e23822 | |
sw $7,68($3) | 34 | ac670044 | |
lw $2, $80( $0) | 38 | 8c020050 | |
j end | 3c | 08000011 | |
addi $2, $0,1 | 40 | 20020001 | |
end: | sw $2,84($0) | 44 | ac020054 |