从门电路到完整的SoC计算机系统

“一生一芯”主要回答三个问题

  1. 程序如何在计算机上运行?
  2. 如何设计一颗可支撑程序运行的处理器芯片?
  3. 如何将设计的处理器芯片转变成可流片的版图?

 

背后其实反映出两项重要的能力

  • 计算机系统软硬件协同能力
  • 处理器前后端全链条设计能力

计算机系统是个状态机

状态机模型帮助大家将程序, 指令集, 处理器关联起来

  • 建立计算机系统软硬件协同的基本认识

 

程序 抽象计算机 CPU
状态 {<V, PC>} {<R, M>} {时序逻辑电路}
状态转移规则 C语言语句的语义 指令的语义 组合逻辑电路
FM C语言标准手册 指令集手册 架构设计文档

 

  • 程序编译 = 将语句翻译成语义等价的指令序列(GCC)
  • 程序运行 = 指令序列驱动抽象计算机进行状态转移(NEMU)
  • 微结构设计 = 按照指令语义设计行为等价的电路(NPC)

程序编译 = 将语句翻译成语义等价的指令序列

  • 预处理 -> 编译 -> 汇编 -> 链接 -> 执行
  • 编译 = 词法分析 -> 语法分析 -> 语义分析 -> 中间代码生成 -> 优化 -> 目标代码生成
printf(6 - 2147483648 > 6 ? "T" : "F");
printf(6 - 0x80000000 > 6 ? "T" : "F");
printf("\n");
32位 64位
c90 TT FT
c99 FT FT
  • C语言标准中除了确切的行为, 还包含
    • Unspecified Behavior
    • Implementation-defined Behavior
    • Undefined Behavior
  • ABI手册记录了Implementation-defined Behavior的选择
    • 还反映出C语言标准, 编译器, 操作系统, 库函数, 处理器之间的协助

程序运行 = 指令序列驱动抽象计算机进行状态转移

YEMU(NEMU简化版) = 指令集模拟器 = 用C语言实现指令集手册定义的状态机

  • 自定义freestanding运行时环境
    • 只有putch()halt()两个API
    • 程序入口为_start()
    • 从地址0开始运行
  • 支持两条指令的指令周期 - addi和ebreak
    • 取指, 译码, 执行, 更新PC
void _start() {
  putch('H'); putch('e'); putch('l'); putch('l'); putch('o'); putch(','); putch(' ');
  putch('R'); putch('I'); putch('S'); putch('C'); putch('-'); putch('V'); putch('!');
  putch('\n');
  halt(0);
}

用30行Chisel代码实现YEMU - NPC简化版

全面认识RISC-V指令集

  • 从计算机系统软硬件协同的视角理解指令集
    • RISC-V的设计对软硬件设计有何影响

 

  • 指令集的7个评价标准
    • 成本, 简洁, 性能, 架构与实现分离, 提升空间, 代码大小, 易于编程/编译/链接
  • RISC-V指令集的最大特点 - 通过模块化应对不同的应用场景
    • 指令扩展可自由组合 - 嵌入式(RV32E, RV32IC), 教学(RV64IMA), 桌面(RV64GC), 高性能(RV64GCBV)
    • 通过自定义指令的模块化解决生态碎片化问题
    • 用起来像是定长的变长指令集
  • RISC-V指令集的若干设计案例
    • 指令格式, 非法指令, 立即数符号扩展, 立即数编码方式…

C程序与RISC-V - 程序的机器级表示

  • 全面理解程序和指令序列的关联
    • 常数, 变量, 运算, 条件分支, 循环, 函数调用(ABI的调用约定), 指针, 数组, 结构体, 联合体
  • 理解C程序如何精确控制机器底层行为
    • 预测写出的C代码将如何在计算机上运行

 

示例 - 手写递归版本汉诺塔的汇编代码

#include <stdio.h>
void hanoi(int n, char from, char to, char via) {
  if (n == 1) { printf("%c -> %c\n", from , to); }
  else {
    hanoi(n - 1, from, via, to);
    hanoi(1,     from, to,  via);
    hanoi(n - 1, via,  to,  from);
  }
}
int main() {
  hanoi(3, 'A', 'B', 'C');
  return 0;
}

