Чтение ввода с использованием ассемблера (16-битный загрузчик) - PullRequest
0 голосов
/ 07 января 2019

В качестве курса, предложенного моим университетом, я следовал учебному пособию по написанию 16-разрядного загрузчика на ассемблере со значением http://3zanders.co.uk/2017/10/13/writing-a-bootloader/. Эта часть (часть 1) - это все, что я должен был сделать до сих пор. По сути, он ничего не делает, кроме вывода Hello World на экран.

Теперь, имея в виду, что это единственный опыт, который я имею при написании загрузчиков в Assembly (это единственный опыт, который у меня есть, точка) - теперь я должен расширить это в меню, где пользователь может выбрать один из три варианта, а затем выведите соответствующую строку, например:

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].

Я пытался понять, с чего начать часами. Я нашел несколько примеров меню выбора в Ассемблере, но проблема в том, что код в этих примерах не имеет никакого сходства с тем, чему этот урок здесь «научил» меня. Я чувствую, что меня заставляют совершить прыжок от простой печати 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: Я еще раз обновил приведенный выше код, пытаясь реализовать то, что сказали мне и Сеп, и Джон. Я понимаю, что это не так, как должно быть, и некоторые вещи, которые мне сказали, не реализованы, потому что я пока не понимаю, как это сделать.

Проблема сейчас, я думаю, в том, что она ничего не делает после показа начальной метки startLabel. Ничего не меняется, если я нажимаю любую кнопку. Если кто-нибудь может направить меня дальше в правильном направлении, это будет высоко ценится!

enter image description here

Ответы [ 2 ]

0 голосов
/ 08 января 2019

1) Вы пропустили один из пунктов @ SepRoland. Ваш код в .loop загружает каждый отдельный символ, и если он НЕ ==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 каждый раз!

Сеп дал вам большую часть того, что я описал; Вы просто еще не соединили все это. Вы должны различать в уме код, который компьютер будет выполнять, и данные, которые он будет обрабатывать. Для ПК все они просто числа, и он вполне с радостью выполнит код, а затем начнет выполнять данные, если натолкнется на него - по крайней мере, «счастлив», пока данные не заставят его сделать что-то глупое!

[EDIT] 3) Похоже, нам нужно вернуться к первым принципам. Представьте, что вы - компьютер, возьмите лист бумаги и ручку и выполните предоставленные вами инструкции. Начните с самого верха:

  • Нарисуйте коробку, обозначьте ее si и поместите startText внутри нее. Это первый mov.
  • Нарисуйте еще одну рамку, пометьте ее ah и поместите 0x0e в нее. Это второй mov.
  • Обратите внимание на строку .loop - она ​​понадобится вам позже.
  • Инструкция lodsb немного сложна. Он использует si для просмотра памяти, загружает это значение в al (вам понадобится новое поле), а затем добавляет его в si. Поскольку si содержит startText, первый байт в startText (13 - помните, "" пуст) загружен в al. Поместите 13 в al и добавьте +1 в si.

    Между прочим: найдите время, чтобы подумать о том, что вы только что загрузили. Это первый байт строки байтов, которую вы хотите распечатать. Поэтому довольно скоро вам нужно будет вызвать процедуру «печать символа».

  • Теперь вы сравниваете al с 51 - значение ASCII для 3, как предложил Sep. (Обратите внимание, что вы можете на самом деле поставить '3' вместо 51, чтобы сделать код более простым для понимания. Обратите внимание на одинарные (не двойные) кавычки.)

    Ммм ... Что здесь происходит? Вы загрузили символ для печати - и теперь вы проверяете, является ли он номером 3? Разве это не обработка ответа? Прежде чем вы попросили компьютер даже получить ответ? Еще до того, как вы распечатали строку, которая просит пользователя набрать ответ?

Вы добавили код, который был предложен правильно, но совершенно не в том месте. Вам нужно отступить назад и записать то, что вы хотите, чтобы программа делала словами высокого уровня, прежде чем пытаться написать код, выполняющий эти действия.

Я предлагаю тебе хотетьсделать следующее:

  1. Запишите строку с вопросом, какой цвет предпочитает пользователь
  2. Получить ввод от пользователя
  3. Если ответ является одним из трех ожидаемых ответов, запишите результат.

    В противном случае запишите «Неожиданный ответ» и вернитесь к шагу 2.

  4. Halt
  5. Данные для распечатки

Самое важное, что весь этот код должен быть вместе в правильном порядке, без данных в середине. Код должен присутствовать не только в той последовательности, в которой вы хотите, чтобы компьютер их выполнял.

Что у вас есть:

3. Если ответ является одним из трех ожидаемых ответов, запишите результат.

1.Запишите строку, спрашивая, какой цвет предпочитает пользователь

2.Получить ввод от пользователя

5.Data

4.Halt

5.Больше данных

0 голосов
/ 08 января 2019

Это укажет вам правильное направление.

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

Для ввода вы можете использовать функцию BIOS 00h на клавиатуре int 16h:

mov ah, 00h
int 16h

Если пользователь нажимает «1», регистр AL будет содержать значение 49.
Если пользователь нажимает «2», регистр AL будет содержать значение 50.
Если пользователь нажимает «3», регистр AL будет содержать значение 51.

Теперь отобразите общее сообщение «Ваш любимый цвет». Во время этого действия вы должны следить за тем, чтобы случайно не изменить значение в AL. Сохраните его, используя push ax ... pop ax вокруг этой части вашего кода.

Затем проверьте значения, полученные при чтении с клавиатуры, чтобы выбрать указатель (SI) на подходящее сообщение. Отобразите это сообщение (только название цвета). Наконец halt.

...