首页 文章

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

提问于
浏览
3

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

我的程序的第一个版本使用DOS函数13h . 我的程序的第二个版本使用BIOS功能10h

我现在想要使用直接硬件输出来完成第三个版本 . 我已经阅读了部分书籍,解释了屏幕在VGA显示器上划分为80x25(不关心检测CGA以及所有这些因此我的程序使用内存地址0B800h用于彩色VGA,因为DOSBox很棒而且所有,我的愿望在90岁之前的某个时候搬到Win Assembler) . 我已经读过硬件屏幕上的每个字符都是2个字节(1表示属性,1个表示字符本身,因此你有80x25x2 = 4000字节) . 奇数字节描述属性,偶数字节描述ASCII字符 .

但我的问题是这个 . 无论我如何尝试,我都不能让我的程序输出一个简单的黑白(这只是属性,我假设我可以很容易地改变这个)字符串(这只是一个字节数组)从顶部5行屏幕,左边缘有20个字符(这只是远离基于零的索引的空白字符数,长度为4000字节) . (如果我的计算结果是正确的,即5x80 = 400 20 = 420x2 = 840是我的字符串在4000字节数组内的起始位置)

如何将该属性与字符分开(我让它部分工作,但它只显示每一个字符,然后是一堆随机垃圾(这就是我认为我需要某种字节对的属性和文本),或者如何设置它们以便两者一起被识别 . 一旦计算出来,我如何控制屏幕上文本的位置 . 我哪里出错了 .

我试过在网上寻找这个看似简单的问题,但我找不到解决方案 . 有没有人曾经在DOS和x86程序集中编程,可以告诉我如何通过不使用BIOS或DOS功能,只需使用硬件来完成这个简单的小程序 .

如果可能的话,我真的会提供一个简单的代码片段 . 或者对某些网站或免费电子书的反思 . 我不想买一本关于dos控制台编程的大书,当我很快转向Windows时,这将最终无用 . 我专注于此的唯一原因是因为我想学习真正的装配,而不是一些宏观语言或一些声称是装配的高级语言 .

我正在尝试 Build 一个程序库,这将使汇编更容易学习,所以人们不必工作,尽管10本理论书中的所有3到6章都在一次又一次地解释同样的东西,当真正需要的就足够了知道如何获得一些输出,为变量赋值,获取一些输入,并做一些循环和决策 . 这个理论可以在以后出现,当它们进入循环和决策时,大多数人都会做足够的汇编来完成所有的理论 . 我相信大会应该被教导与任何其他语言没有什么不同,从简单的hello world程序开始,然后获得输入等 . 我想让这成为可能 . 但是,嘿,我只是一个初学者,也许当我了解更多时,我的女儿会改变 .

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

任何人都可以帮助!!


下面是我使用的程序(在Win 7 64位的DOSBox下的MASM 6.1) . 它使用BIOS Intrrupt 10h功能13h子功能0.我想使用直接硬件IO做同样的事情 .


.model small
.stack
.data           ;part of the program containing data
    ;Constants - None
    ;Variables
    MyMsg   db    'Hello World'

.code
Main:
GetAddress:
    mov ax,@data        ;Gets address of data segment
    mov es,ax           ;Loads segment address into es regrister
    mov bp,OFFSET MyMsg ;Load Offset into DX

SetAttributes:
    mov bl,01001111b    ;BG/FG Colour attributes
    mov cx,11           ;Length of string in data segment

SetRowAndCol:
    mov dh,24       ;Set the row to start printing at
    mov dl,68       ;Set the column to start printing at

GetFunctionAndSub:
    mov ah,13h      ;BIOS Function 10h - String Output
    mov al,0        ;BIOS Sub-Function (0-3)

Execute:
    int 10h         ;BIOS Interrupt 10h

EndProg:
    mov ax,4c00h    ;Terminate program return 0 to OS
    int 21h         ;DOS Interrupt 21h

end Main
end

我希望以易于解释的格式提供此功能 . 所以这是我目前的工作 . 我几乎得到了它 . 但它只打印属性,在屏幕上获取字符是一个问题 . (偶尔当我稍微修改它时,我会得到每个具有随机属性的第二个字符(我想我知道原因的技术性,但是不知道有足够的汇编来修复)它)) .


.model small
.stack
.data
    ;Constants
    ScreenSeg   equ     0B800h

    ;Variables
    MyMsg   db  'Hello World'
    StrLen  equ $-MyMsg

.code
Main:               

SetSeg:
    mov ax, ScreenSeg   ;set segment register:
    mov ds, ax

