北航co计算机组成P6设计文档

Post Cover

P6CPU设计文档及思考题

设计草稿

1.指令详解

(1)calc_R:

  • ADD:add RD, RS, RT
    编码:000000 sssss ttttt ddddd 00000 100000
    描述:GPR[rd] = GPR[rs] + GPR[rt]
  • SUB:sub RD, RS, RT
    编码:000000 sssss ttttt ddddd 00000 100010
    描述:GPR[rd] = GPR[rs] - GPR[rt
  • AND:and RD, RS, RT
    编码:000000 sssss ttttt ddddd 00000 100100
    描述:GPR[rd] = GPR[rs] & GPR[rt]
  • OR:or RD, RS, RT
    编码:000000 sssss ttttt ddddd 00000 100101
    描述:GPR[rd] = GPR[rs] | GPR[rt]
  • SLT:slt RD, RS, RT
    编码:000000 sssss ttttt ddddd 00000 101010
    描述:if GPR[rs] < GPR[rt], GPR[rd] = 1; else GPR[rd] = 0;是有符号的比较
  • SLTU:sltu RD, RS, RT
    编码:000000 sssss ttttt ddddd 00000 101011
    描述:if GPR[rs] < GPR[rt], GPR[rd] = 1; else GPR[rd] = 0; 但是是无符号的比较

(2)calc_I:

  • ADDI:addi RT, RS, IMM
    编码:001000 sssss ttttt iiiii iiiii iiiiii
    描述:GPR[rt] = GPR[rs] + sign_ext(IMM)
  • ANDI:andi RT, RS, IMM
    编码:001100 sssss ttttt iiiii iiiii iiiiii
    描述:GPR[rt] = GPR[rs] & zero_extend(IMM)
  • ORI:ori RT, RS, IMM
    编码:001101 sssss ttttt iiiii iiiii iiiiii
    描述:GPR[rt] = GPR[rs] | zero_extend(IMM)

(3)load:

  • LB:lb RT, OFFSET(RS)
    编码:100000 sssss ttttt iiiii iiiii iiiiii
    描述:GPR[rt] = sign_ext(MEM[GPR[rs] + sign_ext(OFFSET)][7:0])
    操作:
1
2
3
4
Addr = GPR[base] + sign_ext(offset) 
memword = memory[Addr]
byte = Addr1..0
GPR[rt] = sign_ext(memword7+8*byte..8*byte)
  • LH:lh RT, OFFSET(RS)
    编码:100001 sssss ttttt iiiii iiiii iiiiii
    描述:GPR[rt] = sign_ext(MEM[GPR[rs] + sign_ext(OFFSET)][15:0])
    操作:
1
2
3
4
Addr = GPR[base] + sign_ext(offset) 
memword = memory[Addr]
byte = Addr1
GPR[rt] = sign_ext(memword15+16*byte..16*byte)
  • LW:lw RT, OFFSET(RS)
    编码:100011 sssss ttttt iiiii iiiii iiiiii
    描述:GPR[rt] = MEM[GPR[rs] + sign_ext(OFFSET)]

(4)store:

  • SB:sb RT, OFFSET(RS)
    编码:101000 sssss ttttt iiiii iiiii iiiiii
    描述:MEM[GPR[rs] + sign_ext(OFFSET)] = GPR[rt][7:0]
    操作:
1
2
3
Addr = GPR[base] + sign_extend(offset) 
byte = Addr1..0
memory[Addr]7+8*byte..8*byte = GPR[rt]7:0
  • SH:sh RT, OFFSET(RS)
    编码:101001 sssss ttttt iiiii iiiii iiiiii
    描述:MEM[GPR[rs] + sign_ext(OFFSET)] = GPR[rt][15:0]
    操作:
1
2
3
Addr = GPR[base] + sign_extend(offset) 
byte = Addr1
memory[Addr]15+16*byte..16*byte = GPR[rt]15:0
  • SW:sw RT, OFFSET(RS)
    编码:101011 sssss ttttt iiiii iiiii iiiiii
    描述:MEM[GPR[rs] + sign_ext(OFFSET)] = GPR[rt]

(5)md:

  • mult:mult rs, rt
    编码:000000 sssss ttttt 00000 00000 011000
    描述:HI, LO = GPR[rs] * GPR [rt](有符号)
  • multu:multu rs, rt
    编码:000000 sssss ttttt 00000 00000 011001
    描述:HI, LO = GPR[rs] * GPR[rt]
  • div:div rs, rt
    编码:000000 sssss ttttt 00000 00000 011010
    描述:LO = GPR[rs]/ GPR[rt]; HI = GPR[rs] % GPR[rt](有符号)
  • divu:divu rs, rt
    编码:000000 sssss ttttt 00000 00000 011011
    描述:LO = GPR[rs] / GPR[rt]; HI = GPR[rs] % GPR[rt]

(6)mf:

  • mflo:mflo rd
    编码:000000 00000 00000 ddddd 00000 010010
    描述:GPR[rd] = LO
  • mfhi:mfhi rd
    编码:000000 00000 00000 ddddd 00000 010000
    描述:GPR[rd] = HI

(7)mt:

  • mtlo:mtlo rs
    编码:000000 sssss 00000 00000 00000 010011
    描述:LO = GPR[rs]
  • mthi:mthi rs
    编码:000000 sssss 00000 00000 00000 010001
    描述:HI = GPR[rs]

(8)B:

  • BEQ:beq RS, RT, LABEL
    编码:000100 sssss ttttt iiiii iiiii iiiiii
    描述:if GPR[rs] == GPR[rt], PC = PC + 4 + sign_ext(LABEL); else PC = PC + 4;
  • BNE:bne RS, RT, LABEL
    编码:000101 sssss ttttt iiiii iiiii iiiiii
    描述:if GPR[rs] != GPR[rt], PC = PC + 4 + sign_ext(LABEL); else PC = PC + 4;

(9)Other:

  • lui:lui RT, IMM
    编码:001111 00000 ttttt iiiii iiiii iiiiii
    描述:GPR[rt] = sign_ext(IMM) << 16;
  • jal: jal target
    编码:000011 iiiii iiiii iiiii iiiii iiiiii
    描述:GPR[31] = PC + 4; PC = PC[31,28]||instr_index||00
  • jr: jr rs
    编码:000000 sssss 00000 00000 00000 001000
    描述:PC = GPR[rs]
  • nop:nop
    编码:000000 00000 00000 00000 00000 000000
    描述:GPR[0] = GPR[0]

2.各部件接口设计

NPC

接口名称 输入或输出 位宽 描述
PC I 31:0 前一拍指令地址
offset I 31:0 用于计算B类指令跳转地址
Ins_26 I 25:0 用于计算J、JAL跳转地址
Ra I 31:0 用于读取JR、JALR中寄存器存储的地址
B_judge I 1 用于判断B类指令是否满足跳转条件
if_Branch I 1 用于判断是否为B类指令
if_JR I 1 用于判断是否为J、JR指令
Next_PC O 31:0 下一拍指令地址
PC+4 O 31:0 上一拍指令地址+4,用于JAL、JALR地址存储

注意跳转指令PC要是它本身的PC,即beq指令的PC要和上一个周期的一样,不和延迟槽一样,不用+4.

IFU

接口名称 输入或输出 位宽 描述
clk I 1 时钟信号
Reset I 1 同步复位信号
Next_PC I 31:0 计算出的下一拍指令地址
En I 1 有效信号,阻塞时为0
PC O 31:0 当前指令地址

GRF

接口名称 输入或输出 位宽 描述
PC I 31:0 当前指令地址
RA1 I 4:0 读寄存器1地址
RA2 I 4:0 读寄存器2地址
WA I 4:0 写寄存器地址
WD I 31:0 写寄存器数据
clk I 1 时钟信号
reset I 1 同步复位信号
RegWrite I 1 写寄存器控制信号
RD1 O 31:0 读寄存器1数据
RD2 O 31:0 读寄存器2数据

ALU

接口名称 输入或输出 位宽 描述
ALU_Op I 3:0 ALU操作码
Src_A I 31:0 ALU输入A数据
Src_B I 31:0 ALU输入B数据
shift I 5:0 位移量(对B数据进行位移)
ALU_Result O 31:0 ALU输出结果

EXT

接口名称 输入或输出 位宽 描述
Imm I 15:0 扩展前的立即数
if_sign I 1 是否为有符号扩展
offset O 31:0 扩展后的立即数

CMP

接口名称 输入或输出 位宽 描述
D1 I 31:0 数据1
D2 I 31:0 数据2
CMPOP I 2:0 比较操作码
out O 1 比较结果

MDU

接口名称 输入或输出 位宽 描述
clk I 1 时钟信号
reset I 1 同步复位信号
start I 1 乘除法开始运算信号
MDU_Op I 3:0 MDU操作码
A I 31:0 操作数A
B I 31:0 操作数B
HI O 31:0 乘除法结果
LO O 31:0 乘除法结果
out O 31:0 运算结果
busy O 1 乘除法运算忙信号

BE

接口名称 输入或输出 位宽 描述
A I 1:0 DM写入地址的低2位
LSOp I 2:0 访存功能信号
WD_in I 31:0 未经处理的DM写入数据
byteen O 3:0 DM字节使能信号
WD_out O 31:0 经过处理的DM写入数据

DE

接口名称 输入或输出 位宽 描述
A I 2
RD_in I 32 未经处理的DM读出数据
LSOp I 2 访存功能信号
RD_out O 32 处理后的DM读出数据

3.数据通路设计

NPC

操作 PC offset Ins_26 RA if_Branch if_jr if_jal
all IFU EXT splitter GRF control control control

IFU

操作 clk Reset Next_PC
all clk reset NPC

GRF

操作 clk Reset RA1 RA2 WA WD RegWrite
add clk reset splitter[s] splitter[t] splitter[d] ALU control
sub clk reset splitter[s] splitter[t] splitter[d] ALU control
ori clk reset splitter[s] - splitter[t] ALU control
lw clk reset splitter[s] - splitter[t] DM control
sw clk reset splitter[s] splitter[t] - - control
beq clk reset splitter[s] splitter[t] - - control
lui clk reset - - splitter[t] ALU control
jal clk reset - - 31 NPC control
jr clk reset splitter[s] - - - control

ALU

操作 ALU_Op Src_A Src_B shift
add control GRF-RD1 GRF-RD2 -
sub control GRF-RD1 GRF-RD2 -
ori control GRF-RD1 EXT -
lw control GRF-RD1 EXT -
sw control GRF-RD1 EXT -
beq control GRF-RD1 GRF-RD2 -
lui control - EXT 16
jal - - - -
jr - - - -

EXT

操作 Imm if_sign
all splitter[i] control

4.流水线寄存器

名称 功能 F_D D_E E_M M_W
IR 指令
PC 指令地址
WD 写寄存器数据 -
WA 写寄存器地址 -
RegWrite 写寄存器控制信号 -
Tnew 数据产生时间 -
其他 PC+8 RD1,RD2,offset RD2,ALU_Result -

5.控制信号

总控制

数值 MemToReg MemWrite ALUSrc RegWrite signedEXT RegDst if_Branch if_JR if_JAL ALUToReg Ralink lui
控制的位置 GRF-WD DM-MemWrite ALU-SrcB GRF-RegWrite EXT-if_sign GRF-WA NPC-if_Branch NPC-if_JR NPC-if_JAL GRF-WD GRF-WA ALU_shift
0 ALU unable GRF-RD2 unable zero_extend splitter[t] NOT-BEQ NOT-JR NOT-JAL WD不是ALU结果 - 位移是shifter
1 DM enable EXT enable sign_extend splitter[d] BEQ JR JAL WD不是ALU结果 将PC+4存入寄存器的编号(31)(WA的分支) lui是位移16位

ALU控制

0000 : +
0001 : -
0010 : &
0011 : |
0100 : slt
0101 : sltu
1111 : 数据B向左位移shift位

cmp控制

000: ==
001: !=
111:else

LSOp控制

sw 3’b000
sh 3’b001
sb 3’b010
lw 3’b011
lh 3’b100
lb 3’b101
space 3’b111

MDUOp控制

space 4’b0000
mult 4’b0001
multu 4’b0010
div 4’b0011
divu 4’b0100
mfhi 4’b0101
mflo 4’b0110
mthi 4’b0111
mtlo 4’b1000

6.阻塞转发

Tuse 和 Tnew 的分析

Tuse表示数据到了 D 级之后还需要多少个周期要使用,每个指令的是固定不变的。
Tnew表示数据还有多长时间产生,会随着数据的流水动态的减少。(但是大于1)
Tuse表格

指令 rs_Tuse rt_Tuse
calc_R 1 1
calc_I 1 -
md 1 1
mt 1 -
load 1 -
store 1 2
B 0 0
JR 0 -
其他的都是if_use=0

D级时Tnew表格

指令 Tnew
calc_R 2
calc_I 2
mf 2
load 3
lui 2
jal 0
其他的都是RegWrite=0

阻塞转发的判断

当Tuse≥Tnew时,可以通过转发解决;当Tuse < Tnew时,必须阻塞流水线。

阻塞操作:

冻结PC寄存器(IFU_en = ~stall = 0)
冻结D级寄存器(D_en = ~stall = 0)
清空E级寄存器(E_clr = stall = 1)

转发操作:

转发需要:

  1. GRF内部转发
  2. D需要E、M的转发
  3. E需要M、W的转发
  4. M需要W的转发

课上

和P5差不多啦!但是不要掉以轻心,P5过了P6挂的人也有不少)

