在x86汇编中实现160x100模式

3
我知道在IBM CGA上可以通过使用CRTC将行高度改为两个像素来实现伪160x100的图形模式,但我尝试了几天并没有成功。
根据《Intel®开源HD Graphics和Intel Iris™ Graphics程序员参考手册》第45页(或PDF中的第59页)的说法,我可以通过写入最大扫描线寄存器来实现。我理解是这样的。
我已经尝试直接向内存地址3B5写入值为00000001b的代码,也就是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

我对这种低级的东西还不是很自信,任何帮助都将不胜感激。

2
你在DOSBOX中配置了CGA图形适配器吗? - fuz
DOSBox是一款模拟器/虚拟机。在其中运行的代码将看到一个完整的机器,但其行为完全由DOSBox软件确定,而不是DOSBox所在主机的硬件。英特尔手册可能是VGA / CGA文档的有用来源,但请注意,它记录的任何英特尔特定功能或行为在DOSBox中都不会发生。如果您想要编程实际的英特尔硬件,可以在裸机上引导您的代码。此外,请参阅x86标签wiki以获取大量x86链接(没有直接相关)。 - Peter Cordes
获取伪160x100图形模式的更简单方法可能是使用标准的80x50 VGA文本模式和具有2x2块字符的自定义字体。另一种选择是使用VGA的320x200图形模式,在绘制像素时只需将其宽度和高度加倍即可。 - Ross Ridge
我知道DOSBox是一个模拟器。我想让它在DOSBox中运行,因为DOSBox当前配置为CGA模式。由于我没有实际硬件的访问权限,所以我只能使用模拟器。 - verbicide
1个回答

8
你写的不是地址3b5h,而是地址3b50h。如果你想写入地址3b5h,你需要将ES设置为0,然后执行类似于mov BYTE [es:3b5h], 01的操作,但这也不是你想要做的。在你提供的手册中给出的地址3b5h是一个“I/O地址”,意味着它存在于完全不同的地址空间中,需要使用专门的IN和OUT指令才能访问。
要将值01写入I/O地址3b5h,你可以使用以下代码:
mov dx, 3b5h
mov al, 01
out dx, al

请注意,这是您可以在此处使用的OUT指令的唯一形式。您必须使用DX寄存器来指定地址,并使用AL寄存器提供要写入该I/O地址的数据。
除了那也不对。正如您链接的手册所解释的那样,I/O地址3b5h是MDA数据端口,CGA数据端口位于I/O地址3d5h。最后,“最大扫描线寄存器”并不是唯一通过I/O地址3d5h访问的寄存器。有几个不同的寄存器使用此地址。要选择要写入的寄存器,您需要首先通过将其索引值写入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视频卡的模拟精度。

你的代码似乎组装得很好,并且完成了工作。谢谢! - verbicide
@CollisionDetection:当一个答案解决了你的问题时,你应该点击上下投票箭头下面的复选框,而不是留下感谢评论。 - Peter Cordes
这是我的第一个SO问题,我还在逐渐掌握其中的技巧。 - verbicide

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接