# 执行、电路族与分片

> 单个 hart、38 位时钟、每次内存访问都是一次带时间戳的查询、23 个电路族，以及作为证明单位的分片。

## 机器

模拟器在单个 hart 上、基于一个 `ProgramImage` 运行 RV32IMAC，没有中断，也没有特权级。一次运行是映像及其输入的纯函数，没有时钟、随机数或线程，所以两次运行切出的分片完全相同。它与宿主环境中的 RV32IMAC 有三处不同：`sc.w` 总是成功；未对齐的半字或字访问是致命错误，而不会被拆分；指令流就是加载时解码的映像。

运行在到达 `EXIT` 之前停下的其他所有情形，例如访问映射区域之外的地址、`ebreak`，或者跳转到一个没有指令的半字，都是致命错误，不产生执行轨迹。这样的运行没有证明。非零退出状态不是错误：它和其他任何执行一样，是一次可证明的执行。

## 时钟与查询

周期 `c` 占据四个时间戳 `4c + Δ`，每个**槽位** `Δ ∈ {0, 1, 2, 3}` 一个。每条指令是一个周期，除此之外没有任何东西是周期：委托调用搭乘发起它的那个周期。周期从 1 开始编号，因为时间戳 0 是每个地址的初始写入。时钟为 38 位，所以一次执行最多运行 `2^36 − 1` 个周期。

每次内存访问都是一次**查询**：读取一个在某个更早的时间戳上最后写入的值，并在当前时间戳上写入。只读的查询会写回它读到的值。每个周期的槽位 0 是 pc 查询，它读取 `pc` 并写入 `next_pc`。随后是该指令在固定槽位上的寄存器查询和内存查询：

| 类别 | Δ = 1 | Δ = 2 | Δ = 3 |
| --- | --- | --- | --- |
| 寄存器-立即数类、`jalr` | `rs1` | | `rd` |
| 分支 | `rs1` | `rs2` | |
| 寄存器-寄存器类、M 扩展 | `rs1` | `rs2` | `rd` |
| 加载 | `rs1` | 内存字（读取） | `rd` |
| 存储 | `rs1` | `rs2` | 内存字，并入存储的字节 |
| 原子操作 | `rs1` | `rs2` | 内存字，以及 `rd` |
| `ecall` | `a7` | `a0` | `a0`，以及委托的镜像查询 |

地址分属不同的**空间**：32 个寄存器、按 4 字节对齐的字编址的 RAM、pc、每种委托类型各一个锚点空间，以及递归格式的域单元。`x0` 在执行轨迹中是一个普通寄存器，在机器中则是一个常量：对它的每次查询都读写 0。

## 二十三个电路族

**电路族**是一个电路及其所证明的行。电路族分为四类：

| 类别 | 电路族 | 一行是 |
| --- | --- | --- |
| 执行 | 0–6：`ADD_SUB_LUI_AUIPC`、`JUMP_BRANCH_SLT`、`SHIFT_BITWISE`、`MUL_DIV`、`MEM_WORD`、`MEM_SUBWORD`、`ATOMICS` | 一条被执行的指令 |
| 窗口 | 7 `INIT_TEARDOWN`、8 `ZERO_WINDOWS`、12 `PUBLIC_INPUT`、13 `PUBLIC_OUTPUT`、14 `ADVICE_WINDOWS` | 一个内存字，经过初始化与收尾 |
| 委托 | 9 `KECCAK_F`、10 `POSEIDON2`、11 `FR_ARITH`、15 `MOD_MUL`、16 `SHA256_COMP`、17 `EC_ADD` | 作用于一个 RAM 帧的一次调用 |
| 递归 | 18 `FIELD_WINDOWS`、19 `FR_OP`、20 `P2_FIELD`、21 `FIELD_IO`、22 `FQ_OP` | 一个域单元，或一次协处理器运算 |

每个周期都归入这样一个执行电路族：其解码表认领该周期的 pc。各电路族在时间上交错：`ADD_SUB_LUI_AUIPC` 可能拥有周期 1 和 3，`JUMP_BRANCH_SLT` 拥有周期 2。没有任何东西要求它们连续，因为内存论证按 pc 写入为每一行排序。

窗口电路族之所以存在，是因为内存论证要求一次执行触及的每个地址都恰好有一个初始值和一个最终值。`INIT_TEARDOWN` 覆盖 RAM 窗口 0，以程序映像作为其初始内容；`ZERO_WINDOWS` 覆盖这次运行触及的普通 RAM 的其他每个窗口，初始为零；两个公开窗口电路族覆盖输入窗口和公开输出（journal）窗口；`ADVICE_WINDOWS` 覆盖证明者提示（advice）区域，以证明者的字节作为初始内容。

## 分片

一个电路族的行按出现顺序被切分为若干**分片**，每片的行数等于该电路族的高度。最后一个分片用全零行填充，电路在构建时就保证接受这样的行。不论占用率如何，一个分片都按其完整高度计算成本，所以程序触及哪些电路族、选择哪些高度，决定了每份证明的下限。

| 电路族 | 默认高度 | 原因 |
| --- | --- | --- |
| 指令电路族 | `2^22`；`MUL_DIV` 和 `ATOMICS` 为 `2^20` | 其时间戳范围检查的下限是 `2^20` |
| RAM 窗口 | `2^22` | 共用一个窗口高度，至少为 `2^16` |
| 公开输入、公开输出 | `2^12` | 固定不变：高度决定了窗口的位置 |
| `KECCAK_F`、`SHA256_COMP` | `2^18` | 可容纳的调用是其 `2^16` 下限的四倍，证明只大 2% |
| `MOD_MUL`、`EC_ADD` | `2^16` | 其下限 |
| `POSEIDON2`、`FR_ARITH` | `2^8` | 不用表，因此没有下限 |

每个分片都由其电路族的电路独立证明，内存论证除外：每个分片的电路输出其读元组之积与写元组之积，验证者在陈述的所有分片上对这些乘积做一次核对。这是把各分片联系在一起的唯一纽带。不存在逐分片的 pc 衔接，相邻分片之间也没有共享边界。

在默认高度下，分片证明的大小从公开窗口的约 12.5 KB 到 `POSEIDON2` 分片的 665 KB 不等；指令电路族的分片证明为 64 至 77 KB。[性能](https://apogee.gweb3networks.com/docs/architecture/performance)页面给出了完整的表。

规范见[执行轨迹](https://apogee.gweb3networks.com/docs/auditors/spec/execution-trace)、[电路与注册表](https://apogee.gweb3networks.com/docs/auditors/spec/circuits)。
