如何将文本添加到用汇编编写的 OS
How to add text to OS written in assembly
所以我开始学习汇编,并且正在用 FASM 编写一个简单的 OS。我有一个带有灰色顶栏和光标的蓝屏,但无法让文本出现在一行上。在第一行我希望它说 "FILE SYSTEM" 然后在其他行我想要其他东西。我会把代码放在这里:
mov ax, 9ch
mov ss, ax
mov sp, 4096d
mov ax, 7c0h
mov ds, ax
;----------------
;this sets blue to background
mov ah, 09h
mov cx, 1000h
mov al, 20h
mov bl, 17h
int 10h
;end of blue
;start of gray top
mov ah, 09h
mov cx, 80d
mov al, 20h
mov bl, 87h
int 10h
;end of gray
;top bar
;end of top bar
;define mouse
mov ah, 01h
mov cx, 07h
int 10h
mov bl, 5h
mov cl, 5h
_mouser:
mov ah, 02h
mov dl, bl
mov dh, cl
int 10h
mov ah, 00h
int 16h
cmp al, 77h
je _up
cmp al, 73h
je _down
cmp al, 61h
je _left
cmp al, 64h
je _right
cmp al, 20h
je _click
jmp _mouser
_click:
mov ah, 0eh
mov al, 0b2h
int 10h
jmp _mouser
_up:
cmp cl, 0h
je _mouser
sub cl, 1h
jmp _mouser
_down:
cmp cl, 24d
je _mouser
add cl, 1h
jmp _mouser
_left:
cmp bl, 0h
je _mouser
sub bl, 1h
jmp _mouser
_right:
cmp bl, 79d
je _mouser
add bl, 1h
jmp _mouser
;----------------
times 510-($-$$) db 0
dw 0xAA55
我试过了
mov ah, eoh
mov al, 'F'
int 10h
问题是只能生成单个字符而不是字符串。
PC 的 ROM BIOS 提供了一组视频服务,通过中断 10h 调用,包括一些将字符打印到字符串的服务。可在 here.
中找到有关它们的综合文档
看来你已经发现了服务0Eh,它在当前字符位置向屏幕写入一个字符,并向前移动字符位置。这将屏幕视为电传打字机 (TTY),并且非常容易在屏幕上获得输出。
(至少,它 看起来 就像您在尝试调用服务 0Eh。您的代码不正确。您有 mov ah, eoh
,这是不正确的. o
不是十六进制值,即使这是 0 的拼写错误,您也将半字节颠倒了。它应该是 mov ah, 0Eh
。)
如果你想打印一个字符串(多个字符),你基本上有两个选择:
您可以迭代调用类似 0Eh 的服务,每次将一个字符写入字符串。一个示例实现是:
mov ah, 0Eh ; service 0Eh: print char as TTY
.PrintNextChar:
mov al, BYTE PTR [si] ; get next character in string, pointed to by SI
inc si ; increment pointer
test al, al ; is character == 0 (end-of-string)?
je .Done
int 10h
jmp .PrintNextChar
.Done
这会打印 SI
指向的字符串中的字符,直到它到达 0(NUL 字符),这表示字符串的结尾(标准的 C 样式 NUL 终止字符串)。
但是,这种一次打印一个字符的方法相对较慢。相反,人们通常更喜欢……
使用服务 1300h 或 1301h 一次打印整个字符串。区别在于服务 1301h 在打印字符串后使光标前进,而服务 1300h 不更改光标。否则,它们是相同的。
这些服务的参数记录在上面的 link 中;为方便起见转载于此:
AX
== 1300h/1301h
BL
== 视频属性(文本模式下,指定前景色和背景色)
BH
==视频页面(通常为0)
CX
== 字符串长度
DL
/DH
== column/row 字符串的起始位置
ES:BP
== 字符串开头地址
显然这需要你事先知道字符串的长度,并将其作为参数传入CX
寄存器中。该字符串由 ES:BP
.
指向
在您的例子中,要打印 "FILE SYSTEM",您需要在包含该字符串的 DATA 段中声明一个字符数组,然后执行如下操作:
MyString DB "FILE SYSTEM"
mov ax, ds
mov es, ax ; set ES == DS
mov bp, MyString
mov cx, 11 ; length of string (number of chars)
mov bx, 07h ; foreground & background color (white on black)
xor dx, dx ; starting position (top-left)
mov ax, 1301h ; service 1301h: print string and update cursor
int 10h
所以我开始学习汇编,并且正在用 FASM 编写一个简单的 OS。我有一个带有灰色顶栏和光标的蓝屏,但无法让文本出现在一行上。在第一行我希望它说 "FILE SYSTEM" 然后在其他行我想要其他东西。我会把代码放在这里:
mov ax, 9ch
mov ss, ax
mov sp, 4096d
mov ax, 7c0h
mov ds, ax
;----------------
;this sets blue to background
mov ah, 09h
mov cx, 1000h
mov al, 20h
mov bl, 17h
int 10h
;end of blue
;start of gray top
mov ah, 09h
mov cx, 80d
mov al, 20h
mov bl, 87h
int 10h
;end of gray
;top bar
;end of top bar
;define mouse
mov ah, 01h
mov cx, 07h
int 10h
mov bl, 5h
mov cl, 5h
_mouser:
mov ah, 02h
mov dl, bl
mov dh, cl
int 10h
mov ah, 00h
int 16h
cmp al, 77h
je _up
cmp al, 73h
je _down
cmp al, 61h
je _left
cmp al, 64h
je _right
cmp al, 20h
je _click
jmp _mouser
_click:
mov ah, 0eh
mov al, 0b2h
int 10h
jmp _mouser
_up:
cmp cl, 0h
je _mouser
sub cl, 1h
jmp _mouser
_down:
cmp cl, 24d
je _mouser
add cl, 1h
jmp _mouser
_left:
cmp bl, 0h
je _mouser
sub bl, 1h
jmp _mouser
_right:
cmp bl, 79d
je _mouser
add bl, 1h
jmp _mouser
;----------------
times 510-($-$$) db 0
dw 0xAA55
我试过了
mov ah, eoh
mov al, 'F'
int 10h
问题是只能生成单个字符而不是字符串。
PC 的 ROM BIOS 提供了一组视频服务,通过中断 10h 调用,包括一些将字符打印到字符串的服务。可在 here.
中找到有关它们的综合文档看来你已经发现了服务0Eh,它在当前字符位置向屏幕写入一个字符,并向前移动字符位置。这将屏幕视为电传打字机 (TTY),并且非常容易在屏幕上获得输出。
(至少,它 看起来 就像您在尝试调用服务 0Eh。您的代码不正确。您有 mov ah, eoh
,这是不正确的. o
不是十六进制值,即使这是 0 的拼写错误,您也将半字节颠倒了。它应该是 mov ah, 0Eh
。)
如果你想打印一个字符串(多个字符),你基本上有两个选择:
您可以迭代调用类似 0Eh 的服务,每次将一个字符写入字符串。一个示例实现是:
mov ah, 0Eh ; service 0Eh: print char as TTY .PrintNextChar: mov al, BYTE PTR [si] ; get next character in string, pointed to by SI inc si ; increment pointer test al, al ; is character == 0 (end-of-string)? je .Done int 10h jmp .PrintNextChar .Done
这会打印
SI
指向的字符串中的字符,直到它到达 0(NUL 字符),这表示字符串的结尾(标准的 C 样式 NUL 终止字符串)。但是,这种一次打印一个字符的方法相对较慢。相反,人们通常更喜欢……
使用服务 1300h 或 1301h 一次打印整个字符串。区别在于服务 1301h 在打印字符串后使光标前进,而服务 1300h 不更改光标。否则,它们是相同的。
这些服务的参数记录在上面的 link 中;为方便起见转载于此:
AX
== 1300h/1301hBL
== 视频属性(文本模式下,指定前景色和背景色)BH
==视频页面(通常为0)CX
== 字符串长度DL
/DH
== column/row 字符串的起始位置ES:BP
== 字符串开头地址
显然这需要你事先知道字符串的长度,并将其作为参数传入
指向CX
寄存器中。该字符串由ES:BP
.在您的例子中,要打印 "FILE SYSTEM",您需要在包含该字符串的 DATA 段中声明一个字符数组,然后执行如下操作:
MyString DB "FILE SYSTEM"
mov ax, ds mov es, ax ; set ES == DS mov bp, MyString mov cx, 11 ; length of string (number of chars) mov bx, 07h ; foreground & background color (white on black) xor dx, dx ; starting position (top-left) mov ax, 1301h ; service 1301h: print string and update cursor int 10h