微结构设计 = 按照指令语义设计行为等价的电路

  • 微结构设计 - 将处理器需求转变成模块结构和电路图
    • 实例化 - 应采用何种部件实现目标功能
    • 连接 - 数据应该以何种路径在各部件中流动
    • 控制 - 有多条路径时, 应该如何选择正确的路径实现需求
    • 前两者合起来即数据通路

 

  • RTL设计 - 将电路图转换为代码
    • 回归RTL设计的本质, 远离行为建模
    • RTL设计 = 直接描述电路结构 = 实例化 + 连线
      • 和微结构设计非常相似
      • 再次说明行为建模不是一种好的RTL设计范式

要运行更多程序, 还需要运行时环境的支持

AM = 按照计算机发展史将计算机功能抽象模块化裸机运行时环境

  • 按计算机发展史模块化 - 从需求的角度启发我们如何设计计算机
    • AM = TRM + IOE + CTE + VME + MPE
    • 图灵机 -> 冯诺依曼机 -> 批处理系统 -> 分时多任务 -> …
  • 裸机运行时环境 - 软硬协同地揭示程序与计算机的关系
    • (在CPU中)实现功能 -> (在AM中)提供运行时环境 -> (在应用层)运行程序
    • (在CPU中)实现更强大的功能 -> (在AM中)提供更丰富的运行时环境 -> (在应用层)运行更复杂的程序
  • 抽象 - 支持各种计算机和程序, 打通系统方向各课程实验的关键
    • cputest, coremark, microbench, FCEUX, 甚至是OS及其软件栈
    • x86-nemu, mips32-qemu, riscv64-npc, 甚至是Linux native

AM是个多源文件的项目, 需要了解链接

  • 现代工具链以源文件为单位进行编译/汇编, 然后链接成可执行文件
    • 但编译/汇编都无法处理跨节的函数和数据引用

 

  • 链接 = 符号解析 + 重定位
    • 符号解析 = 将符号的引用与符号的定义建立关联
    • 重定位 = 合并相同的节, 确定符号的最终地址, 并将其填写到引用处
// main.c
#include <stdio.h>
int a = 0, b = 0;
extern void f(), g();
int main() { 
  f(); printf("a = %d(0x%08x), b = %d(0x%08x)\n", a, a, b, b);
  g(); printf("a = %d(0x%08x), b = %d(0x%08x)\n", a, a, b, b);
  return 0;
}
// f.c
void f() { extern float  a; a = -1.0; }
// g.c
void g() { extern double a; a = -1.0; }
运行输出结果:
a = -1082130432(0xbf800000), b = 0(0x00000000)
a = 0(0x00000000), b = -1074790400(0xbff00000)

+IOE, 支持输入输出的计算机系统

  • 物理世界
    • 用户操作设备
  • 设备的电气部分
    • 将用户的操作转换成电气信号
  • 设备控制器
    • 将模拟信号转换成数字信号, 通过设备寄存器提供设备功能的抽象
  • CPU I/O指令
    • 访问这些设备寄存器, 让数字信号变成指令的操作数
  • AM的IOE抽象
    • 进一步提供I/O指令和常用设备的抽象
  • 程序
    • 用IOE的API编程, 实现游戏

+CTE, 指令执行可能失败

异常 = 一种特殊的跳转

  • CPU
    • 按照手册约定, 发生异常时跳转到一个预先设定的位置
    • 通过CSR保存部分状态(RTFM)
#include <klib.h>
void handler() {
  uintptr_t mepc;
  asm volatile ("csrr %0, mepc" : "=r"(mepc));
  printf("exception at mepc = %p\n", mepc);
  while (1);
}

int main() {
  asm volatile ("csrw mtvec, %0" : :"r"(handler));
  asm volatile (".word 0"); // illegal instruction
}
  • AM的CTE抽象
    • 把异常抽象成事件, 提供事件处理模型
  • 上层应用
    • 决定如何处理事件

 

  • 真实应用
    • 系统调用, SBI调用, 指令模拟, 处理不对齐访存, 上下文切换…

