北航计组P5P6上机

2024-11-15

北航计组P5和P6上机题型分类与通用解法

前言

  • 本文主要围绕P5和P6的往年题进行分类讲解与解题方法剖析,涵盖运算类指令、条件跳转类指令、条件储存类指令和特殊类指令等内容。详细阐述了各类指令在不同题型中的特点与应对策略,并给出了具体的解题套路和公式,旨在帮助读者深入理解相关知识,提升解决此类问题的能力,为应对 P5&P6 相关考试或学习任务提供全面且系统的提示

P5&P6往年题及分类

  1. 运算类指令
    • R/I型指令(类似add/ori)
    • 1.将GPR[rs]中偶数位与GPR[rt]偶数位进行异或,奇数位保持不变结果存入GPR[rd]中
    • 2.将GPR[rs]中所有位的低GPR[rt]个0替换为1,若不够就全部替换,结果存放到GPR[rd]
    • 3.把GPR[rs]循环移位得到的32个结果无符号求和,把GPR[rt]循环移位得到的32个结果无符号求和,比较这两个结果,计算结果存入rd寄存器中
    • 4.如果GPR[rt]为奇数,则把GPR[rs]循环左移,左移位数是GPR[rt]的低五位,如果GPR[rt]为偶数,则把GPR[rs]循环右移,右移位数是GPR[rt]的低五位,结果存入rd寄存器中
    • 5.把立即数进行1扩展,然后与GPR[rs]相加,如果发生溢出,则向rt寄存器中写入1扩展的立即数,否则向rt寄存器中写入加法的结果 - 乘除指令(类似mult)
    • 6.读取GPR[rs]和GPR[rt],用较大的数除以较小的数(看作无符号数)
    • 7.交换HI、LO寄存器的值
  2. 条件跳转类指令
    • 跳转并链接(类似jal)
    • 8.如果GPR[rs]与GPR[rt](看作有符号数)之中较小的数为偶数,则当前指令会以pc+4为基址,offset为偏移量进行跳转,否则清空延迟槽,无论是否跳转,都需要将pc+8存入31号号存器中
    • 9.比较pc加上偏移的结果与GPR[rs]+GPR[rt]的大小,如果前者小于后者,则以pc+4为基址,offset为偏移量进行跳转,否则跳转到GPR[rs]+GPR[rt]并清空延迟槽,无论何种跳转,都需要将pc+8存入31号号存器中
    • 10.如果GPR[rs]和GPR[rt]互为相反数,则以pc+4为基址,offset为偏移量进行跳转,否则不跳转,无论是否跳转,都需要将pc+8存入31号号存器中
    • 11.如果GPR[rs]的值小于0,则跳转到offset+2^k条指令后的位置,其中k为GPR[rt]的低两位,否则不跳转,无论是否跳转,都需要将pc+8存入31号号存器中 - 只跳转不链接(类似beq)
    • 12.如果GPR[rs]的最高位与GPR[rt]的相同,则以pc+4为基址,offset为偏移量进行跳转,GPR[rs]等于0或GPR[rt]等于0时不跳转
  3. 条件储存类指令(类似lw)
    • 13.读取Memory[GPR[base]+offset],假如该值小于0x80000000,将其写入特定寄存器中,否则写入rt寄存器,特定寄存器号为读取值的后四位,故而在GPR[0]~GPR[15]之间
    • 14.读取Memory[[GPR[base]+offset],将0扩展的rt本身,存入特定寄存器,特定寄存器号为主存读取值的后四位
    • 15.读取Memory[[GPR[base]+offset],写入特定寄存器中,特定寄存器号的计算方法是,将GPR[rt]和主存读出数据进行异或,得到的结果取低五位,特定寄存器号是小于或等于这个数的最大质数,如果没有这样的质数,特定寄存器号为0
    • 16.读取Memory[[GPR[base]+offset]的半字,判断这个半字中1的个数是否大于0的个数,如果1的个数多,就把这个半字到存入rt寄存器中 ,否则将pc+4存入31号号存器中
    • 17.读取Memory[[GPR[base]+offset]的字节,如果读出结果小于0,将结果写入base寄存器,否则写入rt寄存器中
    • 18.读取Memory[[GPR[base]+offset],写入特定寄存器中,特定寄存器号的计算方法是,将主存读出数据与GRF[rt]相加后,计算结果与0x1e进行与运算
    • 19.读取Memory[[GPR[base]+offset],如果读取数据大于GPR[rt],则将其写入5号寄存器中,否则写入4号寄存器中
    • 20.读取Memory[[GPR[base]+offset],如果读取数据大于等于0x00003000并且低两位都是0,就写入31号寄存器中,否则写入rt寄存器中
  4. 特殊类指令
    • 条件写入
    • 21.当GPR[rt]大于0时,将GPR[rs]写入rd寄存器中,否则不进行写入
    • 22.如果GPR[rt]等于0,则跳转到GPR[rs]所在的地址,并且将pc+8存入31号存器中,否则不进行写入 - 复杂操作
    • 23.读取29号寄存器的值,作为地址将pc+8写入内存,而后29号寄存器的值减4,再写回29号寄存器,最后跳转到立即数对应的地址

解题套路

  1. 运算类指令:修改E段结果的计算方法
    • R/I型指令(类似add/ori)
    • 控制信号
      • 修改ALU的计算类型选择信号
      • 其余与add/ori相同
    • 顶层模块:
      • 在ALU中添加添加一种用于新指令的计算方法
        • 乘除指令(类似mult)
    • 控制信号
      • 修改乘除单元的计算类型选择信号
      • 修改busy的时钟周期数
      • 其余与mult相同
    • 顶层模块
      • 在乘除单元中添加一种用于新指令的计算方法
      • 根据运算时间需求,修改busy的时钟周期数
  2. 条件跳转类指令:修改D段的比较方法,添加FD级寄存器的清空操作
    • 跳转并链接(类似jal)
    • 控制信号
      • 修改比较模块的比较方法选择信号
      • 修改跳转方法选择信号
      • 设置Tuse,D段需要立即用到rs和rt的读出结果进行判断,D段两个Tuse均设置为0
      • 设置Tnew,由于需要将D段的PC+8被写入寄存器,E、M、W段的Tnew设置为0
      • 改为有符号的立即数拓展
      • 其余与jal相同
    • 顶层模块
      • 在比较模块中添加添加一种用于新指令的计算方法
      • 新增一种用于新指令的跳转方法
      • 如果需要清空延迟槽,在满足该指令的清空条件,且不处于阻塞态时,复位FD级寄存器
        • 只跳转不链接(类似beq)
    • 控制信号
      • 修改比较模块的比较方法选择信号
      • 修改跳转方法选择信号
      • 其余与beq相同
    • 顶层模块
      • 在比较模块中添加添加一种用于新指令的计算方法
      • 新增一种用于新指令的跳转方法
  3. 条件储存类指令:预测可能写入的寄存器,基于此修改阻塞逻辑
    • 控制信号
      • 修改W段写入寄存器地址的控制信号
      • 如果需要使用寄存器数据参与判断,将前段寄存器数据传到W段
      • 其余与lw相同
    • 顶层模块
      • 在W段新增一个用于确定新指令写入寄存器号的逻辑
      • 预测可能写入的寄存器号,构成一个集合,并去除0号寄存器
      • 增加阻塞逻辑:E或M级指令是新指令 且 需要写入寄存器 且 Tuse < Tnew 且 D段读取的寄存器在预测寄存器集合中
  4. 特殊指令:具体问题具体分析
    • 条件写入
      • 特判寄存器的写使能信号:W级是新指令 且 满足条件
    • 复杂操作
      • 特殊处理特殊部分的选择信号

公式做题就是快

  1. P5上机第二题
    • 题干:比较pc加上偏移的结果与GPR[rs]+GPR[rt]的大小,如果前者小于后者,则以pc+4为基址,offset为偏移量进行跳转,否则跳转到GPR[rs]+GPR[rt]并清空延迟槽,无论何种跳转,都需要将pc+8存入31号号存器中
// 1.D_CU.v 修改比较模块的比较方法选择信号
assign cmpOp = new ? `cmpOp_new;

// 2.D_CU.v 修改跳转方法选择信号
assign pcOp = new ? `pcOp_new;

// 3.D_CU.v 设置Tuse为0
assign rsTuse = new ? 2'b00;
assign rtTuse = new ? 2'b00;

// 4.E_CU.v M_CU.v W_CU.v 设置Tnew为0
assign Tnew = 2'b00;

// 5.mips.v 改为有符号的立即数拓展
assign extOp = new ? `signed_extend;

// 6.D_Cmp.v 在比较模块中添加添加一种用于新指令的计算方法
.cmpIn1 ((D_instr == new) ? D_pc + (D_extend_offset << 2) : D_rsData),
.cmpIn2 ((D_instr == new) ? D_rsData + D_rtData : D_rtData),
assign cmpRes = (cmpOp == `cmpOp_new) : (cmpIn1 < cmpIn2);

// 7.mips.v 新增一种用于新指令的跳转方法
assign F_nextPc = 
(pcOp == `pcOp_new) ? (D_cmpRes ? (D_pc + (D_extend_offset << 2) + 4) : (D_rsData + D_rtData));

// 8.mips.v 在满足该指令的清空条件,且不处于阻塞态时,复位FD级寄存器
.reset (reset || (D_instr == new && !D_cmpRes && !stall)),
  1. P5上机第三题
    • 题干:读取Memory[GPR[base]+offset],假如该值小于0x80000000,将其写入特定寄存器中,否则写入rt寄存器,特定寄存器号为读取值的后四位,故而在GPR[0]~GPR[15]之间
// 1.W_CU.v 修改W段写入寄存器地址的控制信号
assign writeDataOp = new ? `writeDataOp_new;

// 2.mips.v 在W段新增一个用于确定新指令写入寄存器号的逻辑
assign W_writeAddr = `writeDataOp_new ? (W_memRead < 32'h80000000 ? {1'b0, W_memRead[3:0]} : W_rt);

// 3.预测可能写入的寄存器号,构成一个集合,并去除0号寄存器
// 本题可以写入的寄存器集合是 1-15 号寄存器

// 4.mips.v 增加阻塞逻辑:E或M级指令是新指令 且 需要写入寄存器 且 Tuse < Tnew 且 D段读取的寄存器在预测寄存器集合中
assign stall =   
  (E_instr == new ? (D_rs > 0 && D_rs < 16 : D_rs == E_writeAddr) && D_rsTuse < E_Tnew && D_rs && E_regWE)
||(M_instr == new ? (D_rs > 0 && D_rs < 16 : D_rs == M_writeAddr) && D_rsTuse < M_Tnew && D_rs && M_regWE)
||(E_instr == new ? (D_rt > 0 && D_rt < 16 : D_rt == E_writeAddr) && D_rtTuse < E_Tnew && D_rt && E_regWE)
||(M_instr == new ? (D_rt > 0 && D_rt < 16 : D_rt == M_writeAddr) && D_rtTuse < M_Tnew && D_rt && M_regWE);

总结

本文针对 P5&P6 往年题进行了全面的整理与分析,通过对运算类、条件跳转类、条件储存类和特殊类指令的分类,详细介绍了各类指令的题型特点及解题方法。解题套路部分明确了针对不同指令类型在修改控制信号、顶层模块设计等方面的具体操作,如运算类指令需修改计算方法选择信号,条件跳转类指令要修改比较和跳转方法选择信号等。同时,通过 P5 上机第二题和第三题的实例,展示了如何运用这些方法进行解题,包括具体的代码实现和逻辑判断。这些内容有助于读者系统地掌握 P5&P6 相关知识,提高解决此类问题的效率和准确性,为相关学习和考试提供有力的支持

参考资料

  • https://flyinglandlord.github.io/2021/12/02/BUAA-CO-2021/P5/P5%E8%AF%BE%E4%B8%8A1&2/
  • https://flyinglandlord.github.io/2021/12/08/BUAA-CO-2021/P6/P6%E8%AF%BE%E4%B8%8A&%E8%AF%BE%E4%B8%8B/
  • https://blog.csdn.net/i_want_ak_noip/article/details/134387219?spm=1001.2014.3001.5502
  • https://blog.csdn.net/i_want_ak_noip/article/details/134519307
  • https://blog.csdn.net/2202_75827814/article/details/142219966