MIPS单周期CPU-Verilog
MIPS单周期CPU-Verilog
shikiMIPS单周期CPUVerilog设计
设计草稿
模块设计
mips
顶层模块,将各个模块连接,设置clk,reset输入端口。
PC
- 输入端口设置
- [31:0]imm:PC跳转值
- PCset:beq类PC跳转选择
- PCjump:J指令跳转选择
- clk:时钟信号
- reset:同步复位信号
- 输出端口设置
- [31:0]PCout:当前PC值
- 模块内部实现:根据PCset与PCjump选择PC寄存器值的变化行为,reset有效时PC寄存器值设置为0x3000。
- 部分代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16always @(posedge clk) begin
if (reset==1) begin
pc<=16'h3000;
end
else begin
if (PCset==1) begin
pc<=pc+4+imm;
end
else if (PCjump==1) begin
pc<=imm;
end
else begin
pc<=pc+4;
end
end
end
IM
- 输入端口:[31:0] pc
- 输出端口:[31:0] code
- 模块内部实现:设置32位寄存器数组Rom[0:4095]用于存放指令,根据pc值选择相应指令输出到code。
- 部分代码
1
2
3
4
5reg [31:0] Rom[0:12'd4095];
initial begin
$readmemh("code.txt",Rom);
end
assign code = Rom[(pc-16'h3000)>>2];
Control
根据输入的opcode和func判断当前指令为add,sub,ori,beq,lw,sw,jr,jal或lui,并据此判断各输出端口输出情况,具体如下表。
类型输出 | add | sub | ori | beq | lw | sw | jr | jal | lui |
---|---|---|---|---|---|---|---|---|---|
RegDst | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
ALUsrc | 0 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 0 |
MemtoReg | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
RegWrite | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 |
MemWrite | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
PCset | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
PCjump | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
EXTop | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
lui | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
PCtoReg | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
RegtoPC | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
ALUop | 00 | 01 | 10 | 11 | 00 | 00 | 00 | 00 | 00 |
- 部分代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15assign RegDst = ((opcode==`add&&func==`addfun)||(opcode==`sub&&func==`subfun));
assign ALUsrc = (opcode==`ori||opcode==`lw||opcode==`sw);
assign MemtoReg = (opcode==`lw);
assign RegWrite = ((opcode==`add&&func==`addfun)||(opcode==`sub&&func==`subfun)||opcode==`ori||opcode==`lw||opcode==`jal||opcode==`lui);
assign MemWrite = (opcode==`sw);
assign PCset = (opcode==`beq);
assign PCjump = (opcode==`jal||(opcode==`jr&&func==`jrfun));
assign EXTop = (opcode==`lw||opcode==`sw);
assign lui = (opcode==`lui);
assign PCtoReg = (opcode==`jal);
assign RegtoPC = (opcode==`jr&&func==`jrfun);
assign ALUop = ((opcode==`add&&func==`addfun)||opcode==`lw||opcode==`sw)?0:
((opcode==`sub&&func==`subfun))?1:
(opcode==`ori)?2:
(opcode==`beq)?3:0;
GRF
- 输入端口设置
- [4:0]A1:PD1输出对应寄存器地址
- [4:0]A2:PD2输出对应寄存器地址
- [31:0]WD:写入寄存器的值
- [4:0]A3:写入寄存器地址
- [31:0]pc:当前pc值,用于输出测试
- clk:时钟信号
- reset:同步复位信号
- WE:写使能信号
- 输出端口设置
- [31:0]PD1:A1寄存器对应值
- [31:0]PD2:A2寄存器对应值
- 模块内部实现
设置一32位寄存器数组grf[0:31]作为寄存器堆,reset有效时全部归零,若写使能信号有效则系统调用输出所需测试的信息,若A3!=0则写入到对应位置(0号寄存器恒为0)。 - 部分代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16always @(posedge clk) begin
if (reset==1) begin
for (i = 0;i<32 ;i=i+1 ) begin
grf[i]<=0;
end
end
else begin
if (WE==1) begin
if (A3!=0) begin
grf[A3]<=WD;
end
$display("@%h: $%d <= %h", pc, A3, WD);
end
end
end
assign PD1
EXT
- 输入端口设置
- EXTop:0时零扩展,1时符号扩展
- [15:0]input1:需要扩展的数
- 输出端口设置
- [31:0]output1:扩展后的数
- 根据上述信息实现即可
- 部分代码
1
2assign output1 = (EXTop == 1)?{{16{input1[15]}},input1}:
{{16{1'b0}},input1};
ALU
- 输入端口设置
- [31:0]input1:输入数
- [31:0]input2:输入数
- [1:0]op:为00时做加法,01时做减法,10时做或运算,11比较两个输入相等输出1,否则输出0
- 输出端口设置
- [31:0]output1:输出对应计算结果
- 根据上述信息实现即可
- 部分代码
1
2
3
4
5assign output1 = (op==0)?(input1+input2):
(op==1)?(input1-input2):
(op==2)?(input1|input2):
(op==3)?(input1==input2):
0;
DM
- 输入端口设置
- [13:0]addr:读写内存地址
- [31:0]W:写入内存的数据
- WR:读写控制信号,为1时写入,0时读出
- clk:时钟信号
- reset:同步复位信号
- [31:0]pc:当前pc值,用于输出测试数据
- 输出端口设置
- [31:0]out:读出内存的值
- 具体实现
使用一个8位寄存器数组Ram[0:0x3fff]作为内存,reset有效时所有内存清零,读写控制信号为1时,将addr,addr+4,addr+8,addr+12的寄存器值写为输入值,输出同理。 - 部分代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16always @(posedge clk) begin
if (reset==1) begin
for (i = 0;i<=14'h3fff ;i=i+1 ) begin
Ram[i]<=0;
end
end
else begin
if (WR==1) begin
Ram[addr] <= W[7:0];
Ram[addr+1] <= W[15:8];
Ram[addr+2] <= W[23:16];
Ram[addr+3] <= W[31:24];
$display("@%h: *%h <= %h", pc, {{18{1'b0}},addr}, W);
end
end
end
综合
根据模块信息及Control模块的输出信息进行端口选择,并将选择后的端口接入至其他模块
备注
Control各输出端口含义
- RegDst:有效时选择rd值作为GRF写入地址
- ALUsrc:有效时选择EXT输出值作为ALU其中一个输入,反之为寄存器输出其中一个输出值
- MemtoReg:有效时选择DM读出值作为寄存器写入值
- RegWrite:作为GRF写使能信号
- MemWrite:作为DM读写控制信号
- PCset:PC模块对应输入,有效时,若ALU输出结果为1则将imm符号扩展后左移2为的值作为PC模块输入。
- PCjump:PC模块对应输入,有效时将jump地址作为PC模块输入
- EXTop:EXT模块op端口输入
- lui:有效时选择imm加载到高位的值作为寄存器写入数据
- PCtoReg:有效时将PC值写入31号寄存器
- RegtoPC:有效时选择相应位置寄存器输出作为jump地址
- ALUop:作为ALU模块op端口输入