基于CTE机制的计算机系统软件栈

  • 操作系统的加载器(loader)按照链接后的地址将用户程序加载到内存, 并跳转到用户程序的入口_start()
  • 在操作系统提供的运行时环境下提供相应的API
TRM AM 操作系统 | IOE AM 操作系统
程序入口 main() 加载器 | 输入 ioe_read() SYS_read
退出方式 halt() SYS_exit | 输出 ioe_write() SYS_write
打印字符 putch() SYS_write | 设备 时钟/键盘/VGA 设备文件抽象
堆区 heap SYS_brk |
  • 虚拟文件系统提供文件抽象, 并将所有对象看作文件
  • 操作系统通过系统调用向用户程序提供服务
  • 库函数封装了操作系统的服务, 提供更方便的接口
    • 包含自陷指令的内联汇编 -> 系统调用封装函数 -> 系统级I/O库函数 -> C标准I/O库函数 -> 面向应用程序的运行库 -> 应用程序

回到硬件, 用RTL实现IOE的机制

真实的处理器通过总线和其他设备通信

  • 总线 = 接口信号 + 状态机
    • 通过状态机控制接口信号实现通信

 

  • 处理器内部总线
    • 状态机不同的控制方式, 可实现不同微结构的处理器
    • 单周期, 多周期, 流水线, 乱序执行…
    +-----+ inst  ---> +-----+  ...  ---> +-----+  ...  ---> +-----+
    | IFU | valid ---> | IDU | valid ---> | EXU | valid ---> | WBU |
    +-----+ <--- ready +-----+ <--- ready +-----+ <--- ready +-----+
  • 存储器总线
    • 只读存储器同步总线 -> 可读写存储器同步总线 -> 可读写存储器异步总线(AXI-Lite)
    • 通过总线实现处理器和存储器的解耦, 无需关心对方的内部细节

通过总线接入SoC, 实现真实的完整计算机系统

  • 支持TRM的最简单SoC - ROM + UART
  • 实用的SoC - 现场可编程Flash(通过SPI协议通信, 程序只读) + SDRAM(程序可写)
    • XIP模式 - 通过状态机将CPU读请求在线翻译成Flash颗粒的请求
  • 支持IOE的SoC - 加入更多设备: 时钟, PS2, VGA…

 

  • 完整的计算机系统
    • 软件代码描述访问设备的逻辑
    • CPU通过MMIO指令访问设备
    • 总线将各种设备控制器连接起来, 为CPU提供访问设备的事务通道
    • 各种IP核实现了设备控制器, 通过总线接收来自CPU的请求
    • 设备控制器根据器件通信协议(也是一种总线)与器件通信

先完成, 后完美 - 体系结构优化

  • 在优化之前, 需要有一个量化指标
    • 通过看程序是否跑得更快, 来判断优化技术是否有正向收益
    • 通过分析程序的运行情况, 找到系统中的性能瓶颈, 并估计潜在收益
  • 这就是profiling, 针对体系结构优化, 我们关心的是
    • CPU执行程序时, 在哪些地方发生阻塞/等待?
    • 在这些地方具体等待了多久?
  • 科学的性能瓶颈定位方法:
    1. 通过性能计数器统计阻塞事件的次数
    2. 通过波形观察那些阻塞事件较多的部件的细致行为
  • 还需要跑具有代表性的benchmark

 

  • 经典体系结构的4类优化方法 - 缓存, 并行, 预测, 加速器

缓存

  • 缓存是局部性原理的重要应用
    1. 时间局部性 - 当前访问的数据, 短时间内很有可能再次访问
    2. 空间局部性 - 当前访问的数据, 短时间内很有可能访问其相邻数据
            access time       /\          capacity    price
                             /  \
               ~1ns         / reg\          ~1KB     $$$$$$
                           +------+
