Full picture
11

视频配置

11.1 概述

Zeal Video Board 提供了一些寄存器,用于获取当前状态或配置视频输出。这些寄存器包括设置当前视频模式、滚动、扫描束位置甚至当前中断状态。

该配置区域在 I/O 总线上的基地址为 0x90,它永远不会被映射出去,因此随时可用。

11.2 虚拟扫描束

渲染

Zeal Video Board 实现了 VGA 协议以生成视频信号。该信号可以想象为一条虚拟扫描束,从屏幕左上角扫描到右下角。渲染分辨率固定为 640×480 像素,与当前模式无关,像素时钟频率为 25 MHz。

尽管可见区域为 640×480,但虚拟扫描束实际上会遍历更大的区域。每条水平线包含一个额外的 160 像素宽的不可见区域,称为水平消隐(或 H-blank)。

同样,在渲染完 480 条可见线之后,扫描束会继续通过 42 条额外的不可见线,称为垂直消隐(或 V-blank)。

因此,虚拟扫描束的坐标范围在水平方向为 0 到 799,垂直方向为 0 到 524,包括可见区域和消隐区域。

VGA 屏幕
VGA 完整渲染区域

根据这些信息,可以计算出扫描束在这些消隐间隔中停留的时间。

水平消隐期由 160 个像素组成,在 25 MHz 的像素时钟下(即每个像素需要 40 ns),其持续时间为:

\( t = 160 \text{ px} \times 40\,\text{ns} = 6400\,\text{ns} = 6.4\,\mu\text{s} \)

垂直消隐期由 42 条线组成,每条线包含 800 个像素(640 可见 + 160 消隐)。因此:

\( t = 42 \text{ lines} \times 800 \text{ px} \times 40\,\text{ns} = 1344000\text{ns} = 1.344\,\text{ms} \)

理论上,标准 640×480 VGA 分辨率需要以 25.125MHz 的像素时钟生成 525 条线,但 Zeal Video Board 的主时钟为 50MHz,因此使用 25MHz 的像素时钟。为补偿这一差异,仅生成 524 条线。

320×240 模式

320×240 模式是纯虚拟的,其行为类似于一个 2 倍放大到左上象限的 640×480 显示。换句话说,320×240 空间中的每个像素在屏幕上渲染为一个 2×2 的像素块。

VGA 信号保持不变,仍然输出 640×480 的图像。扫描束位置值不受影响,仅修改渲染逻辑以在水平和垂直方向上对每个像素进行加倍。

获取位置

虚拟扫描束位置由两个 16 位值表示,一个用于垂直位置,一个用于水平位置。因此,提供了四个寄存器来读取这些值:V_CURSOR_LOWV_CURSOR_HIGH 用于垂直位置,H_CURSOR_LOWH_CURSOR_HIGH 用于水平位置。有关地址,请参阅寄存器汇总部分。

与 ZVB 上的其他 16 位值一样,必须先读取低字节才能锁存高字节寄存器中的高位字节。

另一种快速检查当前是否处于 H-blank 或 V-blank 间隔的方法是读取 VIDEO_STATUS 寄存器,该寄存器专门提供了两个位用于此目的。借助该寄存器,与 ZVB 连接的 CPU 无需读取 16 位值并手动进行比较。

11.3 屏幕滚动

瓦片地图章节所述,ZVB 具有两个瓦片地图层: layer0layer1。每层在内存中存储 80×40 个瓦片。在固定的 16×16 像素瓦片大小下,每层的虚拟屏幕分辨率为 1280×640 像素

然而,如上所述,实际视频输出分辨率固定为 640×480 像素。这意味着在任何给定时间,只有部分瓦片地图在屏幕上可见。

这就是滚动的作用。滚动允许您在 X 和 Y 方向上移动瓦片地图的可见部分,从而有效控制在 640×480 视口内显示的内容。在其他模式下,滚动也可能定义渲染开始的起始位置。滚动使用模运算,因此超出瓦片地图范围的值会自动回绕,产生连续滚动效果。

Layer0layer1 可以独立滚动,精度为像素级。例如,可以通过让 layer0(背景)比 layer1(前景)滚动更快来实现深度或视差效果:

滚动示意图
8 位 640×480 模式下的滚动示例

同样,320×240 模式是纯虚拟的,因此原理相同,唯一的区别是屏幕视图更小。滚动值不受影响,X 和 Y 的范围仍然分别为 $[0,1279]$ 和 $[0,799]$。

