如何以如此高的像素时钟频率驱动 VGA 显示器?

电器工程 数字逻辑 信号 频率 VGA 传播
2022-02-01 18:41:24

我正在开发一个数字电路,它使用分立元件在 80x30 文本模式下驱动 640x480 VGA 显示器。

对于 640x480 显示器,像素时钟为 25.175MHz,周期约为 40ns。我不明白我应该如何经常为显示器提供新像素。

我的电路的基本架构如下:

  1. 水平像素的二进制计数器在 25.175MHz 处向上计数至 800(640 可见像素 + 160 用于前廊、同步、后廊)。在 800 处,递增垂直行计数器(并在 525 行处重置)

  2. 使用水平和垂直位置,推导出当前字符的 x,y 坐标。

  3. 使用字符的 x,y 坐标,索引到显存以检索 ASCII 字符。

  4. 使用 ASCII 字符在字符 ROM 中进行索引以获取字符的位模式

  5. 使用并行到串行移位寄存器以像素时钟频率将 8 像素行字符转换为单个位

如果你遵循这个链,它会:计数器 -> RAM -> ROM -> 并行到串行移位寄存器

使用我能找到的最快的组件,传播延迟和访问时间加起来约为 15ns + 20ns + 70ns + 15ns = 120ns,远大于 25MHz 的 40ns 周期。

在更高的分辨率和刷新率下,您可以拥有远高于 100MHz 的像素时钟,这将是一个 10ns 的周期。

如果 RAM/ROM 的访问时间已经远远超过它,甚至不考虑系统中的所有其他信号,怎么可能每 10ns 向显示器提供新像素?

4个回答

您发现这具有挑战性的主要原因有两个。

首先,您使用的是比 VGA 时代更旧且更离散(集成度更低)的部件。

但接下来,你以一种非典型的方式使用它们。具体来说,您的方法并不pipelined意味着您在确定间隔时必须累加多个延迟,从而确定速率。

相比之下,试图实现速度的同步数字设计试图在寄存器之间做尽可能少的事情。

虽然细节可能会有所不同,但粗略地说,它会像这样工作:

  • 您增加或重置地址,然后将其放入寄存器。
  • 您将地址锁存到同步内存中
  • 你锁存同步存储器的输出
  • 您将其锁存到同步字符生成器的地址中
  • 您将字符生成器的输出锁存到输出寄存器中
  • 应用调色板查找...
  • 进入同步DAC...

当您像这样分解任务时,您只会得到一个组合延迟加上一些传播延迟以及需要适应时钟之间的寄存器设置和保持时间。

以这种方式构建的设计将需要许多时钟来产生输出 -延迟实际上会高于纯粹的组合设计。但它会在更快的时钟的每个周期产生一个新的正确输出。

嘿,这是视频,CRT 是否在像素计数器后面绘制十几个像素并不重要 - 你当然会在同步信号的时序中考虑到这一点,以便与数据实际时相比它们是正确的来自DAC。

在实践中,几乎所有复杂的数字系统都以这种方式工作,因为这是一个好主意——直到流水线 CPU 依赖于早期的计算结果或条件分支......然后事情变得有趣,正如他们所说在数字系统课的下一节课中 - 但幸运的是,您的 VGA 情况要简单得多,特别是如果您还不担心在绘制屏幕时字符缓冲区发生变化时的撕裂效果。

实际上,如果您想构建它,请在 FPGA 中进行。如果您使用内部存储器,那将在很大程度上强制您使用同步存储器,或者如果您使用外部存储器,则使用同步 IO 寄存器。你会得到很多正确的设计,织物本身会比你的离散部件更快,当然,如果你犯了一个错误,你只需要在重新编译时转动你的拇指,而不是花一整天的时间重新布线.

除了流水线(这是你应该做的)之外,你还缺少一些重要的东西......

并行输入、串行输出移位寄存器的时钟频率为 25 奇数 Mhz,当然,但如果你的字符是 8 像素宽,那么它的输入只有 ~3.2MHz,这对于 VGA 时代的 LS 系列来说很容易达到,尽管如此当移位寄存器完成当前字节时,您需要准备好下一个字节(这是管道进入的地方)。

生成约 25MHz 的像素时钟和 1/8 的内存时钟来驱动文本缓冲区和 CG ROM,然后流水线化该内存和 CG ROM 访问内容。

还有一个技巧,文本缓冲区输出将在任何给定文本行中的每一行重复,所以也许你可以将 80 字节的文本输入一个环形缓冲区,然后停止读取接下来 7 行的 ram(假设 8行字符),这可以让你释放内存供 CPU 使用,代价是需要 80 字节的内存挂在东西的侧面。

使用我能找到的最快的组件,传播延迟和访问时间加起来约为 15ns + 20ns + 70ns + 15ns = 120ns,远大于 25MHz 的 40ns 周期。

您忘记了图形适配器永远不会只绘制一个像素 - 但至少会绘制一条完整的扫描线。因此,这将是一个完全可流水线的问题。

另外,不要忘记,到目前为止,视频制作硬件已经有五年的历史了。您的问题通常可以使用一种特殊类型的 RAM 来解决,您可以在其中一个端口上渲染您的字母,然后依次读出到视频信号 DAC。该硬件比您所看到的要快得多。

我的电路的基本架构如下:

  1. 水平像素的二进制计数器在 25.175MHz 处向上计数至 800(640 可见像素 + 160 用于前廊、同步、后廊)。在 800 处,递增垂直行计数器(并在 525 行处重置)

  2. 使用水平和垂直位置,推导出当前字符的 x,y 坐标。

不,你为什么要这样做?您只需将行像素放入内存的连续区域,然后将其线性输出到您的 DAC - 如果这是关于 CPU / MCU 实现,您甚至不会让您的 CPU 这样做,而是一个 DMA 单元,已编程什么也不做,只取一个接一个的值并将其输出到例如并行数据端口,而无需任何 CPU 内核交互。

  1. 使用字符的 x,y 坐标,索引到显存以检索 ASCII 字符。

啊,你想即时渲染——不错的选择,但在现代 RAM 成本下是不寻常的。相反,您只需事先将字符渲染到帧缓冲区中,或者如果您的设备非常纤薄,则直接将字符行输出(参见我上面的 DMA 说明)到 DAC。

很明显,那是行不通的;你需要一个管道。

1)将字符连续存储在内存中。从左上角开始。

2) 在消隐期间取一个字符。继续按内存顺序获取字符。

3) 将每个解码的字符加上行索引流水线化到 ROM 中。

4) 将 ROM 输出流水线化到缓冲区中。

5) 将缓冲区流水线化到移位寄存器中。从此以 40ns 的间隔连续读出像素。

(这意味着您需要每 320ns 将一个新字符加载到移位寄存器中,这甚至可能在不流水线化整个系统其余部分的情况下也是可行的。)

6) 在水平消隐期间,要么返回行首,要么前进到下一个字符(即下一行的开头)。

额外功能:由于您每 320ns 只需要一个字符,因此您还可以读取字符+颜色对并执行 MSDOS 样式或 Spectrum 样式的颜色字符。