Skip to content
This repository was archived by the owner on Jul 3, 2021. It is now read-only.

Commit 012bd8c

Browse files
committed
实现PUSH,POP,CALL,RET
1 parent becda8c commit 012bd8c

File tree

7 files changed

+1216
-7878
lines changed

7 files changed

+1216
-7878
lines changed

REGFILE.v

+7-4
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,23 @@ module REGFILE(
33
input wire [2:0] srcB,
44
output wire [7:0] A,
55
output wire [7:0] B,
6-
input wire [2:0] dstM,
7-
input wire [2:0] dstE,
6+
input wire [2:0] dstM, //M端口要写到哪个寄存器的地址
7+
input wire [2:0] dstE, //E端口要写到哪个寄存器的地址
88
input wire [7:0] M,
99
input wire [7:0] E,
1010
input wire clk
1111
);
1212

1313
reg [7:0] rf [0:7];
14-
assign A = (srcA==3'b000)? 8'h00 : rf[srcA]; //如果srcA是0必须返回一个零值
14+
15+
//读电路:
16+
assign A = (srcA==3'b000)? 8'h00 : rf[srcA]; //如果srcA是0必须返回一个零值(寄存器的地址是R0的地址,取出一个0值)
1517
assign B = (srcB==3'o0)? 8'h00 : rf[srcB]; //同上
1618

19+
//写操作:
1720
always @(posedge clk)
1821
begin
19-
if(dstM!=3'o0)
22+
if(dstM!=3'o0) //寄存器地址不能为0(不能往R0里面写)
2023
rf[dstM] <= M;
2124
if(dstE!=3'o0 && dstE!=dstM) //如果两个地址是同一个地址,需要有一个优先级(POP指令会涉及),令M端口优先(栈顶的值存入EXP中)
2225
rf[dstE] <= E;

TINYCPU.v

+51-24
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
`include "tinyCPU.h"
22

33
`define ins rom_data[23:20] // -> icode (ROM中高四位)
4-
`define fun rom_data[19:16] // -> ifun (ROM中低四位),功能码
4+
`define fun rom_data[19:16] // -> ifun (ROM中低四位),功能码,不需要的地方功能码为0
55
`define rA rom_data[14:12] //只用3位来表示Ra(一共8个寄存器,3位寻址)
66
`define rB rom_data[10:8] //只用3位
77
`define rC rom_data[6:4] //第三个字节高四位的低三位用来表示rC
@@ -21,40 +21,67 @@ module TINYCPU(
2121
input wire clk,rst_
2222
);
2323

24-
wire [7:0] valA,valB,valC,valP,valE,valM,aluB,new_pc;
24+
wire [7:0] valA,valB,valC,valP,valE,valM,aluA,aluB,new_pc;
2525
wire [1:0] cc;
2626
wire [2:0] dstE, dstM;
27-
27+
wire [2:0] val_rA, val_rB;
28+
//取指阶段
2829
PC pc( .new_pc(new_pc),.pc(rom_addr),.clk(clk),.rst_(rst_)); //实例化一个PC寄存器
29-
30-
assign valC = (`ins==`JXX && `fun==`JMP) ? rom_data[15:8] : rom_data[7:0]; //如果取出来了一个无条件转移指令,输出第二个字节,否则其他的是第三个字节
31-
30+
31+
//valC在其他指令中是第三个字节,在JMP中是第二个字节:
32+
assign valC = ((`ins==`JXX && `fun==`JMP)||`ins==`CALL)? rom_data[15:8]: rom_data[7:0]; //如果取出来了一个无条件转移指令,输出第二个字节,否则其他的是第三个字节
33+
//指令大部分为3字节指令,HLT和NOP是单字节,JMP是2字节。HLT为停机指令,不再增加。
3234
assign valP = rom_addr + ((`ins==`HLT )? 0:
33-
(`ins==`NOP )? 1:
34-
(`ins==`JXX && `fun==`JMP) ? 2:3); //下一条指令的地址
35+
(`ins==`NOP||`ins==`RET)? 1:
36+
((`ins==`JXX && `fun==`JMP)||`ins==`CALL)? 2: 3); //下一条指令的地址
37+
//译码阶段(从REGFILE中读操作数rA,rB,读出来的值传到valA和valB中)
38+
assign val_rA = (`ins==`POP)? `rB:
39+
(`ins==`RET)? 3'o7: `rA;
40+
assign val_rB = (`ins==`CALL||`ins==`RET)? 3'o7: `rB;
3541

36-
REGFILE regfile(.srcA(`rA),.srcB(`rB),.A(valA),.B(valB),.dstM(dstM),.dstE(dstE),.M(valM),.E(valE),.clk(clk) ); //实例化译码器,虽然全部读出来了但是不一定全都用,这样可以简化电路
37-
38-
assign aluB= (`ins==`LD||`ins==`ST||`ins==`OPI)?valC:valB; //状态信号
39-
40-
ALU alu(.A(valA),.B(aluB),.op(`fun),.E(valE),.cc(cc)); //实例化一个运算器
41-
//访存阶段:
42-
assign ram_addr=valE; //地址就是运算器输出的结果
43-
assign ram_wdat=valB;
44-
assign valM=ram_rdat; //从RAM读出来的值写到valM端口
45-
assign ram_rd_ = (`ins==`LD) ? 1'b0 : 1'b1; //LD命令,rd_信号有效
46-
assign ram_wr_ = (`ins==`ST) ? 1'b0 : 1'b1;
47-
//写回阶段:
48-
assign dstM = (`ins==`LD) ? `rB : 3'o0; //代替写使能信号,不是LD的话全写0,表示不写入寄存器
49-
assign dstE = (`ins==`OPR) ? `rC :
50-
(`ins==`OPI) ? `rB : 3'o0;
42+
//当`ins==`CALL时,regfile读出寄存器Ra的值赋值给valA,读出寄存器7的值赋值给valB
43+
//当`ins==`RET时,regfile读出寄存器7的值赋值给valA和valB
44+
//当`ins==`PUSH时,regfile读出寄存器Ra(操作数,存放进栈数据)的值赋值给valA,读出Rb(当前的栈顶指针)的值赋值给valB
45+
//当`ins==`POP时,regfile读出寄存器Rb(当前的栈顶指针)的值赋值给valA和valB
46+
47+
REGFILE regfile(.srcA(val_rA),.srcB(val_rB),.A(valA),.B(valB),.dstM(dstM),.dstE(dstE),.M(valM),.E(valE),.clk(clk) );
48+
//实例化译码器,虽然全部读出来了但是不一定都用(比如JMP就不用rB;比如LD中虽然有rA,rB,但是rB不是源操作数,应该是读出来的值应该写入的内存地址,即destM),这样可以简化电路
49+
//源操作数:用rA来选择A寄存器,rB来选择B寄存器
50+
//输出:A端口输出的信号为valA,B端口输出的信号为valB
51+
52+
//执行阶段
53+
assign aluA = (`ins==`PUSH||`ins==`POP||`ins==`CALL||`ins==`RET)? valB:valA;
54+
//如果是堆栈操作相关,传递进去栈顶指针
55+
assign aluB = (`ins==`LD||`ins==`ST||`ins==`OPI)? valC:
56+
(`ins==`PUSH||`ins==`POP||`ins==`CALL||`ins==`RET)? 8'b00000001: valB; //第二个操作数为常数(不为valB)的情况传入valC
57+
//如果为堆栈指令,执行栈顶指针加减1操作,如果是进栈fun为1,执行减一,否则加一
58+
ALU alu(.A(aluA),.B(aluB),.op(`fun),.E(valE),.cc(cc)); //实例化一个运算器
59+
//错误的代码(比如转移指令)也会使用ALU并计算出一个错误的结果,但是不会使用到,只有运算指令才会使用到ALU的结果
60+
//访存阶段(读写RAM):
61+
//只有LD和ST指令需要访存
62+
assign ram_addr=(`ins==`POP||`ins==`RET)? valA: valE; //地址就是运算器输出的结果
63+
assign valM=ram_rdat ; //从RAM读出来的值写到valM端口
64+
assign ram_rd_ = (`ins==`LD||`ins==`POP||`ins==`RET)? 1'b0: 1'b1; //读控信号,LD命令,rd_信号有效
65+
assign ram_wr_ = (`ins==`ST||`ins==`PUSH||`ins==`CALL)? 1'b0: 1'b1; //写控信号,ST命令,wr_信号有效
66+
//写回阶段:
67+
assign ram_wdat= (`ins==`PUSH)? valA:
68+
(`ins==`CALL)? valP: valB; //如果是写指令(ST)
69+
assign dstM = (`ins==`LD) ? `rB :
70+
(`ins==`POP)? `rA : 3'o0; //代替写使能信号,不是LD的话全写0,表示不写入寄存器
71+
assign dstE = (`ins==`OPR)? `rC :
72+
(`ins==`OPI) ? `rB :
73+
(`ins==`PUSH||`ins==`POP)? `rB:
74+
(`ins==`CALL||`ins==`RET)? 3'b111: 3'o0;
5175
//其他指令不应该修改寄存器内容
76+
//更新PC阶段:
5277
assign new_pc= (
78+
(`ins==`CALL)||
5379
(`ins == `JXX && `fun == `JMP)||
5480
(`ins == `JXX && `fun == `BEQ && cc[1:1])||
5581
(`ins == `JXX && `fun == `BNE && ~cc[1:1])||
5682
(`ins == `JXX && `fun == `BLT && ~cc[1:1] && ~cc[0:0])||
57-
(`ins == `JXX && `fun == `BGT && ~cc[1:1] && cc[0:0]))? valC :valP;
83+
(`ins == `JXX && `fun == `BGT && ~cc[1:1] && cc[0:0]))? valC :
84+
(`ins==`RET)? valM:valP;
5885
//如果成功转移则为valC,不转移则为下一条指令valP
5986

6087
endmodule

0 commit comments

Comments
 (0)