图形模式下,提供了八个寄存器用于获取或设置当前 X 和 Y 方向的滚动值:

同样,读取最低字节时寄存器会被锁存,写入最高字节时写入的值才会生效。

文本模式下,上述寄存器将被忽略且不会影响输出,因为滚动由文本控制器的 SCROLL_XSCROLL_Y 寄存器负责。

Layer1 的滚动值在 4 位图形模式下将被忽略,因为该层用于 layer0 的瓦片属性。这些滚动寄存器仅在瓦片图形模式下影响视频输出。在其他任何视频模式下,硬件将忽略它们。

11.4 禁用屏幕输出

在某些情况下,禁用屏幕输出以防止视觉伪影非常有用,例如在加载新字形集或更新瓦片地图时。这些操作可能会暂时损坏屏幕图像,尤其是当它们耗时超过一帧时。

为此,VIDEO_STATUS 寄存器包含一个可读写的 ENABLE 位。当该位被清除时,屏幕输出被禁用,当前帧及后续帧将渲染黑色像素。当该位再次被设置时,正常视频输出将使用视频存储器的当前内容恢复。

为避免可见的闪烁,建议尽可能在垂直消隐期(V-blank)期间禁用屏幕输出。

11.5 寄存器总览

Name Description Base-relative address Access
V_CURSOR_LOW 垂直光标最低字节(先读取此寄存器以锁存完整的11位值) 0x00 RO
V_CURSOR_HIGH 垂直光标最高字节(在V_CURSOR_LOW之后读取以获取完整的11位值) 0x01 RO
H_CURSOR_LOW 水平光标最低字节(先读取此寄存器以锁存完整的11位值) 0x02 RO
H_CURSOR_HIGH 水平光标最高字节(在H_CURSOR_LOW之后读取以获取完整的11位值) 0x03 RO
LAYER0_SCROLL_Y_LOW 图层0垂直滚动的低8位。必须在写入HIGH寄存器之前写入以锁存完整值。 0x04 WO
LAYER0_SCROLL_Y_HIGH 图层0垂直滚动的高位。写入此寄存器使用先前锁存的LSB完成原子更新。 0x05 WO
LAYER0_SCROLL_X_LOW 图层0水平滚动的低8位。必须在写入HIGH寄存器之前写入以锁存完整值。 0x06 WO
LAYER0_SCROLL_X_HIGH 图层0水平滚动的高位。写入此寄存器使用先前锁存的LSB完成原子更新。 0x07 WO
LAYER1_SCROLL_Y_LOW 图层1垂直滚动的低8位。必须在写入HIGH寄存器之前写入以锁存完整值。 0x08 WO
LAYER1_SCROLL_Y_HIGH 图层1垂直滚动的高位。写入此寄存器使用先前锁存的LSB完成原子更新。 0x09 WO
LAYER1_SCROLL_X_LOW 图层1水平滚动的低8位。必须在写入HIGH寄存器之前写入以锁存完整值。 0x0A WO
LAYER1_SCROLL_X_HIGH 图层1水平滚动的高位。写入此寄存器使用先前锁存的LSB完成原子更新。 0x0B WO
VIDEO_MODE 选择当前视频模式 0x0C RW
VIDEO_STATUS 当前视频系统状态 0x0D varies
VIDEO_INT_STATUS 中断状态位 0x0E RO
VIDEO_INT_CLEAR 清除视频中断标志 0x0F WO

11.6 寄存器