依旧保证课下正确。欢迎使用伟大的cot评测机!!

如果P5写好了扩展性好的接口可以继续使用。如果没有写好,经过P5应该也知道要增加什么了)

依旧是一样的课上题目分析:

1. 计算类型

形如:

1
2
WriteData <- f(GPR[rs], GPR[rt])
GPR[rd] <- WriteData

做法:

  1. 在控制模块中识别新指令,设置控制信号
  2. 新增 ALU 计算类型
  3. 新增各流水线级转发数据

仿照 add 指令编写

与P5不一样的是,会有乘除槽指令的增加(当然也可能不是乘除槽

2. 条件跳转类型

形如:

1
2
3
4
5
6
7
condition <- f(GPR[rs], Ext_Ans)
if condition:
jump
(GPR[rt] <- data)
else:
(NullifyDelayedBranch)

  1. 控制模块中设置控制信号
  2. 计算 condition
  3. 跳转仿照 beq
  4. 条件写入用特判+凌驾的做法,记得改 D-E 级流水线寄存器的输入
  5. 清空延迟槽,新增控制信号Clr_F,Clr_F为真的条件:condition为假 && D级是新指令 && 此时不能阻塞
3. 访存类型

形如:

1
2
3
4
DMdata <- DM[addr]
data <- f(DMdata, GPR[rt])
dest_reg <- f(data)
GPR[dest_reg] <- data
  1. data、dest_reg 是在 W级 算出来的,M-W 流水线传 rt
  2. W级该指令转发 data
  3. dest_reg 最好在 没算出来之前都是 0,防止转发冲突
  4. dest_reg 的范围很重要
  5. 比较阻塞的时候,依次比较E,M级,条件为:是新指令 && 要写寄存器 && 寄存器处在 dest_reg 范围内 && RA!=0 && Tuse < Tnew

往年题依旧指路室友博客

思考题点击展开,不保证正确性,建议自己思考

思考题

1、为什么需要有单独的乘除法部件而不是整合进 ALU?为何需要有独立的 HI、LO 寄存器?

分离设计的原因:乘除法运算需要多个周期(乘法5周期,除法10周期),而ALU的算术逻辑指令是单周期完成。若整合进ALU,会严重拖累流水线效率。并且,乘除法器硬件结构复杂,面积大,独立模块便于优化和复用。
HI、LO寄存器的作用:乘除法的结果往往是64位(32位×32位),HI存高32位,LO存低32位。专用寄存器避免占用通用寄存器堆,同时通过mfhi/mflo指令提供访问接口。

2、真实的流水线 CPU 是如何使用实现乘除法的?请查阅相关资料进行简单说明。

一. 核心思想:用更简单的操作来实现复杂操作
乘法和除法本质上可以用更基本的加法、移位和比较来实现。CPU的算术逻辑单元(ALU)最初就是被这样设计的。
二. 乘法是如何实现的?
我们先从最直观的算法说起。
方法一:模拟手算乘法(移位相加)
我们以两个4位二进制数 1011 (11) 和 1101 (13) 为例:

1
2
3
4
5
6
7
8
9
        1 0 1 1   (被乘数)
x 1 1 0 1 (乘数)
---------
1 0 1 1 (部分积1,因为乘数最低位是1)
0 0 0 0 (部分积2,因为乘数第二位是0,左移一位)
1 0 1 1 (部分积3,因为乘数第三位是1,左移两位)
+ 1 0 1 1 (部分积4,因为乘数第四位是1,左移三位)
---------------
1 0 0 0 1 1 1 1 (结果 143)

CPU如何用硬件实现这个过程?

  1. 初始化:准备三个寄存器,一个存放被乘数,一个存放乘数,一个初始为0用于存放结果(积)。
  2. 循环检查:
    · 检查乘数的最低位。
    · 如果为1,则将被乘数加到结果寄存器上。
    · 如果为0,则不加。
  3. 移位:
    · 将被乘数寄存器向左移位一位(相当于值翻倍)。
    · 将乘数寄存器向右移位一位(这样下一次循环就能检查下一位)。
  4. 判断终止:重复步骤2和3,直到乘数寄存器为0。
    这个方法的缺点是速度慢,需要N个时钟周期(N是数据的位数)。
    方法二:更快的现代方法
    为了提速,现代CPU采用了更先进的技术:
    · 布斯算法:一种优化算法,可以处理带符号数,并且能跳过连续的0或1,减少加法次数。
    · 并行乘法器/硬件乘法器:这是现代CPU的主流方式。它不像上面那样一步一步串行计算,而是使用一个巨大的、专门设计的组合逻辑电路(比如“华莱士树”),通过多级加法器并行地计算所有部分积的和。
    · 优点:速度极快!可以在1个或几个时钟周期内完成一次乘法运算。
    · 缺点:电路非常复杂,晶体管数量多,功耗和芯片面积都更大。
    所以,当你写 a = b * c 时,CPU几乎是在瞬间通过这个专用的硬件乘法器计算出结果的。
    三. 除法是如何实现的?

除法是乘法的逆运算,但它更复杂,速度也更慢。

方法一:模拟手算除法(恢复余数法)

我们以 1111 (15) 除以 0100 (4) 为例:

1
2
3
4
5
6
7
8
9
          0011 (商 = 3)
--------
除数 0100)1111 (被除数)
-0100
-----
0111
-0100
-----
0011 (余数 = 3)

