Full picture
9

只读存储器 (ROM)

9.1 概览

正如我们之前所见,在 CPU 启动或复位后,它将从第一个虚拟地址 0x0000 开始执行代码,此时该地址也等于物理地址 0x000000

因此,此地址必须存在一些 CPU 可以理解并执行的有效二进制代码,所以我们需要一个设备来存储这些数据。这就是只读存储器(ROM)的作用:它将存储 CPU 将要执行的代码。

9.2 硬件实现

尽管名为只读存储器(ROM),但它不一定是不可擦除的。存在多种可以擦除和重写的 ROM 类型:EPROM、EEPROM、NOR Flash、NAND Flash 等。

在 Zeal 8 位计算机上,充当 ROM 的组件是 SST39SF020 NOR Flash,容量为 256KB,组织为 256K 字 × 8 位,在 PCB 上标记为 U4。它采用带插座的 PLCC32 封装,使其紧凑且仍然可以轻松移除和重新插入,无需焊接或拆焊。

这款 SST39SF020 NOR Flash 的主要优点有:

  • 可在电路内编程,无需取出并使用专用编程器进行擦除或重写,可以直接从 Z80 完成!
  • 不需要任何特殊的硬件协议来擦除或编程,从 CPU 的角度看,它仍然像一个常规的(EEP)ROM。
  • 对于 8 位计算机来说容量大:最高可达 512KB。
  • 引脚与传统的 27C020 ROM 兼容。
  • 可用性强,由于仍在大批量生产,很容易找到。

在引脚排列方面,其组织方式如下:

ROM 引脚排列
ROM 的引脚排列

让我们看看连接到它的常规信号:

  • $ADDR\ 0$ 到 $ADDR\ 17$:表示要读取的字节的地址。ROM 为 256KB,因此最后一个字节地址为 0x3ffff
  • $DATA\ 0$ 到 $DATA\ 7$:表示刚从 ROM 读取的字节。
  • $\overline{RD}$:来自 CPU 的信号,当 CPU 正在执行读取时有效。
  • $\overline{WR}$:来自 CPU 的信号,当 CPU 正在执行写入时有效。更多信息请参见编程 ROM 部分。
  • $\overline{CE}$:来自逻辑胶合的信号,当 CPU 尝试访问 ROM 映射的地址范围时有效,该范围是物理地址空间的前 512KB。更多信息请参见逻辑胶合章节

两个带有星号标记的信号具有特殊功能或状态,以下各节将解释这些细节。

9.3 硬件依赖与时序

在时序方面,ROM 依赖于 MMU,因为它需要 18 或 19 条地址线(取决于 ROM 的大小),同时也依赖于逻辑胶合。实际上,后者输出的 $\overline{ROM\_ENABLE}$ 连接到 ROM 的 $\overline{CE}$ 信号。两者都应考虑在内,以确定从 CPU 执行读取到 ROM 输出数据之间的总传播延迟。

根据数据手册,SST39SF020A-70 本身在最坏情况下标称传播延迟为 70ns。

关于延迟和时序的所有详细信息在官方数据手册中有详细说明。

9.4 安装更大的 NOR Flash

ROM 的第一个引脚 $NC / ADDR\ 18$ 有两种可能的状态:如果在插座 U4 中安装了 256KB ROM(默认情况),此引脚必须保持不连接

但是,如果安装的是 512KB ROM(例如 SST39SF040),则必须将此引脚连接到来自 MMU 的 $ADDR\ 18$。为此,只需在 PCB 上标记为 JP1 的焊桥上连接一个跳线即可。

通过连接此跳线,MMU 的 $ADDR\ 18$ 将连接到该引脚,使 Z80 CPU 能够访问整个 512KB ROM。

这个跳线 JP1 解释了为什么我们需要在逻辑胶合中为 ROM 分配 512KB 的连续内存。如果只分配了 256KB(从 0x000000x3ffff),用 512KB ROM 替换将更加困难,因为需要额外的逻辑来映射 ROM 的第二个 256KB 部分。

其原理图如下所示:

ROM 跳线
512KB ROM 的跳线

9.5 禁用 ROM

如逻辑胶合章节所述,无论安装的 ROM 是 256KB 还是 512KB,当 CPU 尝试读取(或写入)任何物理地址在 0x000000x3ffff 之间时,ROM 的 $\overline{CE}$ 信号都将有效。

这样做的结果之一是,ROM 始终是 CPU 获取指令的第一个位置。然而,在某些情况下,拥有一个外部可引导卡带会很有用,它可以完全绕过 Zeal 8 位计算机的内部 ROM,只让 CPU 从该新外部板中嵌入的 ROM 读取和执行数据。