V_CURSOR_LOW (0x00)
垂直光标最低字节(先读取此寄存器以锁存完整的11位值)
V_CURSOR_LSB
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
V_CURSOR_LSB
垂直光标位置的低8位。读取此寄存器将高位锁存到内部影子寄存器中,以实现原子性的垂直光标读取。 (RO)
V_CURSOR_HIGH (0x01)
垂直光标最高字节(在V_CURSOR_LOW之后读取以获取完整的11位值)
(reserved)
V_CURSOR[10:8]
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
V_CURSOR[10:8]
锁存的垂直光标位置的高3位。必须在读取`V_CURSOR_LOW`之后进行。 (RO)
H_CURSOR_LOW (0x02)
水平光标最低字节(先读取此寄存器以锁存完整的11位值)
H_CURSOR_LSB
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
H_CURSOR_LSB
水平光标位置的低8位。读取此寄存器将高位锁存到内部影子寄存器中,以实现原子性的水平光标读取。 (RO)
H_CURSOR_HIGH (0x03)
水平光标最高字节(在H_CURSOR_LOW之后读取以获取完整的11位值)
(reserved)
H_CURSOR[10:8]
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
H_CURSOR[10:8]
锁存的水平光标位置的高3位。必须在读取`H_CURSOR_LOW`之后进行。 (RO)
LAYER0_SCROLL_Y_LOW (0x04)
图层0垂直滚动的低8位。必须在写入HIGH寄存器之前写入以锁存完整值。
SCROLL_Y_LSB
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
SCROLL_Y_LSB
Y滚动值的低8位(写入锁存)。单独写入此寄存器无效,直到写入HIGH寄存器。 (WO)
LAYER0_SCROLL_Y_HIGH (0x05)
图层0垂直滚动的高位。写入此寄存器使用先前锁存的LSB完成原子更新。
(reserved)
SCROLL_Y[9:8]
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
SCROLL_Y[9:8]
Y滚动值的高2位。写入此值将锁存的LSB提交到实际的滚动寄存器。 (WO)
LAYER0_SCROLL_X_LOW (0x06)
图层0水平滚动的低8位。必须在写入HIGH寄存器之前写入以锁存完整值。
SCROLL_X_LSB
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
SCROLL_X_LSB
X滚动值的低8位(写入锁存)。单独写入此寄存器无效,直到写入HIGH寄存器。 (WO)
LAYER0_SCROLL_X_HIGH (0x07)
图层0水平滚动的高位。写入此寄存器使用先前锁存的LSB完成原子更新。
(reserved)
SCROLL_X[10:8]
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
SCROLL_X[10:8]
X滚动值的高3位。写入此值将锁存的LSB提交到实际的滚动寄存器。 (WO)
LAYER1_SCROLL_Y_LOW (0x08)
图层1垂直滚动的低8位。必须在写入HIGH寄存器之前写入以锁存完整值。
SCROLL_Y_LSB
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
SCROLL_Y_LSB
Y滚动值的低8位(写入锁存)。单独写入此寄存器无效,直到写入HIGH寄存器。 (WO)
LAYER1_SCROLL_Y_HIGH (0x09)
图层1垂直滚动的高位。写入此寄存器使用先前锁存的LSB完成原子更新。
(reserved)
SCROLL_Y[9:8]
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
SCROLL_Y[9:8]
Y滚动值的高2位。写入此值将锁存的LSB提交到实际的滚动寄存器。 (WO)
LAYER1_SCROLL_X_LOW (0x0A)
图层1水平滚动的低8位。必须在写入HIGH寄存器之前写入以锁存完整值。
SCROLL_X_LSB
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
SCROLL_X_LSB
X滚动值的低8位(写入锁存)。单独写入此寄存器无效,直到写入HIGH寄存器。 (WO)
LAYER1_SCROLL_X_HIGH (0x0B)
图层1水平滚动的高位。写入此寄存器使用先前锁存的LSB完成原子更新。
(reserved)
SCROLL_X[10:8]
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
SCROLL_X[10:8]
X滚动值的高3位。写入此值将锁存的LSB提交到实际的滚动寄存器。 (WO)
VIDEO_MODE (0x0C)
选择当前视频模式
(reserved)
MODE
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
MODE
选择预定义的视频模式,请查看上表了解所有可用选项 (RW)
VIDEO_STATUS (0x0D)
当前视频系统状态
ENABLE
(reserved)
VBLANK
HBLANK
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
ENABLE
置位以启用视频输出。写入1将渲染黑屏。 (RW)
VBLANK
垂直消隐状态(激活时为1) (RO)
HBLANK
水平消隐状态(激活时为1) (RO)
VIDEO_INT_STATUS (0x0E)
中断状态位
(reserved)
VBLANK_INT
GP_INT
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
VBLANK_INT
表示有挂起的垂直消隐中断 (RO)
GP_INT
表示有挂起的通用视频中断 (RO)
VIDEO_INT_CLEAR (0x0F)
清除视频中断标志
(reserved)
CLR_VBLANK
CLR_GP
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
CLR_VBLANK
写入1以清除垂直消隐中断 (WO)
CLR_GP
写入1以清除通用视频中断 (WO)
EN | 中文Beta