cache ----->   ~3ns       /  SRAM  \        ~30KB     $$$$$
                         +----------+
               ~10ns    /    DRAM    \      ~10GB     $$$$
                       +--------------+
               ~10ms  /      disk      \     ~1TB      $$
                     +------------------+
               ~10s /        tape        \  >10TB       $
                   +----------------------+

 

  • 缓存的设计空间很大 - cache块的大小/关联度/替换算法/写策略/…
  • 设计空间探索需要用较低的开销评估命中率, IPC等容易评估的指标
    • 通过较低成本过滤掉某些不达标的设计
    • 通常在功能模拟器/全系统模拟器上开展
    • 最后才在RTL层次考虑主频和面积

加速器 - 功能单元

  • 加法器 - RCA, CLA, CSA
  • 乘法器 - Booth算法, 基4-Booth算法, 华莱士树
  • 除法器 - 恢复余数法, 不恢复余数法, 高基SRT除法

 

             A/B12~15   A/B8~11   A/B4~7    A/B0~3
                ||        ||        ||        ||
         +---------------------------------------------+
S0~3  <--|------||--------||--------||------+ ||       |
S4~7  <--|------||--------||------+ ||      | ||       |
S8~11 <--|------||------+ ||      | ||      | ||       |
S12~15<--|-+    VV      | VV      | VV      | VV       |
         | | +----+    +----+    +----+    +----+      |
         | +-|4CLA|<-+ |4CLA|<-+ |4CLA|<-+ |4CLA|<--+--|--C0
         |   +----+  | +----+  | +----+  | +----+   |  |
         |      ||   |    ||   |    ||   |    ||    |  |
         |      VV   |    VV   |    VV   |    VV    |  |
         |  +------------------------------------+  |  |
         |  |  P3G3 C12  P2G2 C8   P1G1 C4   P0G0|  |  |
  C16 <--|--|C16  Carry Lookahead Unit(CLU)      |<-+  |
         |  |                           PG  GG   |     |
         |  +------------------------------------+     |
         | 16-bit Carry-Lookahead Adder  |   |         |
         +---------------------------------------------+
                                         |   |
                                         V   V
      +----+         |  |   +----+
 A4-->|    |------+  |  +-->|    |-->S4
 B4-->| FA |      |  +----->| FA |
 C4-->|    |---+  +-------->|    |--+
      +----+   |            +----+  |
               +-----+  +-----------+
      +----+         |  |   +----+
 A5-->|    |------+  |  +-->|    |-->S5
 B5-->| FA |      |  +----->| FA |
 C5-->|    |---+  +-------->|    |--+
      +----+   |            +----+  |
               +-----+  +-----------+
      +----+         |  |   +----+
 A6-->|    |------+  |  +-->|    |-->S6
 B6-->| FA |      |  +----->| FA |
 C6-->|    |---+  +-------->|    |--+
      +----+   |            +----+  |

指令级并行 - 流水线

  • 流水线 = 让处理器的不同阶段处理不同的指令
  • 理想情况下, 5级流水线处理器执行程序的效率是单周期处理器的5倍
  • 但实际上有冒险问题, 需要检测并处理
    • 结构冒险 - 消极等待, 添加硬件部件避免竞争, 部件流水化
      • 总线的通信方式自动实现了等待功能
    • 数据冒险 - 消极等待, 数据转发
    • 控制冒险 - 消极等待, 分支预测

 

  • 站在SoC软硬件全系统的角度理解各个模块之间的影响
  • 通过性能计数器科学地定位流水线当前的性能瓶颈

学会独立解决问题

不畏惧新问题/新知识 - STFW, RTFM, RTFSC

遇到问题时知道去哪里找到正确的答案

 

  • 手册 - C语言标准, ABI手册, 指令集手册, IP核手册, Flash颗粒手册, GCC/LLVM手册, Verilator手册…
    • 蕴含你对计算机系统工作原理的认识

 

  • 社区 - stackoverflow, wikipedia, github issue区, mailing list…
    • ChatGPT - 但不一定能得到正确的答案, 需要有能力核实

 

  • 项目 - README, 文档, 源代码, 构建脚本…
    • 尽最大努力理解一切细节

科学地写代码

  • 仔细RTFM, 正确理解需求
  • 好代码的两条重要准则
    • 不言自明 - 仅看代码就能明白是做什么的(specification)
    • 不言自证 - 仅看代码就能验证实现是对的(verification)

 