CPU如何用硬件实现这个过程?

  1. 初始化:准备寄存器存放被除数(和余数)、除数、商。
  2. 对齐:将除数和被除数的最高有效位对齐。
  3. 尝试减法:从当前被除数(或余数)中减去除数。
  4. 判断结果:
    · 如果结果大于等于0,说明够减,则将商的对应位置1,并将减法结果作为新的余数。
    · 如果结果小于0,说明不够减,则将商的对应位置0,并恢复原来的被除数/余数(这就是“恢复余数法”名称的由来)。
  5. 移位:将除数右移一位,准备下一次计算。
  6. 循环:重复步骤3-5,直到处理完所有位。

这个方法同样很慢,最坏情况下需要2N个时钟周期(N是数据的位数)。

方法二:更快的现代方法

· 不恢复余数法/SRT除法:这是“恢复余数法”的优化。它在发现不够减时,不去恢复余数,而是记录一个负的余数,并在下一步操作中通过加回来进行修正。这减少了很多不必要的步骤,是现代CPU常用的算法之一。
· 牛顿-拉弗森迭代法:这是一种利用乘法来逼近除法结果的方法。它通过一系列迭代,快速收敛到精确的商。公式大致是: x_{n+1} = x_n * (2 - D * x_n) ,其中D是除数。这种方法需要快速的乘法器支持,在计算高精度除法时特别有效。
· 查表法:对于某些初始近似值,CPU可能会使用一个小的、快速的查找表来获取,以加速迭代过程的启动。

