assembly - 在 x86 汇编中实现 160x100 模式

标签 assembly x86 intel dosbox undocumented-behavior

我早就知道,通过使用 CRTC 将行高更改为两个像素,可以在 IBM CGA 上实现伪 160 x 100 图形模式。几天来,我一直在努力实现这一目标,但走到了死胡同。

Intel® Open Source HD Graphics and Intel Iris™ Graphics Programmer's Reference Manual声称我可以在第 45 页(或 PDF 中的第 59 页)通过写入最大扫描线寄存器来执行此操作,或者这就是我从中解释的内容。

我已经尝试过直接写入值为 00000001b 的内存地址 3B5,或者我相信是 2 条扫描线的代码。当我在 DOSBox 中测试它时,它什么也没做。

如果您想查看我编写的将在 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 地址”,这意味着它位于一个完全不同的地址空间中,您需要使用专门的 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。最后,“最大扫描线寄存器”并不是唯一通过 I/O 地址 3d5h 访问的寄存器。有几个不同的寄存器使用这个地址。要选择要写入的寄存器,首先需要通过将其索引值写入 I/O 地址 3d4h 处的 CGA CRT Controller 索引寄存器来选择它。这意味着您的代码需要如下所示:

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 视频卡的准确程度。

关于assembly - 在 x86 汇编中实现 160x100 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39337743/

相关文章:

linux - 如何使用 RF24 通过 USB 在普通 PC (Linux) 上与 nRF24L01+ 通信?

c - 如何在没有调用或跳转的情况下调用ASM中的函数?

assembly - 测试 xmm/ymm 寄存器是否为零的更快方法?

linux - 如何在 kdbg 中处理用户输入/输出(测试汇编代码)?

assembly - 在汇编/编译/链接时构建静态 IDT 和 GDT 所需的解决方案

linux - __gmon_start 在_start 之前执行

assembly - x86组装极限新手查询: "invalid instruction operands"?

C++:英特尔 SIMD 内在函数类成员的初始化

英特尔 HAXM API 可以在 QEMU 之外使用吗?

c++ - 内联汇编的麻烦