Hotdry.
systems

复古矢量图形发生器硬件架构与信号时序深度解析

深入分析 Atari 矢量图形发生器的工作原理、硬件架构与信号时序,为复古硬件修复提供工程参数与调试指南。

在 1970 年代末至 1980 年代初的街机游戏时代,矢量图形(Vector Graphics)以其极高的分辨率和清晰度成为技术标杆。从《Lunar Lander》到《BattleZone》,从《Asteroids》到《Star Wars》,这些经典游戏背后的核心技术正是矢量图形发生器(Vector Generator)。理解其硬件架构与信号时序,不仅是对游戏历史的致敬,更是复古硬件修复与 FPGA 实现的必备知识。

矢量图形的基本原理

与传统光栅显示器逐行扫描不同,矢量显示器直接控制电子束在屏幕上的位置。电子束从起点移动到终点,绘制出一条直线,然后熄灭,移动到下一个起点。这种工作方式带来了一个显著优势:分辨率不再受限于像素网格 —— 理论上可以达到任意精度,只要硬件(偏转放大器)能够跟得上。

在 Atari 的实现中,矢量发生器需要解决三个核心问题:如何精确控制电子束位置、如何在不同长度的矢量间保持一致的亮度、以及如何在没有帧缓冲区的情况下高效绘制大量矢量。这些问题直接催生了两种不同的矢量发生器架构:数字矢量发生器(Digital Vector Generator,DVG)和模拟矢量发生器(Analog Vector Generator,AVG)。

数字矢量发生器的核心架构

数字矢量发生器的核心思想是将矢量绘制转化为一个计数问题。系统使用一个计数器连接到数模转换器(DAC),通过递增或递减计数器来移动电子束。具体实现中,计数器工作在双向模式,接收来自二进制速率乘法器(Binary Rate Multiplier,BRM)的时钟脉冲。

BRM 是整个系统的关键组件。Atari 采用的是 TI 公司的 7497 芯片,这是一款 6 位二进制速率乘法器。当输入为 63 时,每个输入时钟周期产生 63 个输出脉冲;当输入为 1 时,每 64 个输入时钟产生 1 个输出脉冲。这种非线性特性使得系统可以通过调整 BRM 的输入值来精确控制矢量绘制速度。两片 7497 级联形成 12 位 BRM,提供足够的精度控制。

由于 X 轴和 Y 轴的矢量长度通常不同,系统需要为两个轴提供独立的时钟源。如果使用相同的时钟源绘制一条 40 单位长 X 轴和 30 单位长 Y 轴的矢量,结果将是一个阶梯状而非直线。解决方案是让较长的轴全速绘制,较短的轴按比例减速。具体而言,如果 X 轴需要 40 微秒,Y 轴需要在同样的 40 微秒内完成 30 单位,则 Y 轴的时钟频率应为 X 轴的 30/40。

数模转换与去抖动

DAC 本身存在一个固有问题:输入值改变时,内部电阻网络的切换会产生尖峰噪声。如果直接将这些噪声送到偏转放大器,电子束会显示不必要的抖动。解决方案是使用采样保持电路(Sample-and-Hold):在 DAC 输出稳定时闭合开关对电容充电,然后断开开关允许 DAC 改变输入,保持电容上的电压驱动输出。缓冲放大器具有高输入阻抗,使电容在采样保持周期内不会显著放电。

Atari 的数字矢量发生器使用 10 位 DAC,提供 1024 步的分辨率。坐标系统采用二进制补码形式:最高位为符号位,$200(512)代表零点,正数向右 / 向上,负数向左 / 向下。由于正负范围不对称(-512 到 +511),编程时需要考虑这一细节。

二进制归一化

为了在不同长度矢量间保持一致的磷光亮度,矢量应按比例绘制:如果一条矢量是另一条的两倍长,绘制时间也应翻倍。理论上这需要计算平方根和多次除法,在运行时执行这些数学运算对 6502 处理器来说过于昂贵。

Atari 的解决方案是二进制归一化(Binary Normalization):在程序集阶段预先处理矢量数据。X 和 Y 值加载到移位寄存器,时间寄存器加载预设值;每次 X 和 Y 移位左翻倍(乘以 2),时间寄存器右移减半;重复直到任一轴即将溢出。最终 X、Y 和时间保持正确的比例关系,矢量以接近最快的安全速度绘制。由于时间寄存器的初始状态每次只有一位被置位,可以用 4 位数字表示,允许额外的 4 位加法器进行短矢量的二进制缩放。

矢量发生器状态机

将数据高速馈送 DAC 并保持系统运行是一项艰巨任务 ——6502 即使不运行游戏也远远不够快。Atari 的解决方案是构建一个由 SSI 和 MSI 电路组成的专用协处理器,其核心是一个状态机。

状态机由 PROM 和锁存器组成。PROM 编程为每个地址的数据选择下一个地址,锁存器允许 PROM 输出稳定后再反馈到输入,提供基本的时序。清除锁存器使机器进入状态 0,该状态的数据决定下一状态。通过解码状态可以提供最多八种功能。

