1. 分析指令集
- 经过分类,指令共包含R型指令和I型指令
- 列出其对应的32位机器码,寻找共性差异
R型指令:
Type |
Op |
Rs |
Rt |
Rd |
Shamt |
Func |
解释 |
add |
000000 |
(5) |
(5) |
(5) |
00000 |
100000 |
相加(rs+rt->rd) |
sub |
000000 |
(5) |
(5) |
(5) |
00000 |
100010 |
相减(rs-rt->rd) |
and |
000000 |
(5) |
(5) |
(5) |
00000 |
100100 |
rs & rt -> rd |
or |
000000 |
(5) |
(5) |
(5) |
00000 |
100101 |
rs | rt -> rd |
slt |
000000 |
(5) |
(5) |
(5) |
00000 |
101010 |
rs < rt ? 1 : 0(signed) |
sltu |
000000 |
(5) |
(5) |
(5) |
00000 |
101011 |
rs < rt ? 1 : 0(unsigned) |
mfhi |
000000 |
00000 |
00000 |
(5) |
00000 |
010000 |
HI ->rd |
mflo |
000000 |
00000 |
00000 |
(5) |
00000 |
010010 |
LO -> rd |
Type |
Op |
Rs |
Rt |
0 |
Func |
解释 |
mult |
000000 |
(5) |
(5) |
0000000000 |
011000 |
rs * rt -> (HI, LO)(signed) |
multu |
000000 |
(5) |
(5) |
0000000000 |
011001 |
rs * rt -> (HI, LO)(unsigned) |
div |
000000 |
(5) |
(5) |
0000000000 |
011010 |
rs / rt -> (HI, LO)(signed) |
divu |
000000 |
(5) |
(5) |
0000000000 |
011011 |
rs / rt -> (HI, LO)(unsigned) |
Type |
Op |
Rs |
0 |
Func |
解释 |
mthi |
000000 |
(5) |
000000000000000 |
010001 |
rs -> HI |
mtlo |
000000 |
(5) |
000000000000000 |
010011 |
rs -> LO |
I型指令:
Type |
Op |
Rs |
Rt |
Immediate |
解释 |
ori |
001101 |
(5) |
(5) |
(16) |
或运算(rs|immediate->rt) |
lui |
001111 |
00000 |
(5) |
(16) |
立即数加载至高16位({immediate||{16{1’b0}}}->rt) |
addi |
001000 |
(5) |
(5) |
(16) |
rs + immediate -> rt |
andi |
001100 |
(5) |
(5) |
(16) |
rs & immediate -> rt |
Type |
Op |
Rs |
Rt |
Offset |
解释 |
lw |
100011 |
(5) |
(5) |
(16) |
加载字(rs+offset在memory中data->rt) |
sw |
101011 |
(5) |
(5) |
(16) |
保存字(rt->rs+offset在memory中的data) |
beq |
000100 |
(5) |
(5) |
(16) |
rs与rt相等则PC偏移offset*4 |
lb |
100000 |
(5) |
(5) |
(16) |
mem中rs +offset对应字节符号拓展 -> rt |
lh |
100001 |
(5) |
(5) |
(16) |
mem中rs +offset对应半字符号拓展 -> rt |
sb |
101000 |
(5) |
(5) |
(16) |
rt[7:0] -> mem(offset + rs) |
sh |
101001 |
(5) |
(5) |
(16) |
rt[15:0] -> mem(offset + rs) |
bne |
000101 |
(5) |
(5) |
(16) |
不相等则跳转 |
J型指令
type |
Op |
instr_index |
解释 |
jal |
000011 |
(26) |
跳转至index并且PC+4 -> $ra |
type |
Op |
rs |
0 |
0 |
func |
解释 |
jr |
000000 |
(5) |
{10{1’b0}} |
{5{1’b0}} |
001000 |
跳转至$rs中的地址 |
2. 阶段分析