使用正确的编程模式写出好代码, 降低出错的可能

  • 防御性编程 - 通过assert检查非预期行为
  • 减少代码中的隐含依赖 - 使得 “打破依赖”不会发生
    • 头文件 + 源文件
  • 编写可复用的代码 - 不要Copy-Paste
  • 使用合适的语言特性 - 把细节交给语言规范和编译器
    • 用Chisel写译码器和华莱士树生成器

测试验证

  • 进行充分的测试
    • 将Fault转变成Error
    • 先完成, 后完美 - 先运行足够多的程序测试处理器/模拟器

 

  • 添加充分的断言
    • 将Error转变成Failure

 

  • 使用现代工具辅助测试验证
    • DiffTest - 在线指令级行为差分测试
    • z3 - 形式化验证, 通过SMT求解器自动证明代码的正确性
    • libAFL - 模糊测试, 自动生成测试用例

用正确的工具和方法解决bug

  • 心态上 - 调试公理
    • 机器永远是对的
    • 未测试代码永远是错的

 

  • 技能上 - 知道用什么样的工具快速解决问题
    • lint工具 - 检查静态代码, -Wall, -Werror
    • sanitizer - 动态检查内存错误, UB等
    • printf - 查看程序状态
    • trace - 特定功能的printf, 可二次分析
      • 自顶向下理解程序行为: ftrace, itrace, mtrace, dtrace, etrace
    • gdb/sdb - 查看程序的所有细节
    • 波形 - 查看电路的所有细节

性能bug

  • 使用profiler发现性能瓶颈
    • 了解程序的运行时间都花在哪里
99.99%     0.00%  callgraph  [unknown]
        |
        ---0x64e258d4c544155
           __libc_start_main
           main
           |
           |--58.81%--A
           |          |
           |          |--23.57%--C
           |          |
           |           --23.52%--B
           |                     |
           |                      --11.78%--C
           |
           |--23.51%--B
           |          |
           |           --11.78%--C
           |
            --11.79%--C

项目维护和管理

  • 学会使用正确的工具做正确的事情
    • 读/写代码 -> 编辑器及其高级功能
    • 代码编译和管理 -> make
    • 终端分屏 -> tmux
    • 加速编译 -> ccache, icecream
    • 自动编译运行 -> inotifywait
    • 调试代码 -> trace, DiffTest, gdb, …

 

  • 工具不够用的时候, 学会改进/制造新工具
    • 如果你想走得更远, 这是必须的
    • 从小事做起 - 理解代码中的每一处细节

通过构建计算机系统, 锻炼解决未知问题的能力

通过构建计算机系统, 锻炼解决未知问题的能力(2)

第五期课程总结

第一次准备课堂教学, 手忙脚乱 😂

  • 课件从零开始做, 每周需要花大约一半时间, 持续21周
    • 周六晚上直播, 一般周四早上就要开始做了

 

  • 最近半年每周的我: 3天做课件, 2天开会, 2天推进其他事情
    • 多的时候一周开9个会 😵
    • 有时候突然要写份材料, 或者做个ppt, 其他事情也没法推进了
  • 有几次事情太多, 拖到周五下午才开始做课件, 觉都没睡好 😂
    • 幸好之前在其他场合做过相关报告: AM, Difftest, 仙剑, 总线
      • 这些素材救我一命
    • 有想过🕊一周, 但还是不想松懈, 最后坚持下来

 

  • 上一次的类似经历是10年前在学校带OS实验课, 学校的课还没法🕊

痛苦中的快乐: 重温把一件事情讲清楚的乐趣

  • 如: CLA引入P和G只是换个角度理解进位, 为什么能降低进位延迟?
    • 研一上过胡老师的系统结构课, 当时也没细想这个问题
    • 这次备课思考了本质原因 - 通过表达式变换对电路进行平衡处理
      • 果然读了博士还是会本能地追求事物的本质(职业病 😂)
  • 更多例子: DiffTest的好处, 行为建模的问题, 总线从简单到复杂的过渡…

 

