gpt4 book ai didi

nasm - 旧dos组件中的硬件VGA文本模式IO问题

转载 作者:行者123 更新时间:2023-12-01 16:03:28 29 4
gpt4 key购买 nike

在阅读了至少约4本关于汇编编程的不同书籍的前3或4章之后,我进入了一个阶段,可以使用MASM 6.11将“Hello World”放置在dosbox控制台上。想象一下我的喜悦!

我程序的第一个版本使用DOS Function 13h。
我程序的第二个版本使用了BIOS Function 10h

我现在想使用直接硬件输出来制作第三个版本。我已经阅读了解释屏幕在VGA显示器上分成80x25的书的各个部分(不必为检测CGA等烦恼,所以我的程序将内存地址0B800h用于彩色VGA,因为DOSBox非常有用,而且我也渴望在90岁之前的某个时候移至Win Assembler)。我已经阅读到硬件屏幕上的每个字符都是2个字节(属性为1个字节,字符本身为1个字节,因此您有80x25x2 = 4000字节)。奇数字节描述属性,偶数字节描述ASCII字符。

但是我的问题是这个。无论如何尝试,我都无法让我的程序输出一个简单的黑白(这只是属性,我认为我可以相当容易地更改它)字符串(只是一个字节数组),从顶部开始5行屏幕上,并且从左边缘开始输入20个字符(这是距4000字节长的从零开始的索引处的空白字符数)。 (如果我的计算正确,那我的字符串在4000字节数组中的起始位置是5x80 = 400 + 20 = 420x2 = 840)

如何将属性与字符分开(我只能部分使用它,但它仅显示每个第二个字符,然后显示一堆随机垃圾(这就是我认为我需要某种字节对作为属性和文本的方式),或者我该如何设置它们以便一起识别。一旦计算完成后,如何控制文本在屏幕上的位置?我要去哪里了?

我曾尝试在网上寻找这个看似简单的问题,但无法找到解决方案。有谁曾经在DOS和x86汇编语言中编程,可以告诉我如何通过不使用BIOS或DOS函数而仅通过硬件来执行此简单的小程序。

如果可能的话,我真的很喜欢一个简单的代码段。或对某些网站或免费电子书的引用。我不想买一本关于dos控制台编程的大书,当我很快移到Windows时,它最终将毫无用处。我专注于此的唯一原因是因为我想学习真正的汇编语言,而不是学习一些宏语言或某些自称是汇编语言的高级语言。

我正在尝试建立一个例程库,使程序集更易于学习,因此人们不必工作,尽管10本理论书籍中的所有3至6章基本上都在必要的条件下一次又一次地解释相同的内容知道如何获得一些输出,为变量分配值,获得一些输入以及进行一些循环和决策。该理论可以在以后出现,并且当他们开始循环和做出决定时,大多数人将已经完成了足够的汇编程序以反正所有理论。我相信beleive汇编的教学方法与其他任何语言都一样,从一个简单的hello world程序开始,然后获得输入等。我想让这成为可能。但是,嘿,我只是一个初学者,当我学到更多时,也许我的教义就会改变。

另一个注意事项,我知道一个问题不是DOSBox,因为我有一台非常老的PC运行的是真正的MS-DOS V6.2,并且该程序仍然无法正常工作(但给出的输出几乎相同)。实际上,DOSBox实际上运行我的某些旧程序甚至比True dos更好。宝石台式机就是一个例子。只是想在人们尝试提出它与模拟器有关的问题之前将其清除。不可能,不是有这么简单的程序。不用担心,问题在于我的小脑袋无法完全理解所需的东西。

有人可以帮忙吗!

下面是我使用的程序(Win 7 64位上的DOSBox下的MASM 6.1)。它使用BIOS Intrrupt 10h Function 13h子功能0。我想使用直接硬件IO进行相同的操作。

.model小
。堆栈
.data;包含数据的程序部分
;常量-无
;变量
MyMsg db“Hello World”

。码
主要:
获取地址:
mov ax,@ data;获取数据段地址
mov es,ax;将段地址加载到es regrister中
mov bp,OFFSET MyMsg;将偏移量加载到DX中

SetAttributes:
mov bl,01001111b; BG / FG颜色属性
mov cx,11;数据段中字符串的长度

SetRowAndCol:
mov dh,24;将行设置为从以下位置开始打印
mov dl,68;将列设置为从以下位置开始打印

GetFunctionAndSub:
mov ah,13h; BIOS函数10h-字符串输出
mov al,0; BIOS子功能(0-3)

执行:
int 10h; BIOS中断10h

EndProg:
mov ax,4c00h;终止程序向OS返回0
int 21h; DOS中断21h

主端
结束


我想以一种易于解释的格式进行操作。这是我目前的工作方式。我快知道了。但是它仅打印属性,因此在屏幕上显示字符是一个问题。 (有时,当我稍加修改时,我会得到具有随机属性的第二个字符(我想我知道为什么这样,但是不知道足够的汇编器来解决)。

.model小
。堆栈
。数据
;常量
ScreenSeg equ 0B800h

;变量
MyMsg db“Hello World”
StrLen equ $ -MyMsg

。码
主要:

SetSeg:
mov ax,ScreenSeg;设置段寄存器:
mov ds,ax

InitializeStringLoop:;显示所有字符:-不起作用:(是!
mov cx,StrLen;字符数。
mov di,00h;从字节'h'开始

OutputString:
mov [di],偏移字节ptr MyMsg [di]
添加di,2;跳过vga内存中的下一个属性代码。
循环OutputString

InitializeAttributeLoop :;为所有字符上色:-属性工作正常。
mov cx,StrLen;字符数。
mov di,01h;从'h'之后的字节开始

;假设我所有具有相同属性的字符-暂时可以-稍后我将使其
;进入一个程序,我将把细节传递给它。 -但现在我只想要一个
;基本输出教程。

OutputAttributes:
mov [di],11101100b;在黄色(1110)上呈红色(1100)
添加di,2;跳过vga内存中的下一个ascii代码。
循环OutputAttributes

EndPrg:
机斧,4C00h
21小时
主端


当然,我想减少对裸露骨骼必需品的使用说明。 (出于适当的学费目的,在教其他人时应少支付)。弄清楚我没有在REP中使用MOVSB / W / D ect的原因。我选择使用标准MOV,INC,ADD ect来简化解释手动循环。这些是足够基本的说明,易于向新手解释。因此,如果可能的话,我想使其尽可能接近。

我基本上知道似乎所有的错误都是实际字符串处理程序的循环。它不能让我按我希望的方式增加地址。它给我带来的尴尬是因为我实际上是使用C++,C#,VB和Delphi的优秀程序员(回溯何时)。我知道您不会认为即使在汇编器中也无法获得正确的循环,但这是一种不同的语言。在高级语言中有2或3个循环,并且似乎有多种方法可以根据指令在汇编器中完成循环。所以我说“简单循环”,但实际上并没有那么简单。

我希望有人可以帮助我,您将省下我的集会顾问,并确保我最终成为一名优秀的集会老师。在此先感谢您,特别是感谢您阅读本文。

最佳答案

典型的约定是使用ds:si作为源,并使用es:di作为目标。

因此,它最终类似于(未试用):

  mov ax, @data
mov ds, ax
mov ax, ScreenSeg
mov es, ax
...
mov si, offset MyMsg
OutputString:
mov al, byte ptr ds:[si]
mov byte ptr es:[di], al
add si, 1 ; next character from string
add di, 2 ; skip over next attribute code in vga memory.
loop OutputString

关于nasm - 旧dos组件中的硬件VGA文本模式IO问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6866746/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com