状态机执行一条指令需要多个微状态。以最基础的 Load X,Y 指令为例:状态 0 将数据锁存到指令锁存器并递增程序计数器;状态 1 将数据锁存到 X 锁存器;状态 2 将数据锁存到 Y 锁存器;状态 3 触发采样保持并决定是否结束指令。完整的指令集包括:Load X,Y(3 字节,4 个机器周期)、JMP addr(2 字节)、JSR addr(2 字节)、RTS(1 字节)、NOP(1 字节)、HALT(1 字节)和 TIMER(2 字节,带计时数据)。

Asteroids 的矢量发生器状态机除了状态机外还包含相当数量的随机逻辑,这是因为需要支持更多功能。

模拟矢量发生器的演进

模拟矢量发生器解决了数字版本的一个根本问题:阶梯效应。在数字版本中,每个 XY 位置来自计数器输出,结果类似于帧缓冲区 —— 当矢量以离散步长移动时会出现阶梯。模拟版本通过模拟积分器产生连续变化的电压,消除阶梯。

模拟矢量发生器的核心是积分器电路。根据电容的电流 - 电压关系 I = C × dV/dt,对电容施加恒定电流产生线性斜坡。实际实现中使用运算放大器构建的电流源,确保电容电流恒定而与电压无关。

模拟矢量发生器与数字版本有几个关键差异:数字版本产生由离散坐标点组成的矢量,模拟版本在点之间连续变化;数字版本可通过加载计数器直接设置位置,模拟版本只能将电子束居中并绘制空白矢量到目标位置;数字版本需要 BRM 提供不同频率时钟,模拟版本自动产生正确比例的模拟斜坡。

运行时归一化

模拟矢量发生器首次用于 BattleZone,该游戏的 3D 物体矢量是运行时计算的结果,无法在程序集阶段进行归一化。因此模拟版本增加了在运行时执行二进制归一化的电路。

窗口电路

BattleZone 引入了窗口电路,允许程序员定义屏幕上的矩形区域。落在窗口外的矢量被消隐。这用于将游戏矢量排除在雷达显示之外 —— 程序员先绘制矢量到窗口右下角并发出 HST 命令采样保持,然后绘制到左上角并发出 LST 命令,两组比较器持续监控当前位置是否在窗口内。

线性缩放

模拟矢量发生器支持一种数字版本无法实现的功能:通过改变 DAC 参考电压 VREF 来线性缩放物体。改变 VREF 从缩放点开始缩放后续矢量,不影响起始位置。结合二进制缩放和线性缩放,可以在不改变绘制时间的情况下大范围调整物体大小。

时序与调试参数

对于复古硬件修复和 FPGA 实现,以下是关键的时序参数和信号:

主时钟与分配

Atari 矢量发生器通常使用 12 MHz 主时钟,经分频后为矢量逻辑提供 6 MHz 时钟。检查矢量发生器时,首先验证主时钟及其分频:错误的分频(如二分频错误)会等比缩放所有矢量。示波器测量时应能在测试点观察到稳定的 6 MHz 或 12 MHz 方波。

BRM 输入与输出

两片 7497 级联形成 12 位 BRM,正确的 12 位速率数据对长度缩放至关重要,尤其是长矢量。示波器监测 BRM 输出应看到与设定值成比例的脉冲序列。如果矢量长度缩放异常,特别是长矢量,应检查 7497 芯片和速率数据总线。

控制信号时序

核心控制信号包括:VG GO 启动矢量列表执行;VG HALT 指示状态机已完成列表;VG CENTER 是将电子束居中的微操作。每个信号都有特定的时序要求 —— 可以用逻辑分析仪验证这些控制信号相对于 VG GO 和相互之间的时序关系。

故障症状与定位

常见的矢量显示故障症状有:矢量过短或过长,通常是定时链中某个计数器或锁存器(如 LS161、LS193、LS175)故障;某些长度组合下矢量行为异常,表现为负轴线错误或命令 "瞬间" 执行(没有可见线条);所有矢量都是小点或显示异常,可能是定时链问题导致有效绘制时间为零。

现代实现的可能性

将整个状态机矢量发生器放入 FPGA 现已可行,现代 FPGA 的规模足以包含状态机和矢量存储器。模拟后端可以用现代高速 DAC 和模拟开关实现:现代 30 MHz DAC 取代了原来的 4 MHz AD561,采样保持电路也能满足速度要求。

另一个方向是用 DSP 取代状态机。TMS32010 及其后继者具有足够的计算能力执行实时归一化和矢量生成,现代 DSP 如 ADSP-2186 甚至可以完全在片上完成。

资料来源

本文技术细节主要参考 Jed Margolin 的权威文章《The Secret Life of Vector Generators》。Jed Margolin 曾在 Atari 工作,是 BattleZone 等矢量游戏硬件团队的成员,该文章详细记录了从 Lunar Lander 到 TomCat 的整个矢量发生器发展历程,包含原始电路图和 IC 数据手册。

查看归档