It's very satisfying to take a problem we thought difficult and find a simple solution. The best solutions are always simple.

-- Ivan Sutherland

 

教学的 “神之一手” - 用简单的话将一件复杂的事情讲清楚

课程自评

  • 课件的质量还算可以 ✔️
    • 广阔的视野 - 从程序到门电路
    • 理论模型 - 状态机
    • 融合科学的理念 - 计算机发展史, 先完成/后完美, 工具
    • 代码示例 - YEMU, NPC版YEMU, 总线状态机, 一些方便的脚本…
  • 但也远没到满意的程度 ✖️
    • 不少内容能看得出来是临时上线的(没时间细化)
      • SoC课件的后半部分, 除法器, 形式化验证, libAFL
    • 有的内容本来想讲, 但最后压根没出现
      • 动态链接, 中断嵌套, 数电基础, 时序概念, 验证
      • NVBoard在预学习之后再也没出现了
    • 只能说, 先完成, 后完美: 有了这次积累, 下一期改起来应该轻松不少

遥遥无期的S阶段

  • 临时请香山团队帮忙, 给大家凑了6个报告
    • 处理器前端, 乱序流水, 乱序访存, 缓存, 性能迭代加速, 敏捷开发方法和工具
    • 感谢香山团队的支持

 

立个第六期的Flag给大家看看

  1. 完善课件的已知问题
  2. 将课件内容同步到讲义
  3. 添加更多的示例代码
  4. 添加开源EDA
  5. 添加性能优化目标
  6. 出个基于开源EDA的后端学习讲义
    • 我自己都还没学会, 这个Flag看看就好
  7. 改进直播和录制效果
    • 之前用的笔记本, 开OBS风扇狂转, 把风扇声音录进去了
    • 设置降噪后效果也不明显
      • 更高级的降噪算法需要耗费更多CPU算力 😂
    • 已经换了一个比较安静的笔记本

欢迎大家提建议

  • B站有很多留言和弹幕, 我都看了, 但很少回复
    • 建议 - 记下来了, 但大部分因为时间原因还没实施
      • 例如, 建议加一个显示按键的插件
        • 找了一个简单试了一下, 发现输入密码时会暴露, 就没有仔细研究了
    • 不同的声音 - 无论我是否同意, 某种程度上来说都是我没讲好
      • 下一期备课的时候再想想怎么讲

 

  • 在此统一回复
    • 低情商: 再等等吧
    • 高情商: 求大家给社畜施舍一些高质量时间

从不完美开始

  • 其实项目组知道, “一生一芯”作为一个复杂系统, 本身还存在很多问题
    • 不仅是教学部分, 还有助教, 组织流程, 支撑, 社区…
    • 但无法一开始就把所有问题都想清楚, 只能在做的过程中改进完善

 

  • 这和大家学习 “一生一芯”是很类似的
    • 大多数同学的第一版代码也并不完美, 都有各种问题
    • 有的同学希望少走弯路, 一次写出一份好代码
      • 从客观规律上来看, 这是不现实的
    • 有问题的代码反映的是你的认知水平, 是你交的 “学费”
      • AXI手册包含所有细节, 但你还是没法一次全写对, 要不断看手册
  • 积极意义: 当你对当前感到不满, 你已经变强了, 可以开始新一轮学习
    • 做过 != 做得好

我的处理器设计经历 - 新知识刷新对 “做得好”的认识

  • 大二下学期(2012年)组成原理课程实验
    • 年少无知, 当时觉得自己写得很好, 现在不堪回首
  • 研一(2015年)有点课余时间, 想重写一个
    • 大四期间完成计算所的课题, 对处理器和RTL设计有新的认识
    • 想通过更科学的方式写一个处理器, 但研二之后投入项目, 就搁置了
  • 2019年, 以改革南大的组成原理实验为目标重写一个
    • 2018年, 南大师弟凭借Chisel, Verilator和DiffTest获得龙芯杯一等奖
    • 有更多现代工具, 可以再写一个好的 - 经验传给 “一生一芯”和香山
  • 2023年的现在, 我又手痒了
    • Chisel和Verilator版本在演进, 提供更多功能
    • 接触到z3, libAFL等现代工具, 香山团队也有不少基础设施
    • 解老师团队在设计开源EDA工具, 是个学习后端设计的好机会