重要提示:除法在所有基本运算中是最慢的。即使是最优化的硬件实现,一次整数除法也可能需要几十个时钟周期,而一次整数乘法或加法可能只需要1个或几个周期。这就是为什么在优化代码时,要尽量避免不必要的除法操作。

3、请结合自己的实现分析,你是如何处理 Busy 信号带来的周期阻塞的?

乘除法到达E级时,产生控制信号Start=1
当start=1时,Busy=1持续到运算完成。
在D级检测到Busy=1或者start=1时,同时D级是乘除法指令暂停流水线(插入气泡)。乘除法完成后Busy=0,解除阻塞,流水线继续。

4、请问采用字节使能信号的方式处理写指令有什么好处?(提示:从清晰性、统一性等角度考虑)

清晰性:m_data_byteen[3:0]明确指定写入哪些字节,避免手动拼接数据。
统一性:所有存储指令(sw/sh/sb)共用同一写端口,通过byteen区分行为,简化DM接口。

5、请思考,我们在按字节读和按字节写时,实际从 DM 获得的数据和向 DM 写入的数据是否是一字节?在什么情况下我们按字节读和按字节写的效率会高于按字读和按字写呢?

读操作:从DM读出的总是整个字(32位),再由数据扩展模块提取并扩展特定字节。
写操作:向DM写入的是整个字,但通过byteen控制哪些字节实际被写入。
当程序频繁访问非字对齐数据时,按字节访问可避免读写整个字,减少内存带宽浪费。在稀疏数据结构(如字符数组、标志位数组)中,字节访问更高效。