一种解决方案是暂时移除内部 ROM,然后插入扩展板,这样 ROM 之间就不会发生冲突。另一种不需要修改主板的解决方案是将 $\overline{CE}$ 线拉高,使其失效。

为此,$\overline{CE}$ 信号通过一个 1kΩ 电阻(标记为 R5)连接到逻辑胶合的 $\overline{ROM\_ENABLE}$ 信号,并且也连接到扩展端口(标记为 J2)的第 49 引脚,不经过任何电阻。

因此,每当外部扩展板需要禁用内部 ROM 时,此 ROM_DISABLE 引脚必须设置为高电平(5V)。请查看扩展端口部分以了解其确切位置。

9.6 编程 ROM

NOR Flash 与 EPROM 和 EEPROM 一样,可以通过一些通用编程器进行编程。

然而,如前所述,NOR Flash 相较于前面提到的 ROM 的主要优点是它可以在电路内编程,无需从插座中取出,因此不需要这样的通用编程器。

擦除和编程 NOR Flash 的整个过程在官方数据手册中有详细说明。

编程原理

简而言之,NOR Flash 通过软件命令实现这一点,这些命令由在预定义地址上连续写入预定义值组成,如下表所示(取自上述文档):

NOR Flash 命令
NOR Flash 命令

值得注意的是,这些地址是相对于 NOR Flash 的地址,但由于 NOR Flash 在 Zeal 8 位计算机上映射到物理地址 0x00000,我们可以将它们视为物理地址,而不是虚拟地址!

换句话说,要执行这些命令中的任何一个,必须将 ROM 的至少两个 16KB 页面映射到 64KB 虚拟地址空间中。这两个页面分别是包含地址 0x2AAA(页面 0)和 0x5555(页面 1)处字节的页面。它们不一定需要同时被映射。

另一个重要注意事项是,在尝试编程一个字节之前,必须先执行擦除操作。因此,即使只需要(重新)编程某个扇区中的一个字节,也必须先擦除整个扇区!

实际示例

如前表所述,擦除芯片的步骤为:

  1. 0xAA 写入 ROM 地址 0x5555
  2. 0x55 写入 ROM 地址 0x2AAA
  3. 0x80 写入 ROM 地址 0x5555
  4. 0xAA 写入 ROM 地址 0x5555
  5. 0x55 写入 ROM 地址 0x2AAA
  6. 0x10 写入 ROM 地址 0x5555

然后 NOR Flash 将开始擦除自身,这最多需要 100ms。这意味着擦除 Flash 的程序不能位于 Flash 本身中,否则它会被擦除,它应该从其他地方(如 RAM)执行。

以下是一个实际的 Z80 汇编示例,展示如何通过软件命令擦除芯片:

    ; 以下代码从 RAM 中运行,位于虚拟地址 0x8000
    ; 前两个 16KB 虚拟页面是空闲的,我们可以用它们来映射 ROM 的前几个页面
erase_chip:
    ; 将 A 初始化为 0
    xor a
    ; 将虚拟页面 0 映射到物理地址 0x0000 - 0x3FFF
    out (0xF0), a
    inc a
    ; 将虚拟页面 1 映射到物理地址 0x4000 - 0x7FFF
    out (0xF1), a

    ; 我们现在可以访问 NOR Flash 地址 0x2AAA 和 0x5555,开始擦除过程
    ld hl, 0x5555
    ld a, 0x55
    ; 1. 将 `0xAA` 写入 ROM 地址 `0x5555`
    ld (hl), 0xAA
    ; 2. 将 `0x55` 写入 ROM 地址 `0x2AAA`
    ld (0x2AAA), a
    ; 3. 将 `0x80` 写入 ROM 地址 `0x5555`
    ld (hl), 0x80
    ; 4. 将 `0xAA` 写入 ROM 地址 `0x5555`
    ld (hl), 0xAA
    ; 5. 将 `0x55` 写入 ROM 地址 `0x2AAA`
    ld (0x2AAA), a
    ; 6. 将 `0x10` 写入 ROM 地址 `0x5555`
    ld (hl), 0x10

    ; 等待至少 100ms 以完成擦除 = 在 10MHz 下为 1,000,000 个 T 状态
    ; 下面是 24 个 T 状态
    ld bc, 1000000 / 24
wait:
    ; 以下循环(直到 'jp nz, wait')共 24 个 T 状态
    dec bc
    ld a, b
    or c
    jp nz, wait

    ; 100ms 已过,芯片已擦除。
EN | 中文Beta