一直在思考的问题: 如果把事请做到极致, 该怎么做?

  • 具体又分两个问题
    • 处理器设计有哪些评价标准?
      • 正确 – 这是最基本的
      • 软件支持 – 排序 or OS
      • 微结构复杂度 – 单周期, 流水线, cache, 分支预测…
      • 性能 – IPC, 主频
      • 面积 – 不能超过流片面积预算
      • 功耗 – 暂时不关注
      • 可配置性
      • 代码可读性/可维护性
    • 如何科学兼顾多个维度(正确性只是其中之一), 尽量把处理器做好?
      • “一生一芯”的学习路线, 来源于对这个问题的回答

大家疑惑的问题1 - 为什么芯片设计要学软件/环境?

  • AM, Nanos-lite, Navy-apps - 软件如何在处理器芯片上运行
  • NEMU, DiffTest, 仿真环境, 测试框架, 工具 - 如何快速测试/验证
    • UVM本质上也是软件/环境的工作
    • 还有z3, libAFL…
  • 模拟器, benchmark, profiling - 如何评估一个微结构特性的收益
  • 代码复用, 代码抽象, 语言特性 - 如何更好地维护项目

 

  • 两个本质原因
    • 处理器本身就是用来运行软件
    • 处理器芯片设计已经从以前的面包板设计转变为现在的代码开发
      • 代码即软件 - 即使它描述的是硬件
      • 需要使用合适的软件工程技术管理/维护/优化代码

科学评价RTL的作用和局限

  • 有同学对RTL过分执着, 认为用DPI-c实现存储器 “不够纯正”
  • 但我们得到了
    • DiffTest的内存操作API
    • 容易实现的设备模型
    • 输出灵活的mtrace
    • 更多高级功能 - 内存镜像压缩, 多核的内存一致性检查…

 

  • 接入SoC后用的是flash/SDRAM, 也不会采用RTL实现的ROM/RAM
    • flash/SDRAM的仿真也使用颗粒模型
  • 需要看到处理器设计的更多评价指标, 结合实际场景解决问题
    • 仅仅追求表面上的美感, 意义不大

大家疑惑的问题2 - 流水线的学习为什么放在最后?

同学喜欢的顺序: 单周期 -> 流水线 -> cache -> 总线 -> 仙剑

  • 大多按教科书从详细到简略的顺序, 但在项目方面说不出合理性

 

  • 流水线, cache, 总线只能跑很少的测试, 最后才暴露各种问题, 难调试
  • 做完所有硬件模块才能测量出真实的性能
    • 添加流水线和cache时, 测量出的性能并不能代表接入SoC后的性能
    • 可能被误导, 开始觉得某特性提升性能, 但接入SoC后反而下降
      • 你还不容易知道是哪一些特性
  • 很少能全面思考其中的问题
    • 只关注流水线的功能, 很少将其性能与SoC和程序关联
      • 书上的不少假设, 在SoC中不再成立
    • 实现方案能跑对, 但不一定合适 - 需要根据实际场景来制定

大家疑惑的问题2 - 流水线的学习为什么放在最后?

讲义顺序: 单周期 -> 仙剑 -> 总线 -> cache -> 流水线

 

  • 先尽量跑更多软件, 然后用软件测试硬件, 再用硬件测试其他硬件
    • 用仙剑充分测试单周期, 用这个单周期充分测试总线…
    • 每一次都基于相对稳定的设计添加新功能
  • 接入总线后即可测量出与将来接入SoC后相对一致的性能
    • 真正理解每一个特性带来的性能提升
  • 站在全局的角度理解各个模块之间的影响
    • 既包括硬件之间, 也包括硬件-ISA-软件
    • 用总线思想实现流水线的分布式控制

 

即使是学过/做过的内容, 重新思考也会带来新的认识

希望大家能用掌握的知识和能力,
追求更高的目标