6、为了对抗复杂性你采取了哪些抽象和规范手段?这些手段在译码和处理数据冲突的时候有什么样的特点与帮助?

抽象手段:
1.将指令按功能分类(如算术、访存、跳转、乘除),统一生成控制信号。
2.用 define,替代判断选择信号的常量
规范手段:
1.模块化设计,各功能模块职责单一,接口清晰。
2.流水线寄存器规范化,统一传递必要信号。
特点和帮助:
逻辑更加简单,容易看懂,容易debug,方便修改。

7、在本实验中你遇到了哪些不同指令类型组合产生的冲突?你又是如何解决的?相应的测试样例是什么样的?

遇到的冲突:
1.控制冲突:分支指令和跳转指令导致的控制流改变。
2.数据冲突:算术指令之间的读后写(RAW)冲突。
(1)在E级产生结果的指令和在D级需要数据的指令之间的冲突,如add后beq
(2)在M级产生结果的指令和在D级需要数据的指令之间的冲突,如lw后beq
(3)在E级产生结果的指令和在E级需要数据的指令之间的冲突,如add后add
(4)在M级产生结果的指令和在E级需要数据的指令之间的冲突,如lw后add
(5)在M级产生结果的指令和在M级需要数据的指令之间的冲突,如lw后sw
(6)乘除发指令之间的冲突
4.解决:通过延迟槽,阻塞,转发的方式解决
测试样例:部分测试如下表示,但是由于测试比较长,没有完全粘贴过来

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
main:
# 测试1: ALU→ALU转发
addi $1, $0, 1 # $1 = 1
addi $2, $0, 2 # $2 = 2
add $3, $1, $2 # $3 = 3 (RAW: 需要$1,$2)
add $4, $3, $1 # $4 = 4 (需要E级转发)

