【问题标题】:ASM subroutine to print coloured text at specific location on the screenASM 子程序在屏幕上的特定位置打印彩色文本
【发布时间】:2012-11-06 05:52:52
【问题描述】:

我正在尝试编写一些 ASM 代码,这些代码将使用 BIOS 中断将一些文本写入显示器。此代码将从引导扇区运行。

我有

msgText DB "Hello"                  ;Text
msgCol  DB 0x07,0x08,0x09,0x0A,0x0B ;Colours
msgXY   DW 0x0E26                   ;Col/Row
msgLen  DB 0x05                     ;Length

消息只是“你好”,每个字母都有不同的颜色。消息在屏幕上的位置大致在中间,长度为5。

我想编写一个函数,将任何消息/颜色/xy/长度写入屏幕,但现在,让我们专注于这个。

print:
  MOV AH,0x02        ;Tell BIOS we want to set the cursor position
  MOV DX,[msgXY]     ;Tell BIOS where the cursor should go
  INT 0x10           ;Call BIOS video interrupt

  XOR ECX,ECX        ;Clear ECX
  MOV CX,[msgLen]    ;Set CX = msgLen

  MOV AH,0x0E        ;We want to print characters on the screen

  _loop:
    MOV EDX,msgText  ;Move address of text to EDX
    DEC ECX          ;Temporarily decrement ECX
    ADD EDX,ECX      ;Add ECX to the address of msgText
    INC ECX          ;Increment ECX back to what it was
    MOV AL,BYTE[EDX] ;Put the contents of the memory at EDX into AL

    MOV EDX,msgCol   ;Move address of text colour to EDX
    DEC ECX          ;Temporarily decrement ECX
    ADD EDX,ECX      ;Add ECX to the address of msgCol
    INC ECX          ;Increment ECX back to what it was
    MOV BL,BYTE[EDX] ;Put the contents of the memory at EDX into BL

    INT 0x10         ;Call BIOS video interrupt
    LOOP _loop
  RET

现在,我应该可以用CALL print 调用它了。

(是的,我知道这会向后打印“Hello”,我并不担心。我可以将它作为“olleH”存储在内存中,我不在乎 - 我有更大的问题)

首先,我将CX 设置为[msgLen] 的行会导致问题。我不得不对其进行硬编码以使CX 等于0x05,但我不知道为什么。

其次,大概是出于同样的原因,当我尝试设置颜色代码时,我遇到了与文本长度相同的问题。如果我摆脱这些行并只硬编码MOV BL,0x0C,那么它工作正常。

不过,奇怪的是,MOV DX,[msgXY] 部分似乎工作正常。

我不能给出任何确切的问题,因为我已经尝试通过改变很多东西来解决这个问题几个小时,而我在这里和那里改变的小东西似乎会产生非常不可预测的结果。此外,调用各种 BIOS 中断似乎会更改某些寄存器,这很烦人。另外,当我将东西压入堆栈并稍后将其弹出时,情况有所不同,因此我一直避免使用PUSHPOP

顺便说一句,我现阶段仍处于实模式 x86。

当然,我正在做的事情不可能这么难。也许我只是需要一杯咖啡。或者一些帮助? :)

【问题讨论】:

    标签: assembly nasm bootloader bios


    【解决方案1】:

    嗯,“首先”,您已将msgLen 定义为db。当您mov cx, [msgLen] 时,您加载两个字节。这是否会导致问题取决于msgLen 之后的内容(如果有的话)。将msgLen 定义为dw,或者将mov cl, [msgLen] 定义为(因为您已经清除了高位)。

    我没有看到“Secondly”的类似问题 - 您将一个字节移动到一个 8 位寄存器中。您在本节中使用 32 位寄存器似乎很奇怪。 “应该”工作,但它会使您的代码膨胀一点。当然,[dx] 不是有效的 16 位寻址模式 - 您必须使用 bx(用于其他目的)、sidi。由于您使用的是 32 位寄存器,lea edx, [edx + ecx - 1] 应该做您想做的事,而无需临时递减和递增 ecx。 (但我认为这对您的问题没有帮助)

    预计某些 BIOS 中断会改变寄存器。是否奇怪取决于哪些中断正在执行此操作。大多数情况下他们没有。无法poppushed 相同的值很奇怪。要么你发现了一个 CPU 错误,要么你做错了什么。猜猜哪个更有可能。 :) 它们是有用的指令,所以不能使用它们是一种耻辱。您没有显示引导扇区的“第一幕”,您在其中初始化 dses 并设置了一个合理的堆栈 - 也许那里有问题?

    你看过 int 10h/13h 吗?我认为它会做你想要的(“彩虹”文本)。这是一个奇怪的中断,因为它希望文本地址在es:bp,但很有用。另一种方法是将字符和颜色直接插入 B800h:xxxx 处的“屏幕内存”——一个字节用于字符,一个字节用于颜色。

    引导扇区并不是特别容易编写。如果你有真正的 dos 可用(甚至是 Dosbox),它可能有助于“试用”你的例程作为 .com 文件的一部分(其中 DEBUG 可用)。 bootsector 是与 dos 不同的环境,因此它不会解决您的所有问题,但可能有助于缩小范围。

    咖啡可能会有所帮助,但主要是……勇气!

    最好, 弗兰克

    【讨论】:

    • 感谢您的建议。到目前为止,我在“第一幕”中没有太多其他内容。扇区 0 上的第一阶段引导加载程序除了读取下一个扇区并跳转到它之外什么都不做。您在这里看到的代码就是那里的代码(减去几位)。就在这一点之后,我启用了 A20 和保护模式,但我什至还没有考虑堆栈或 GDT - 对我来说仍然非常复杂。
    • 所以... ds=?, es=?, ss=?, sp=? BIOS 将它们留在哪里?这可能适用于一台特定的机器,但不太可能适用于“任何机器”。也许这对于您的目的不是必需的。我不会急于进入 Pmode。至少在您仍然有可用的 BIOS 中断时找出您安装了多少内存。 osdev.org 可能已经被提及了很多次,但再次提及它不会有什么坏处——那里有大量的好信息!快乐开机!
    【解决方案2】:

    您可以使用此代码:

    mov si,msg_text
    call print_colored
    print_colored:
    .loop:
    lodsb
    cmp al,0
    je .done
    inc bl
    mov ah,0x0E
    Int 0x10
    jmp .loop
    .done:
    ret
    

    它使您的字符串着色,但不是供您选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-20
      • 1970-01-01
      • 2016-03-16
      • 2021-12-14
      • 1970-01-01
      • 1970-01-01
      • 2023-04-06
      相关资源
      最近更新 更多