# 脚本交互与代码展示：8 位微处理器动态演示

> 基于网站的 JS 脚本组件支持，构建 8 位 CPU 状态机可视化演示，并测试代码高亮、复制与悬停黑块功能

- HTML: /nodes/computer-showcase/
- Markdown: /nodes/computer-showcase.md
- Section: Nodes / 实践
- Published: 2026.11.09
- Column: Maplen
- Tags: 计算机, 交互

---

export const cpuCycle = `
stateDiagram-v2
  [*] --> 取指_Fetch: PC 地址送上地址总线 (SRAM 选通)
  取指_Fetch --> 译码_Decode: 机器码送入 IR 指令寄存器, PC++
  译码_Decode --> 执行_Execute: 控制单元解析操作码, 激活 ALU 运算
  执行_Execute --> 写回_Writeback: 运算结果锁存进 ACC 或写回 SRAM
  写回_Writeback --> 取指_Fetch: 启动下一时钟周期
  写回_Writeback --> 停机_HALT: 遇到 HLT 指令, 时钟停振
  停机_HALT --> [*]
`;

在写一些涉及底层软硬件或算法的技术文章时，纯文字与静态截图往往很难把「状态如何转移、数据如何流动」讲得直观透彻。

得益于 [Maplen](/wiki/maplen.md) 支持在 [MDX (.mdx)](/wiki/mdx.md) 中直接编写自定义的 JS/React 脚本，我可以很轻便地在文章里嵌入一些可视化的小组件。

这篇手记没有复杂的理论说教，主要用来测试和展示网站的两项实用功能：
1. **基于 JS 脚本的可视化动态演示**（以一个简化的 8 位微处理器时钟周期小工具为例）；
2. **代码块排版与小交互**（语法高亮、精准行标记、版本 Diff、一键复制代码，以及悬停黑块遮蔽）。

---

## 一、可视化组件演示：简易 8 位微处理器时钟周期

为了演示文章内嵌脚本的能力，我写了一个轻量级的 8 位微处理器模拟组件。

### 1. 指令周期的四个节拍
在传统教学中，CPU 的「取指—译码—执行—写回」通常只是一张静态示意图。这里我先用 [Mermaid](/wiki/mermaid.md) 简单画出它的状态转移：



### 2. 交互式仿真演示
利用网站对 React 组件的支持，我把这个过程做成了一个可交互的可视化画布：
- **横平竖直的总线**：顶部为 16 位地址总线，底部为 8 位数据总线；
- **基础部件**：PC（程序计数器）、IR（指令寄存器）、ACC（累加器）、ALU（运算单元）与 8 字节的小内存；
- **交互操作**：
  - 点击「单步执行」：每点一下走一个时钟节拍，观察总线高亮与寄存器数值变化；
  - 点击「自动运行」：让时钟连续跳动，自动完成计算；
  - **鼠标悬停暂停（Hover to Pause）**：在连续运行时，把鼠标移到画布上方就会自动暂停，方便看清当前寄存器的值，移开后继续运行；
  - 切换「程序 1」与「程序 2」：载入简单的加法（3 + 5）或减法（9 - 4）测试指令。



这种小组件并不需要引入庞大的前端工程，随手写个几十行脚本，就能让文章的解释力提升不少。

---

## 二、代码块排版与辅助功能测试

代码是技术写作里的常客。Maplen 借助服务端的 [Shiki](/wiki/shiki.md) 插件，支持了一些日常写作很方便的功能：

### 1. 标题栏、重点行高亮与 Diff 增删标记
平时贴代码时，我经常需要指出某几行是修改重点，或者对比版本前后的改动。

比如下面这段模拟 ALU 运算的 TypeScript 示例：
- **文件标题**：右上角或顶栏展示代码文件名；
- **精准行高亮**：聚焦在核心的加法逻辑行；
- **Diff 标记**：用绿色 `// [!code ++]` 和红色 `// [!code --]` 标出重构逻辑；
- **复制代码**：鼠标悬停在代码块上，点击「复制代码」按钮即可复制纯文本。

```typescript title="src/sim/alu_core.ts" {9-12}
export interface CpuState {
  pc: number;          // 程序计数器
  acc: number;         // 累加器
  ir: number;          // 指令寄存器
  ram: Uint8Array;     // 8 字节 SRAM
}

export function executeAlu(state: CpuState, opcode: number, operand: number): CpuState {
  // 核心运算单元：执行算术逻辑指令
  switch (opcode) {
    case 0x01: // ADD 指令：累加器相加并截断为 8 位
      return { ...state, acc: (state.acc + operand) & 0xff };
    // [!code --]
    case 0x02: // 旧版本逻辑：未处理下溢
      return { ...state, acc: state.acc - operand };
    // [!code ++]
    case 0x02: // 优化重构：严谨模拟 8 位补码环绕
      return { ...state, acc: (state.acc - operand + 256) & 0xff };
    default:
      return state;
  }
}
```

### 2. 汇编代码与单行高亮
如果是汇编或底层指令清单，也可以指定着色语言，并配合 `// [!code highlight]` 对指定指令做醒目标记：

```asm title="src/firmware/boot_kernel.asm"
_start:
    MOV AL, [0x05]    ; 步骤 1：从内存地址 0x05 载入参数 A // [!code highlight]
    ADD AL, [0x06]    ; 步骤 2：累加器相加 // [!code highlight]
    MOV [0x07], AL    ; 步骤 3：将计算结果写回目标地址 // [!code highlight]
    HLT               ; 步骤 4：停机指令
```

---

## 三、悬停黑块遮蔽文本（Spoiler / 悬停显示）

有时候在文章里写题目答案、解密思路，或者影视随笔里的剧透内容，直接平铺出来容易影响读者自己的思考。

我在网站里实现了一个简单的小功能：用 `<span className="spoiler">` 把文字遮起来，鼠标放上去或者手机上轻点一下才会显示：

> **小思考题**：在运行程序 1 时，当程序执行到 `STORE [7]` 把结果写回内存时，累加器里的值是多少？  
> 答案：<span className="spoiler">十进制 8（十六进制 0x08）</span>。  
> *(把鼠标移到黑色块上即可查看答案)*

---

## 四、小结

文章的本质依然是把事情讲清楚。有了这些基础的小排版、代码高亮和按需插入的小脚本组件，以后在写类似硬件设计、算法演示或系统笔记时，就能更自如地做一些直观的表达了。
