# P4 课上测试

通过阅读本文,您可以大致了解 2021 年秋季北航计算机组成课程 P4 课上测试的题目内容、难度和解题思路
P4 课上测试的主要内容是对课下用 Verilog 搭建的单周期 CPU 进行强测,同时添加一些新指令
题目每年都会发生变化,题意描述可能与原题有一定差异

想要完成 P4 课上,请务必保证熟悉单周期 CPU 的数据通路,同时课下一定要尝试自行添加一些指令,另外写设计文档时把 P3 时 Logisim 搭的 CPU 的图截一份放上去,这样添加指令的时候会非常清楚需要改变什么数据通路

课下强烈建议添加 lbsb ,此外可以试一试 bltzal 指令,跟课上的跳转非常类似,而且 Mars 里面有现成的,总之课上测试的跳转一般是 branch and link

感觉今年 P4 课上像是娱乐局,但是我很菜所以竞速失败了

不说了,放题目

# T1 添加 RLB 指令

指令描述

31:2625:2120:1615:0
111111$rs 地址$rt 地址16 位立即数 imm

指令格式

rlb rt, rs, imm

RTL 语言描述

if imm == 0 then
	GPR[$rt] <- GPR[$rs]
else
	GPR[$rt] <- $rs[31:imm] || inverse($rs[(imm-1):0])
endif

注:这里的 inverse 是按位取反的意思

一句话描述: GPR[$rs] 的低 imm 位按位取反,存入 GPR[$rt]

解法

  • 首先明确这是一个运算指令,只需要修改 ALU 即可
  • ALUOp 添加信号 ALU_rlb ,用 for 循环把低 imm 位按位取反,剩下位原样放到 ALU 的输出 C
//imm 会放到 B 里,题面保证 imm 在 0~31 之间,因此 imm 可以符号扩展也可以无符号扩展
for(i=0; i<B; i=i+1) C[i] = !A[i];		
for(i=B; i<32; i=i+1) C[i] = A[i]

对,关键代码就这么长...

  • 其它的就是普通的运算指令了

# T2 添加 BNEZALC 指令

这一题如果你课下加过 bltzal ,那就是大水题直接过

指令描述

31:26(regimm)25:2120:1615:0
000001$rs 地址10011offset

指令格式

bnezalc rs, offset

RTL 语言描述

if GPR[$rs] != 0 then
	PC <- PC + 4 + sign_extend(offset||2'b00)
	GPR[$31] <- PC + 4
else
	PC <- PC + 4
endif

一句话描述:如果 GPR[$rs] != GPR[$rt] 那么跳转并链接到 $31 ,否则顺序执行但是不链接

解法

  • 首先明确这是一个跳转指令,对于我的设计而言,只需要修改 CMP 即可

  • CMP 直接加一下不等就把 jump 置为 1 即可

  • 注意 CTRLGRFWrEn 即寄存器的写使能信号要添加一个 | !(bnezalc && !jump) ,即不跳转不链接

  • 其他的和 beq 是相同的,直接写就好

# T3 添加 LWRR 指令

这一题和去年的 swrr 神似...

指令描述

31:2625:2120:1615:0
110100base$rt 地址offset

指令格式

lwrr rt, offset(base)

RTL 语言描述

vAddr <- GPR[base] + sign_extend(offset)
memw <- Memory[vAddr]
byte <- vAddr[1:0]
if byte == 0 then
	GPR[$rt] <- Memory[vAddr]
else
	GPR[$rt] <- Memory[vAddr][8*byte-1 : 0] || Memory[vAddr][31 : 8*byte]
endif

没有一句话描述,直接看 RTL 语言

解法

  • 首先明确这是一个访存指令,对于我的设计而言,只需要修改 DM 即可
  • 修改 DM 的输出逻辑使得符合题意
assign RD = ...(忽略)
    (DMOp == `DM_lwrr & byte == 2'b00) : mem[Addr[11:2]] ?
    (DMOp == `DM_lwrr & byte == 2'b01) : {mem[Addr[11:2]][7:0], mem[Addr[11:2]][31:8]} ?
    (DMOp == `DM_lwrr & byte == 2'b10) : {mem[Addr[11:2]][15:0], mem[Addr[11:2]][31:16]} ?
    (DMOp == `DM_lwrr & byte == 2'b11) : {mem[Addr[11:2]][23:0], mem[Addr[11:2]][31:24]} ?
    mem[Addr[11:2]];

关键代码如上

  • 其他的和 lw 是相同的,直接写就好

# 选择与提答

  • 选择考察 NPC 的写法,就是看熟不熟悉指令集,可以打开指令集对着仔细看看就行
  • 助教没问多少问题,也许是交的早的原因吧,看了看设计文档和代码就没了