1
1
`include "tinyCPU.h"
2
2
3
3
`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
5
5
`define rA rom_data[14 :12 ] // 只用3位来表示Ra(一共8个寄存器,3位寻址)
6
6
`define rB rom_data[10 :8 ] // 只用3位
7
7
`define rC rom_data[6 :4 ] // 第三个字节高四位的低三位用来表示rC
@@ -21,40 +21,67 @@ module TINYCPU(
21
21
input wire clk,rst_
22
22
);
23
23
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;
25
25
wire [1 :0 ] cc;
26
26
wire [2 :0 ] dstE, dstM;
27
-
27
+ wire [2 :0 ] val_rA, val_rB;
28
+ // 取指阶段
28
29
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为停机指令,不再增加。
32
34
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;
35
41
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 ;
51
75
// 其他指令不应该修改寄存器内容
76
+ // 更新PC阶段:
52
77
assign new_pc= (
78
+ (`ins== `CALL)||
53
79
(`ins == `JXX && `fun == `JMP)||
54
80
(`ins == `JXX && `fun == `BEQ && cc[1 :1 ])||
55
81
(`ins == `JXX && `fun == `BNE && ~ cc[1 :1 ])||
56
82
(`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;
58
85
// 如果成功转移则为valC,不转移则为下一条指令valP
59
86
60
87
endmodule
0 commit comments