CS152 · Homework 1 导读
这份导读帮你理解 HW1 在考什么、需要哪些前置知识、如何组织解题思路。它不包含任何完整解答——官方解答会在截止日期后由课程组发布,这里只帮你搭建理解问题所需的概念框架。
一句话总结:用同一段"循环左移 n 位"的 C 代码,横向比较 CISC(x86)、RISC(RISC-V)、栈式(stack)、累加器式(accumulator)四种 ISA 风格在代码体积、取指字节数、访存字节数上的真实差异;然后动手给一台微编码 RISC-V 机器新增两条自定义指令;最后回到第 4 课的 Iron Law,判断一系列微架构改动对性能三要素分别有什么影响。
| 题目 | 对应课程 | 核心概念 |
|---|---|---|
| Problem 1:CISC/RISC/栈式/累加器式 ISA 对比 | 第 1、2 课 | ISA 风格如何影响代码体积与访存流量 |
| Problem 2:微编码实现新指令 | 第 2、3 课 | 寄存器传输级微指令、微码 ROM 表格 |
| Problem 3:6 级流水线的旁路与精确异常 | 第 4 课 | 旁路路径、写回端口、精确异常 |
| Problem 4:CISC vs. RISC 情景判断 | 第 2、3 课 | 技术条件如何决定 ISA 风格的选择 |
| Problem 5:Iron Law 表格 | 第 4 课 | 区分"指令数/CPI/周期时间"三者各自的变化 |
MA:=PC)、微码 ROM 的地址/数据位宽计算、技术条件如何决定硬连线 vs. 微编码的选择Time/Program = Instructions/Program × CPI × Cycle Time)、经典 5 级流水线、旁路 vs. 互锁、精确异常与提交点题目给出一段"循环左移 n 位"的 C 函数,先展示它在 x86(CISC,变长指令)上编译出的真实汇编。你需要分别把这段逻辑翻译成:
x=0x01020304, n=5)、访存加载/存储字节数PUSH/POP/OR/SHL/SIGN/DEC/BEQZ/BNEZ/JUMP 指令集翻译,注意题目假设栈顶两项有寄存器缓存、更深层的栈访问才需要额外的内存引用LOAD/STORE/OR/SHL/SIGN/INC/DEC/SWAP/ZERO/BEQZ/BNEZ/JUMP 指令集翻译,题目额外引入了一个"副累加器"简化编程解题的关键提醒:题目每种 ISA 都给出了精确的指令字节宽度表——这不是可以跳过的细节,"代码体积""取指字节数""访存字节数"这三个问题必须基于这些具体位宽精确计算,而不能只凭直觉估算。四种 ISA 得出的数字差异,正是第 1 课"ISA 是软件可见契约"与第 2、3 课"CISC→RISC 技术论证"两条线索在具体数字上的交汇点——你可以直接用这道题的计算结果,去检验"RISC 代码通常更长但每条指令更简单"这类经验判断是否站得住脚。
基于第 2、3 课讲过的单总线微编码 RISC-V 数据通路("Handout #1 Bus-Based RISC-V Implementation"),题目要求你直接在微码 ROM 的表格里填写寄存器传输级的微指令:
MODULOM rd, rs1, rs2,语义是 M[rd] ← M[rs1] % M[rs2]。由于 ALU 本身不支持取余/除法,需要把取模运算实现成一个减法循环(while(x>=y) x-=y; return x;),并保证代码不破坏 rd/rs1/rs2 等通用架构寄存器,最终要通过微跳转(microbranch)回到 FETCH0。MINV rd, rs1, rs2,在内存中一段无符号整数向量(起止指针分别是 rs1/rs2)里找最小值,写入 rd。题目允许在执行过程中修改 rs1,并要求尽量减少所用的周期数、尽量多用"don't care"简化控制信号。SUB、ANDI、LW、taken/not-taken 的 BNE/BEQ、J、JAL、JALR、AUIPC),推算各自在微编码实现中需要多少个周期,并指出哪条指令周期数最多、哪条最少。与 Lab 1 的直接呼应:题目明确建议参考 Sodor 微编码核心的真实源码 rv32_ucode/microcode.scala——但同时提醒"该微码虽然通过了所有测试,但不保证是最优实现,甚至可能仍有 bug"。这正好印证了第 2 课里对 JAL/Branch 微码"教学草图 vs. 真实 RTL"这条提醒:做这道题时,光靠幻灯片伪代码可能不够精确,必须去读真实的 Chisel 源码来确认每个控制信号的确切含义。
题目把第 4 课的经典 5 级流水线扩展成 6 级:把访存阶段拆成 M1/M2 两级(对应两周期延迟的数据缓存),然后提出一个具体的硬件改动方案——让所有整数运算指令直接在执行阶段末尾写回寄存器堆(需要新增一个写端口),而不必等到写回阶段:
这道题是第 4 课"精确异常与提交点"最直接的应用:一旦允许"提前写回",就打破了"所有指令按顺序到达同一个提交点"的假设——而这个假设正是第 4 课里保证精确异常的核心机制。解题时应该回到第 4 课明确提出的问题:"如何处理多个流水级同时出现的异常?"来systematically 组织你的论证。
四道简答题,每道给出一个具体的技术/市场约束场景,要求判断该场景更适合 CISC 还是 RISC 风格,并说明理由:
这四道题直接对应第 2、3 课反复强调的核心论点:ISA 风格的选择不是审美偏好,而是由当时的编译器技术水平和存储/逻辑的相对成本决定的——回答时应该引用第 3 课里 Cocke 的 PL.8 编译器实验、Emer/Clark 的 VAX-11/780 实测数据,以及"IC 时代 RAM 追上 ROM 速度"这条技术反转论据。
题目给出 6 种微架构/ISA 改动,要求你分别判断它们对 Iron Law 三个分量(指令数/程序、CPI、每周期时间)各自的影响方向(增大/减小/不变),以及对整体性能的影响(增大/减小/不变/含糊不清——如果含糊不清,需要说明这是一个"看情况"的权衡,并给出工程判断):
这是全课程目前为止对 Iron Law 最系统的一次综合演练:每一小题都要求你把"改动"精确拆分到指令数、CPI、周期时间三个独立维度上分别推理,而不能笼统地说"应该会更快/更慢"。特别是 (f) 小题,直接呼应第 3 课"从 CISC 到 RISC"一节讲过的真实设计(Intel Ivy Bridge 式的硬连线流水线化 CISC 机器)——可以直接用第 3 课的论据来组织答案。
问题 1:Problem 1 比较 CISC/RISC/栈式/累加器式四种 ISA 时,为什么不能只凭直觉估算代码体积和访存流量?
问题 2:Problem 3 中,为什么让整数指令提前在执行阶段末尾写回寄存器堆,可能会破坏精确异常?
sp23/hw01.pdf(Problem Set #1, Version 1.2, UC Berkeley CS152, Spring 2023)generators/riscv-sodor/src/main/scala/rv32_ucode/microcode.scala