F阶段PC值已经确定,进行的是根据PC访存相应的Instruction操作。此时指令已经确定好了
D阶段是将instruction转换成对应的操作数、产生控制信号。
E阶段是将操作数转换成计算结果。
M阶段是方寸数据内存。
W阶段是写入GRF。
3.命名规则
采用首字母大写命名法,每个单词首字母大写。
4. PC设计
端口设计:
方向 |
name |
位宽 |
input |
PcOp |
[3:0] |
input |
BeqPc |
[31:0] |
input |
JalPc |
[31:0] |
input |
JrPc |
[31:0] |
input |
reset |
1 |
input |
clk |
1 |
output |
Pc_F |
[31:0] |
input |
BnePc |
[31:0] |
转移设计:
PcOp |
解释 |
0000 |
Pc_F <= Pc_F + 4 |
0001 |
Pc_F <= BeqPc |
0010 |
Pc_F <= JalPc |
0011 |
Pc_F <= JrPc |
0100 |
Pc_F <= BnePc |
5. CU控制信号分析
端口设计:
type |
name |
位宽 |
解释 |
input |
Op |
[5:0] |
机器码高6位 |
input |
Func |
[5:0] |
机器码低6位 |
output |
RegDst |
[1:0] |
GRF被写入寄存器是rt还是rd。0是rt,1是rd,10是$ra |
output |
AluSrc |
[1:0] |
ALU第二个运算值是rt还是立即数。0是rt,1是立即数 |
output |
MemToReg |
[1:0] |
GRF写入值是ALUans还是DMans。0是ALUans,1是DMans,10是PC + 4 |
output |
RegWrite |
1 |
是否写入GRF |
output |
MemWrite |
1 |
是否写入RAM |
output |
PcSel |
[3:0] |
当前指令是否是beq\jal\jr |
output |
ExtOp |
[7:0] |
扩展操作类型类型,详见Extender |
output |
AluOp |
[7:0] |
ALU运算类型,详见ALU |
output |
InstrType |
[7:0] |
指令类型 |
output |
TNew_D |
[3:0] |
从D级开始,经过多少周期该指令产生运算结果 |
output |
TUse1_D,TUse2_D |
[3:0] |
从D级开始,经过多少周期要用到运算结果 |
output |
Multiply_D |
1 |
是否进行乘法操作 |
output |
Divide_D |
1 |
是否进行除法操作 |
- 内部电路采用最小项表达式判断法,先判断Op,再判断Func
每种指令所需控制信号:
|
RegDst |
AluSrc |
MemToReg |
RegWrite |
MemWrite |
PcSel |
ExtOp |
AluOp |
TNew |
TUse1 |
TUse2 |
add |
01 |
00 |
00 |
1 |
0 |
0000 |
|
ADD |
2 |
1 |
1 |
sub |
01 |
00 |
00 |
1 |
0 |
0000 |
|
SUB |
2 |
1 |
1 |
ori |
00 |
01 |
00 |
1 |
0 |
0000 |
0000 |
OR |
2 |
1 |
10 |
lui |
00 |
01 |
00 |
1 |
0 |
0000 |
0010 |
ADD |
2 |
10 |
10 |
lw |
00 |
01 |
01 |
1 |
0 |
0000 |
0001 |
ADD |
3 |
1 |
10 |
sw |
11 |
01 |
|
0 |
1 |
0000 |
0001 |
ADD |
0 |
1 |
2 |
beq |
11 |
00 |
|
0 |
0 |
0001 |
0011 |
EQUAL |
0 |
0 |
0 |
jal |
10 |
|
10 |
1 |
0 |
0010 |
0100 |
|
0 |
10 |
10 |
jr |
11 |
00 |
|
0 |
0 |
0011 |
|
ADD |
0 |
0 |
10 |
6. 流水线寄存器存储信息分析
F级:
name |
位宽 |
Pc_F |
[31:0] |
Instruction_F |
[31:0] |
D级:
name |
位宽 |
Pc_D |
[31:0] |
RD1_D |
[31:0] |
RD2_D |
[31:0] |
WR_D |
[4:0] |
ExtAns_D |
[31:0] |
MemToReg_D |
[1:0] |
RegWrite_D |
1 |
AluSrc_D |
[1:0] |
MemWrite_D |
1 |
AluOp_D |
[7:0] |
InstrType_D |
[7:0] |
TNew_D |
[7:0] |
Addr1_D |
[4:0] |
Addr2_D |
[4:0] |
E级:
name |
位宽 |
Pc_E |
[31:0] |
AluAns_E |
[31:0] |
WR_E |
[4:0] |
RD2_E |
[31:0] |
MemToReg_E |
[1:0] |
RegWrite_E |
1 |
MemWrite_E |
1 |
InstrType_E |
[7:0] |
TNew_E |
[7:0] |
Addr2_E |
[4:0] |
M级:
name |
位宽 |
Pc_M |
[31:0] |
AluAns_M |
[31:0] |
WR_M |
[4:0] |
DmAns_M |
[31:0] |
MemToReg_M |
1 |
RegWrite_M |
1 |
InstrType_M |
[7:0] |
TNew_M |
[7:0] |
W级:
name |
位宽 |
Pc_W |
[31:0] |
AluAns_W |
[31:0] |
WR_W |
[4:0] |
DmAns_W |
[31:0] |
MemToReg_W |
[1:0] |
RegWrite_W |
1 |
InstrType_W |
[7:0] |
TNew_W |
[7:0] |
7. 流水线转发数据
E级:
instruction |
Data_E |
add |
0 |
sub |
0 |
ori |
0 |
lui |
0 |
beq |
0 |
jal |
Pc_E + 8 |
jr |
0 |
lw |
0 |
sw |
0 |
M级:
instruction |
Data_M |
add |
AluAns_M |
sub |
AluAns_M |
ori |
AluAns_M |
lui |
AluAns_M |
beq |
0 |
jal |
Pc_M + 8 |
jr |
0 |
lw |
0 |
sw |
0 |
W级:
instruction |
Data_W |
add |
AluAns_W |
sub |
AluAns_W |
ori |
AluAns_W |
lui |
AluAns_W |
beq |
0 |
jal |
Pc_W + 8 |
jr |
0 |
lw |
DmAns_W |
sw |
0 |
8. 测试方案
针对每一条新添加的指令都进行测试,确保有符号、无符号的正确性,以及周期数的正确。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| 3508000c 35290015 01095024 000a5820 35080010 35290019 01095025 01405820 2108ffff 2108ffff 2108fffe 310a0079 314a0015 000a582a 2009ffff 0120582a 0000582a 200afffe 012a582a 0149582a 012a582b 340c03e8 012c582a 012c582b 0169582b 14000007 20080001 20080002 20080003 14080003 20080004 20080005 20080006 20080003 2009fffe 200a0002 01090018 01090019 010a0018 0109001a 0109001b 010a001a 00004010 21080001 00004012 21080003 00004010 1100fff1 20090003 20090007 01200011 00005010 012a0018 01600013 00005812 016a5824 2008fffd 20090001 200a0002 200b0003 a0080000 a1280000 a1480000 a1680000 a4080004 a5480008 800c0004 218c0002 814c0004 218c000d 840c0004 218c0034 34080005 34090022 00084022 00094822 01280018 00005010 00005812
|
9. 思考题汇总
- 鼠标和键盘的信号被CPU知晓的过程涉及到硬件中断、信号传输、以及操作系统的参与。
鼠标信号被CPU知晓的过程
- 鼠标信号的产生:当鼠标移动或点击时,会产生相应的电信号或数字信号。这些信号代表了鼠标的位置、移动方向、点击动作等信息。
- 信号传输到计算机:这些信号通过鼠标线(有线鼠标)或无线方式(无线鼠标)传输到计算机的USB接口或其他类型的接口上。
- 中断请求:一旦鼠标信号到达计算机,它会触发一个硬件中断。这个中断请求会被送到中断控制器,中断控制器再将请求转发给CPU。
- CPU处理中断:CPU在接收到中断请求后,会暂停当前正在执行的任务,转而处理鼠标中断。CPU会读取鼠标控制器中的数据,这些数据包含了鼠标的位置信息和状态信息。
- 操作系统的角色:操作系统会进一步处理这些原始数据,将其转换为更高级别的事件,如鼠标移动事件或点击事件,并将这些事件传递给应用程序。
键盘信号被CPU知晓的过程
键盘信号的产生:当用户按下键盘上的某个键时,键盘内部的电路会产生一个相应的电信号。这个信号代表了被按下的键的位置信息。
信号编码:键盘控制器将这些电信号转换为键盘扫描码,这是一种二进制编码,用于表示键盘上每个键的唯一标识。
信号传输到计算机:键盘扫描码通过键盘线传输到计算机的USB接口或其他类型的接口上。
中断请求与CPU处理:与鼠标类似,键盘信号也会引起硬件中断。CPU在接收到中断请求后,会读取键盘控制器中的扫描码,并将其存储在特定的内存位置(如键盘缓冲区)中。
操作系统与驱动程序:操作系统和键盘驱动程序会进一步处理这些扫描码,将其转换为ASCII码或Unicode码等字符编码,以便应用程序能够理解和使用。
因为这样,我们就可以提前在该地址处书写异常处理程序;当异常发生时,只需要固定跳转到该地址,即可运行相对应的异常处理程序来处理异常。如果是用户自定义处理异常中断的入口地址,自己提供程序,那么CPU仍然可以正常提供异常中断修复的功能。但是这样的问题在于用户的自定义程序入口或自定义程序可能占用了DM的存储空间,导致DM空间不足或者访存指令出错。
因为每种外设的接口不同,格式不同,方寸方式也不同。如果不用Bridge,则CPU需要为每一种外设都新增新的方寸方式或者接口,这不利于维护CPU的正常工作。而Bridge可以解决这一问题,通过读取CPU的信号和外设的信号,来进行中间的交互,转移了工作量,有利于CPU的功能维护和扩展。
两种中断模式在计数为0后的行为不同。一种是自动填装初值再重新倒数,一种是保持为0直到使能信号置位再计数。![[810a3c13b390e6a91ad2365bd55281f.jpg]]
![[12ac7de1353c985830c21aa192065fc.jpg]]
会发生的问题是,空泡的PC和BD可能不是我们所期待的,从而导致eret指令返回地址异常。因此空泡指令需要保存原指令的PC和BD,如果在空泡时遇到了中断,也能根据PC和BD返回正确的指令。
因为会存在冒险。jalr指令的功能是跳转到对应寄存器中的地址,同时把PC+4(有延迟槽则PC+8)的值写入对应寄存器中。如果后面两个寄存器都是相同的,则先跳转再写入还是先写入再跳转就会产生两种不一样的结果。因此为了避免这种未知情况的发生,不能这样写。