Full picture
12

文本控制器

12.1 概述

瓦片地图的 layer0layer1(参见瓦片地图存储器)足以实现一个功能性的文本终端或控制台输出。然而,在 8 位系统上完全通过软件实现这一点可能并不简单。光标位置计算可能需要乘法、取模运算以及额外的滚动和换行逻辑。

文本控制器通过以下功能简化了这一过程:

  • 硬件光标
  • 自动滚动
  • 换行处理
  • 其他文本显示辅助功能

与其他控制器一样,文本控制器可以映射到 I/O 端口上起始地址为 0xA0设备分片中。其设备索引为 0

12.2 硬件光标

文本控制器包含一个可定制的硬件光标。光标是一个瓦片(8×12 像素),可以显示来自字形存储器的任何字符,通过 CURSOR_CHARACTER 寄存器选择。

其颜色通过 CURSOR_COLORS 配置,其工作方式与 layer1 条目类似:

  • 高半字节(4 位)= 背景颜色索引
  • 低半字节(4 位)= 前景颜色索引

两个索引均引用调色板存储器中的前 16 个条目。

Name Description Offset Access
CURSOR_Y 设置光标垂直位置。 0x01 R/W
CURSOR_X 设置光标水平位置。 0x02 R/W
CURSOR_BLINK_TIMING 光标闪烁速度。控制光标可见/不可见的帧数。 0x06 R/W
CURSOR_CHARACTER 用于显示光标的字符字形 0x07 R/W
CURSOR_COLORS 光标颜色,格式同CURRENT_COLOR 0x08 R/W

光标闪烁

闪烁时序通过 CURSOR_BLINK_TIMING 设置,单位为

  • 例如,30 = 显示 30 帧(60 Hz 下约 500 毫秒),隐藏 30 帧
  • 0 是特殊值,表示始终隐藏
  • 2550xFF)是特殊值,表示始终可见

当隐藏时,下方的字符仍然可见,使得光标的行为类似于覆盖在 layer0 之上的叠加层,类似于图形模式下的精灵。

位置跟踪

光标的当前列和行(以字符单位计,而非像素)存储在 CURSOR_XCURSOR_Y 中。

这些寄存器是可读写的,例如,将 CURSOR_X 设置为 1 可将光标移动到第二列。

保存与恢复

CTRL 中的两个位可以轻松地临时重定位光标:

  • SAVE_CURSOR 存储当前的 X 和 Y
  • RESTORE_CURSOR 恢复存储的 X 和 Y

仅保存位置,光标的字符和颜色不受影响。

12.3 字符输出

PRINT_CHAR 写入任何 8 位值,都会使用 CURRENT_COLOR 中设置的颜色,在光标位置显示相应的字形(来自字形存储器)。

在内部,字符代码写入 layer0CURRENT_COLOR 值写入 layer1,偏移量根据光标位置和当前滚动值计算得出。

写入后,光标 X 递增。如果 X 超过最后一列(640×480 模式下为 80,320×240 模式下为 40),它将换行到下一行的开头,如果已经在最后一行,则换行到屏幕顶部。

自动滚动

硬件也支持自动滚动。CTRL 寄存器的两个控制位修改此行为:

  • AUTO_SCROLL_X:设置后,到达最后一可见列时将水平滚动而非换行(光标 X 保持不变)
  • AUTO_SCROLL_Y:设置后,到达最后一行时将垂直滚动

如果启用 AUTO_SCROLL_Y 后发生垂直滚动,CTRL 中的 SCYF 标志会被置位,通知 CPU 可能需要清除新行。

滚动偏移量存储在 SCROLL_XSCROLL_Y 中。这些寄存器是可读写的,因此也可以手动写入,但不得超过边界:

  • 80×40 模式:X ≤ 79,Y ≤ 39
  • 40×20 模式:X ≤ 39,Y ≤ 19

光标位置不受滚动设置的影响。

在大多数情况下,为模拟终端,AUTO_SCROLL_X 被禁用,而 AUTO_SCROLL_Y 被启用。

12.4 换行

转到下一行

写入 PRINT_CHAR 的值不会被解释为 ASCII,它们直接按原样写入 layer0。 虽然默认的字形存储器使用类似 ASCII 的布局,但这纯粹是约定俗成的。

在软件中实现换行需要以下步骤:

  1. 读取 CURSOR_Y
  2. 递增它并将 CURSOR_X 设置为 0
  3. 如果已在最后一行:
    • 如果启用了垂直滚动:递增 SCROLL_Y(必要时回绕),设置 SCYF 标志
    • 否则:将 CURSOR_Y 回绕到 0