InitializeStringLoop:   ;Display all characters: - Not working :( Y!
    mov cx, StrLen      ;number of characters.
    mov di, 00h         ;start from byte 'h'

OutputString:
    mov [di], offset byte ptr MyMsg[di]
    add di, 2           ;skip over next attribute code in vga memory.
    loop OutputString

InitializeAttributeLoop:;Color all characters: - Atributes are working fine.
    mov cx, StrLen      ;number of characters.
    mov di, 01h         ;start from byte after 'h'

;Assuming I have all chars with same attributes - fine for now - later I would make this
;into a procedure that I will just pass the details into. - But for now I just want a
;basic output tutorial.

OutputAttributes:
    mov [di], 11101100b     ;light red(1100) on yellow(1110)
    add di, 2               ;skip over next ascii code in vga memory.
    loop OutputAttributes

EndPrg:
    mov ax, 4C00h
    int 21h
end Main

当然我想减少用于裸骨要领的指令 . (为了适当的学费目的,在教导他人时少用) . Hense我没有使用MOVSB / W / D等与REP的原因 . 我选择使用标准MOV,INC,ADD等来轻松解释手动循环 . 这些是基本的指令,易于向新手解释 . 所以,如果可能的话,我希望尽可能地保持尽可能接近这一点 .

我知道所有看似错误的是实际字符串处理程序的循环 . 它不会让我按照我想要的方式递增地址 . 它对我的尴尬导致我实际上是一个很好的程序员使用C,C#,VB和Delphi(回来的时候)) . 我知道你不会想到,因为我甚至无法在汇编程序中获得循环,但它是一种不同的语言 . 在高级语言中有2或3个循环,似乎根据指令在汇编程序中进行循环的方法有无限组合 . 所以我说“简单循环”,但实际上有一点简单 .

我希望有人可以帮助我,你会拯救我的装配工,并确保我最终成为一名优秀的装配老师 . 在此先感谢,尤其是阅读这一点 .

3 回答

  • 2

    典型的惯例是使用 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
    
  • 0

    如果你还没有,我会建议你去拿Masm32 Package . 它主要是为了在"Windows today"中轻松使用汇编语言,这非常好,但也会教你很多关于Asm的信息,并且还显示了在早期回复中提到的必不可少的英特尔芯片手册的位置 .

    我在80年代开始编程,所以我可以看到为什么你对它的细节如此感兴趣,我知道我很想念它 . 如果有更多的人从那里开始,它将为他们付出很大的回报 . 你正在做一个很棒的服务!

    我正在玩你正在谈论的直接硬件,我也了解到Windows已经改变了一些DOS服务,BIOS服务也发生了变化,因此有些不再工作了 . 我实际上正在编写一个小的.com程序并在命令提示符窗口中从Win7运行它,打印一个消息并等待一个密钥,非常酷,考虑到2012年的Win7!

    事实上它是BIOS 10h - 0Eh不起作用,所以我尝试Dos 21h 02h写入屏幕,它的工作原理 . 代码如下,因为它是一个.com(命令程序),我认为它可能对你有用 .

    ;这使得一个.com程序(64k限制,代码,数据和所有;必须适合这个空间 . 用于小型实用程序;适用于非常快速的任务 . 实际上DOS命令主要是;小.com程序这样(除了更有用)!;;使用Masm组装; c:\ masm32 \ bin \ ml / AT / c bfc.asm;使用; c:\ masm32 \ bin \ link16 bfc.obj,bfc.com ;;与Masm的Link16链接; Link16是制作这个16bit .com(命令)文件的关键

    SEGMT SEGMENT
    org 100h
    
    Start:
            push    CS
            pop     DS
    
            MOV SI, OFFSET Message
    Next:
            MOV ah, 02h             ; Write Char to Standard out
            MOV dl, [si]            ; Char
            INT 21h                 ; Write it
            INC si                  ; Next Char
            CMP byte ptr[si], 0     ; Done?
            JNE Next                ; Nope
    
    WaitKey:
            XOR ah, ah              ; 0
            INT 16h                 ; Wait for any Key
    ExitHere:        
            MOV ah, 4Ch             ; Exit with Return Code
            xor al, al              ; Return Code
            INT 21h
    
    Message db  "It Works in Windows 7!", 0
    
    SEGMT ENDS
    END Start
    
  • 2

    我曾经做过你所说的所有事情 . 试着记住细节 . Michael Abrash是一个你应该用Google搜索的名字 . 模式-X例如200乘200(240x200?)256色模式非常受欢迎,因为它打破了16色边界并且当时游戏看起来非常好 .

    我认为金属寄存器编程是可行但痛苦的,您可能需要为您感兴趣的芯片获得程序员参考/数据表 . 随着时间的推移从CGA到EGA再到VGA再到VESA,工作方式也发生了变化 . 我认为通常你使用int调用来访问页面框架,然后你可以直接填写它 . VESA我认为这样做,VESA在视频卡支持方面是一个很大的助手,你以前必须为每个芯片编写自己的驱动程序(如果你不想要丑陋的标准模式) .

    我会看看mode-x或vesa并从那里开始 . 无论如何,你需要在里面有一些黑客来完成其中的一些,很难找到一个完整而准确的数据表/程序员参考手册,你总是只需要推一些字节来看看会发生什么 . 开始填充那些应该是页面框架的内存块,直到您在屏幕上看到更改...

    我没有看到我的图书馆中的任何特定的图形编程书籍,除了像图形编程黑皮书这样的abrash书籍这一段时间的尾声 . 我有bios和dos程序员参考,也使用ralf browns列表 . 我确信我有流行视频芯片手册的副本(在互联网之前记得你在那个电话上叫人类用绳子悬挂它,人类拿了一本印刷手册,有时很好地绑定了有时只是一个主食如果那个角落,把它放在一个信封里并邮寄给你,这是你唯一的副本,除非你通过复印机运行它) . 我有很多印刷的东西,不好意思,我不打算回答这个问题 . 我会在脑海中记住这个问题,并查看更多信息,实际上我可能有一些旧的程序方便,绘制分形和其他类似的东西(直接对视频卡/内存实用) .

    编辑 .

    我知道你正在寻找文本模式的东西,这是一种图形模式,但它可能会或可能不会对你想要做的事情有所了解 . int调用和填充页面和调色板内存的组合直接 .

    http://dwelch.s3.amazonaws.com/fly.tar.gz

相关问题