作为我的大学提供的一门课程,我遵循了一个教程,在http://3zanders.co.uk/2017/10/13/writing-a-bootloader/的Assembly中编写了16位的引导程序。这部分(第1部分)是到目前为止我应该做的所有事情。它基本上什么也没做,只是在屏幕上打印Hello World。
现在,请记住,这是我在Assembly中编写引导加载程序的唯一经验(这是我唯一的经验,期间)-现在,我应该将其扩展为一个菜单,用户可以从中选择一个菜单三个选项,然后相应地输出一个字符串ergo:
What is your favourite colour?
Press 1 for red
Press 2 for green
Press 3 for blue
[user input here]
Your favourite colour is [whatever corresponding colour].
我一直试图弄清楚从何处开始甚至到现在都已经结束了几个小时。我在Assembly中找到了选择菜单的一些示例,但问题是这些示例中的代码与本教程“教给我”的内容完全没有相似之处。我觉得我被迫从简单的将Hello World打印到屏幕,到制作根据用户输入打印不同输出的菜单,实现了飞跃。
这是我目前拥有的:
bits 16 ; tell NASM this is 16 bit code
org 0x7c00 ; tell NASM to start outputting stuff at offset 0x7c00
boot:
mov si,startText ; point si register to startText label memory location
mov ah,0x0e ; 0x0e means 'Write Character in TTY mode'
.loop:
lodsb
cmp al,51
je blue
cmp al,50
je green
cmp al,49
je red
or al,al ; is al == 0 ?
jz getInput ; if (al == 0) jump to halt label
int 0x10 ; runs BIOS interrupt 0x10 - Video Services
jmp .loop
getInput:
mov ah,00h
int 16h
red:
db "Your favourite colour is red",0
green:
db "Your favourite colour is green",0
blue:
db "Your favourite colour is blue",0
halt:
cli ; clear interrupt flag
hlt ; halt execution
startText:
db "",13,10
db "what is your favourite colour?",13,10
db "Press one for red",13,10
db "Press two for green",13,10
db "Press three for blue",13,10
db 13,10,0
times 510 - ($-$$) db 0 ; pad remaining 510 bytes with zeroes
dw 0xaa55 ; magic bootloader magic - marks this 512 byte sector bootable!
EDIT2: 我再次更新了上面的代码,尝试实现Sep和John告诉我的内容。我意识到这不是应该的样子,他们告诉我的某些事情没有实现,因为我还不知道如何实现。
我认为现在的问题是在显示初始startLabel之后它什么也没做。如果我按任何按钮,什么都不会改变。如果有人能指出我正确的方向,将不胜感激!
答案 0 :(得分:2)
1)您错过了@SepRoland的其中一项。您在.loop
中的代码会加载每个字符,如果它是 NOT ==0
,则会将其打印出来并重复循环。这意味着您有责任在数据中提供 0
:
db "",13,10
应为:
db 13,10,0
(请注意,””
是一个空字符串-无需打印,因此没有必要。)
在屏幕截图上看到竖线(带有左勾号)吗?实际上,这是计算机为以下mov
指令打印操作码!该垃圾输出是因为您的代码已停止打印数据,现在正在打印实际代码的字节。它将继续这样做,直到代码碰巧有一个0
为止-幸运的是,它恰好是下一个字节!上面的,0
将阻止所有这些情况。
2)好了,那么当它(最终)加载0
时会发生什么呢?根据您的评论,它将“跳转以暂停标签”。果然,代码然后跳至cli
和hlt
指令-并且计算机停止运行。无法执行下面添加的mov ah,00h
和int 16h
。
您需要将这些行移动到halt
标签之前-给它们加上自己的标签:getInput
或其他名称。然后将上面的jz halt
更改为jz getInput
:您希望它获得输入,而不是停止!
然后,您需要添加代码以打印出结果。您已经知道如何打印字符串:您只需要打印与以前不同的字符串-这些字符串需要新的标签和不同的标签。而且不要忘记最后的0
!
Sep为您提供了我所描述的大部分内容;您还没有将所有内容放在一起。您需要在头脑中区分计算机将执行的代码与计算机将处理的数据。对PC来说,它们只是数字,它将很高兴地执行代码,然后在遇到数据时开始执行数据-至少“高兴”直到数据使它变得愚蠢!
[编辑] 3)看来我们需要回到第一原理。假设您是计算机,拿起纸和笔,然后执行提供的说明。从最顶部开始:
si
,然后将startText
放入其中。那是第一个mov
。ah
,然后将0x0e
放入其中。那是第二个mov
。.loop
行-您稍后将需要。 lodsb
指令有点复杂。它使用si
查看内存,将该值加载到al
中(您需要一个新框),然后将其添加到si
中。由于si
持有startText
,因此startText
的第一个字节(13
-请记住,""
为空)被加载到al
中。将13
放在al
中,然后在+1
内附加si
。
偶然地:花点时间考虑一下您刚刚加载的内容。这是要打印的字节串的第一个字节。因此,很快您将需要调用“打印字符”例程。
现在,您正在将al
与51
进行比较-3
的ASCII值,就像Sep建议的那样。 (请注意,您实际上可以放'3'
而不是51
,以使代码更易于理解。请注意单引号(而不是双引号)。
嗯……这是怎么回事?您加载了要打印的字符-现在您要检查它是否是数字3?那不是在处理答案吗?在您要求计算机获得答案之前?在甚至打印出要求用户键入答案的字符串之前?
您已经添加了建议的所有代码-但完全在错误的位置。在尝试编写执行这些操作的代码之前,您需要先退一步并用高级的语言写下您想要程序执行的操作。
我建议您执行以下操作:
如果答案是三个预期答案之一,请写出结果。
否则,写下“意外答案”,然后返回到步骤2。
最重要的是,所有这些代码都必须以正确的顺序组合在一起,中间没有数据。该代码不仅必须存在,而且还必须按照您希望计算机执行它们的顺序显示。
您拥有的是:
3。如果答案是三个预期答案之一,则写出结果。
1。编写字符串,询问用户喜欢哪种颜色
2。从用户那里获取输入
5。数据
4。停止
5。更多数据
答案 1 :(得分:1)
这将为您指明正确的方向。
hello: db "What is your favourite colour?",13,10 db "Press 1 for red"13,10 db "Press 2 for green"13,10 db "Press 3 for blue"13,10 db "",13,10
首先通过正确地将其终止为零而不忽略逗号来更正此消息:
hello:
db "What is your favourite colour?",13,10
db "Press 1 for red",13,10
db "Press 2 for green",13,10
db "Press 3 for blue",13,10
db 13,10,0
要输入,可以在键盘int 16h上使用BIOS功能00h:
mov ah, 00h
int 16h
如果用户按下“ 1”,则AL
寄存器将保留值49。
如果用户按下“ 2”,则AL
寄存器将保留值50。
如果用户按下“ 3”,则AL
寄存器将保留值51。
现在显示常见消息“您喜欢的颜色是”。在执行此操作期间,必须注意不要意外修改AL
中的值。通过在代码的这一部分使用push ax
... pop ax
来保留它。
然后测试您从阅读键盘获得的值,以便选择一个指向适当消息的指针(SI
)。显示该消息(只是颜色的名称)。最后halt
。