这在 8 位 CPU 上可能代价较高。为简化此过程,CTRL 中的 DO_NL 位可执行整个序列:

  1. 递增 Y,设置 X = 0
  2. 如果 Y ≤ 最大可见行:完成
  3. 否则:
    • 如果启用了垂直滚动:递增 SCROLL_Y(必要时回绕),设置 SCYF
    • 否则:设置 Y = 0

延迟换行

在默认模式下,到达最后一列会导致立即换行到下一行的开头。 这可能导致"换行故障":连续打印 80 个字符后跟一个换行符,会导致跳过两行而不是一行。

以下示例可以轻松重现此问题:

  1. 从光标位置 (0,0) 开始
  2. 打印 80 个字符 → 光标换行到 (0,1)
  3. 打印换行符 → 光标移动到 (0,2)

许多终端在光标已经换行的情况下会忽略换行符。

为支持此行为,CTRL 中的 WAIT_AND_WRAP 位会延迟换行。到达最后一列后,光标在 X 方向上保持越界状态,直到下一次操作:

  • 如果下一次操作是 DO_NL:忽略换行,光标仅换行到下一行
  • 如果下一次操作是 PRINT_CHAR:先换行,再打印字符
  • 如果下一次操作是写入 CURSOR_Y:Y 改变,X 保持越界状态

12.5 寄存器总览

Name Description Base-relative address Access
PRINT_CHAR 在当前光标位置写入一个字符 0x00 WO
CURSOR_Y 设置光标垂直位置。 0x01 R/W
CURSOR_X 设置光标水平位置。 0x02 R/W
SCROLL_Y 文本层的垂直滚动。 0x03 R/W
SCROLL_X 文本层的水平滚动。 0x04 R/W
CURRENT_COLOR 打印字符的当前文本颜色 0x05 R/W
CURSOR_BLINK_TIMING 光标闪烁速度。控制光标可见/不可见的帧数。 0x06 R/W
CURSOR_CHARACTER 用于显示光标的字符字形 0x07 R/W
CURSOR_COLORS 光标颜色,格式同CURRENT_COLOR 0x08 R/W
CTRL 文本控制器控制寄存器,包含行为标志和命令 0x09 varies

12.6 寄存器

CURSOR_Y (0x01)
设置光标垂直位置。
CURSOR_Y
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
CURSOR_Y
光标Y位置。写入可垂直移动光标。 (R/W)
CURSOR_X (0x02)
设置光标水平位置。
CURSOR_X
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
CURSOR_X
光标X位置。写入可水平移动光标。 (R/W)
SCROLL_Y (0x03)
文本层的垂直滚动。
OFFSET_Y
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
OFFSET_Y
垂直滚动偏移量或绝对Y位置。 (R/W)
SCROLL_X (0x04)
文本层的水平滚动。
OFFSET_X
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
OFFSET_X
水平滚动偏移量或绝对X位置。 (R/W)
CURRENT_COLOR (0x05)
打印字符的当前文本颜色
FG_COLOR
BG_COLOR
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
FG_COLOR
前景色,取自全局调色板的前16个条目 (R/W)
BG_COLOR
背景色,取自全局调色板的前16个条目 (R/W)
CURSOR_CHARACTER (0x07)
用于显示光标的字符字形
CURSOR_CHAR
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
CURSOR_CHAR
作为光标显示的ASCII字符 (R/W)
CURSOR_COLORS (0x08)
光标颜色,格式同CURRENT_COLOR
FG_COLOR
BG_COLOR
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
FG_COLOR
光标的前景色,取自全局调色板的前16个条目 (R/W)
BG_COLOR
光标的背景色,取自全局调色板的前16个条目 (R/W)
CTRL (0x09)
文本控制器控制寄存器,包含行为标志和命令
SAVE_CURSOR
RESTORE_CURSOR
AUTO_SCROLL_X
AUTO_SCROLL_Y
WAIT_AND_WRAP
(reserved)
SCYF / DO_NL
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
Reset
SAVE_CURSOR
保存当前光标位置 (WO)
RESTORE_CURSOR
恢复光标到最后保存的位置 (WO)
AUTO_SCROLL_X
若为1,到达行末时自动水平滚动;若为0,则换行 (RW)
AUTO_SCROLL_Y
若为1,到达底部时自动垂直滚动;若为0,则换行 (RW)
WAIT_AND_WRAP
若为1,等待有可用空间再换行;否则跳过 (RW)
SCYF / DO_NL
读取时,表示打印字符或换行后发生了自动Y滚动。
写入时,手动插入换行,触发与自动换行相同的效果。 (R/W)
EN | 中文Beta