# 测试2: 加载使用冲突(需要阻塞)
addi $5, $0, 0x1000 # 数据地址
sw $3, 0($5) # 存储数据
lw $6, 0($5) # 加载数据
add $7, $6, $1 # 需要阻塞1周期 (加载使用)

# 测试3: 多级转发
addi $8, $0, 5 # $8 = 5
add $9, $8, $1 # $9 = 6
add $10, $9, $2 # $10 = 8
add $11, $10, $9 # $11 = 14

# 测试4: 转发到存储指令
addi $12, $0, 8
addi $13, $0, 9
add $14, $12, $13 # $14 = 17
sw $14, 4($5) # 需要转发到存储数据

# 乘法测试
addi $1, $0, 15
addi $2, $0, 20
mult $1, $2 # 开始乘法,Busy=1

# 测试乘除阻塞 - 这些指令应该被阻塞在D级
addi $3, $0, 30 # 应该正常执行
addi $4, $0, 40 # 应该正常执行

# 在Busy期间尝试乘除指令(应该被阻塞)
mflo $5 # 应该等待乘法完成
mfhi $6 # 应该等待乘法完成

# 除法测试
addi $7, $0, 100
addi $8, $0, 7
div $7, $8 # 开始除法,Busy=1

# 测试除法阻塞期间的指令
addi $9, $0, 50 # 正常执行
mflo $10 # 等待除法完成
mfhi $11 # 等待除法完成

8、如果你是手动构造的样例,请说明构造策略,说明你的测试程序如何保证覆盖了所有需要测试的情况;如果你是完全随机生成的测试样例,请思考完全随机的测试程序有何不足之处;如果你在生成测试样例时采用了特殊的策略,比如构造连续数据冒险序列,请你描述一下你使用的策略如何结合了随机性达到强测的效果。

手动构造样例策略:
1.先确保每一个寄存器都可以正常使用,用lui、ori、addi、andi对每一个寄存器先赋不同值,寄存器的值保证,有正有负有0有32’HFFFF_FFFF等
2.运用寄存器中的值,对每一条指令是否正常进行进行检测
3.构造冒险,保证每一类冒险的情况都覆盖
通过以上方式构造,同时确保每一点都覆盖所有情况,则可以基本保证覆盖了所有需要测试的情况。

本作品由 一一 于 2026-02-13 13:00:00 发布
作品地址:北航co计算机组成P6设计文档
除特别声明外,本站作品均采用 CC BY-NC-SA 4.0 许可协议,转载请注明来自 anAilurus' Blog
Logo
上一篇北航co计算机组成P7debug分享和思考题下一篇北航co计算机组成P5设计文档