在 x86 汇编中实现 160x100 模式
Achieving 160x100 Mode in x86 Assembly
我早就知道可以在 IBM CGA 上通过使用 CRTC 将行高更改为两个像素来实现伪 160 x 100 图形模式。几天来我一直在努力完成这个,走到了死胡同。
英特尔® 开源高清显卡和
Intel Iris™ Graphics Programmer's Reference Manual 声称我可以在第 45 页(或 PDF 中的第 59 页)通过写入最大扫描线寄存器来执行此操作,或者这就是我从中解释的内容。
我已经尝试直接写入值为 00000001b 的内存地址 3B5,或者我相信是 2 条扫描线的代码。当我在 DOSBox 中测试它时,它什么也没做。
如果你想看我写的代码assemble in NASM:
BITS 16
xor bx,bx
mov ax, 3b5h
mov es, ax
mov ah, 00000001b
mov BYTE [es:bx], ah ; write 00000001b to 0x03b5:0000, right?
cli
hlt
我对这种低级的东西还不是很有信心,如果有任何帮助,我们将不胜感激。
您不是在写入地址 3b5h,而是在写入地址 3b50h。如果你想写地址 3b5h,你会用 0 加载 ES,然后做类似 mov BYTE [es:3b5h], 01
的事情,但这也不是你想要做的。您链接的手册中给出的地址 3b5h 是一个 "I/O address",这意味着它位于一个完全不同的地址 space,您需要使用专门的 IN 和 OUT 指令才能访问该地址。
要将值 01 写入 I/O 地址 3b5h,您可以使用如下代码:
mov dx, 3b5h
mov al, 01
out dx, al
请注意,这是您可以在此处使用的 OUT instruction 的唯一形式。您必须使用 DX 寄存器指定地址,并使用 AL 寄存器提供要写入该 I/O 地址的数据。
除非那也不对。正如您链接的手册所解释的那样,I/O 地址 3b5h 是 MDA 数据端口,CGA 数据端口位于 I/O 地址 3d5h。最后,"Maximum Scanline Register" 不是通过 I/O 地址 3d5h 访问的唯一寄存器。有几个不同的寄存器使用这个地址。要select 您想写入哪个寄存器,您首先需要通过将其索引值写入位于I/O 地址3d4h 的CGA CRT 控制器索引寄存器来选择它。这意味着您的代码需要如下所示:
mov dx, 3d4h ; CGA CRTC Index Register
mov al, 09h ; Maximum Scan Line Reigster
out dx, al
mov dx, 3d5h ; CGA CRTC Data Port
mov al, 01 ; 2 scan lines
out dx, al
请注意,这可能仍然不正确,因为 VGA 将其他参数添加到最大扫描线寄存器。您可能需要保留这些值,但在实际的 CGA 硬件上这是不可能的,因为寄存器是只读的。这可能取决于您 运行 您的代码模拟真实 CGA 视频卡的准确程度。
我早就知道可以在 IBM CGA 上通过使用 CRTC 将行高更改为两个像素来实现伪 160 x 100 图形模式。几天来我一直在努力完成这个,走到了死胡同。
英特尔® 开源高清显卡和 Intel Iris™ Graphics Programmer's Reference Manual 声称我可以在第 45 页(或 PDF 中的第 59 页)通过写入最大扫描线寄存器来执行此操作,或者这就是我从中解释的内容。
我已经尝试直接写入值为 00000001b 的内存地址 3B5,或者我相信是 2 条扫描线的代码。当我在 DOSBox 中测试它时,它什么也没做。
如果你想看我写的代码assemble in NASM:
BITS 16
xor bx,bx
mov ax, 3b5h
mov es, ax
mov ah, 00000001b
mov BYTE [es:bx], ah ; write 00000001b to 0x03b5:0000, right?
cli
hlt
我对这种低级的东西还不是很有信心,如果有任何帮助,我们将不胜感激。
您不是在写入地址 3b5h,而是在写入地址 3b50h。如果你想写地址 3b5h,你会用 0 加载 ES,然后做类似 mov BYTE [es:3b5h], 01
的事情,但这也不是你想要做的。您链接的手册中给出的地址 3b5h 是一个 "I/O address",这意味着它位于一个完全不同的地址 space,您需要使用专门的 IN 和 OUT 指令才能访问该地址。
要将值 01 写入 I/O 地址 3b5h,您可以使用如下代码:
mov dx, 3b5h
mov al, 01
out dx, al
请注意,这是您可以在此处使用的 OUT instruction 的唯一形式。您必须使用 DX 寄存器指定地址,并使用 AL 寄存器提供要写入该 I/O 地址的数据。
除非那也不对。正如您链接的手册所解释的那样,I/O 地址 3b5h 是 MDA 数据端口,CGA 数据端口位于 I/O 地址 3d5h。最后,"Maximum Scanline Register" 不是通过 I/O 地址 3d5h 访问的唯一寄存器。有几个不同的寄存器使用这个地址。要select 您想写入哪个寄存器,您首先需要通过将其索引值写入位于I/O 地址3d4h 的CGA CRT 控制器索引寄存器来选择它。这意味着您的代码需要如下所示:
mov dx, 3d4h ; CGA CRTC Index Register
mov al, 09h ; Maximum Scan Line Reigster
out dx, al
mov dx, 3d5h ; CGA CRTC Data Port
mov al, 01 ; 2 scan lines
out dx, al
请注意,这可能仍然不正确,因为 VGA 将其他参数添加到最大扫描线寄存器。您可能需要保留这些值,但在实际的 CGA 硬件上这是不可能的,因为寄存器是只读的。这可能取决于您 运行 您的代码模拟真实 CGA 视频卡的准确程度。