use16
org 7c00h
start:
mov ax, cs ; читаем сегмент кода в регистр ax
mov ds, ax ; из регистра ax переписываем адрес сегмента в регистр сегмента данных dx
mov ss, ax ; из регистра ax переписываем адрес сегмента в регистр сегмента стека ss
mov es, ax ; из регистра ax переписываем адрес сегмента в дополнительный регистр сегмента данных es
mov sp, start ; stack pointer
mov [disk_start], dl ; обычно при запуске системы номер диска, с которого проведён запуск передаётся в dl
mov bh, 0 ; видео страница 0
mov dl, [x] ; Координата X курсора
mov dh, [y] ; Координата Y курсора
mov ah, 02h ; сервис установить курсор
int 10h ; вызов сервиса
mov si, msg_start ; сообщаем, что загрузчик загружен
call print_string
; Выведем сообщение — с какого диска стартовали
inc [y] ;y = y + 1 перепрыгиваем на следующую строку
mov dh, [y]
mov ah, 02h ; сервис — установить курсор
int 10h
mov si, msg_disk_start ; информация — с какого номера диска стартовали
call print_string
mov al, [disk_start]
call WRITE_HEX_BYTE ; выводим байт код диска
; Выведем сообщение — в каком сегменте оперативной памяти работаем
inc [y] ;y = y + 1 перепрыгиваем на следующую строку
mov dh, [y]
int 10h ; установка курсора. В ah сохранился код функции 02h
mov si, msg_segment
call print_string
push ax ; сохраним номер функции установки курсора
mov ax, cs ; выводим сегмент загрузки (просто для информации)
call WRITE_HEX_DWORD ;
pop ax ; восстановим номер функции установки курсора
; зафиксируем сообщения перед загрузкой второго сектора
mov bh, 0
inc [y] ; Y + 1
mov dh, [y]
int 10h ; установка курсора. В ah сохранился код функции 02h
mov si, msg_press_key ; адрес строки — нажмите клавишу
call print_string
;mov ah, 01h ; поверка наличии символа (для 84-клавишной клавиатуры). Выход: если ZF=0, то AH=скан-код BIOS, AL=символ ASCII
mov ah, 00h ; читать (ожидать) следующую нажатую клавишу. AL=ASCII символ
int 16h ; вызов функции ожидания нажатия клавиши
; загружаем второй сектор
mov ah, 02h ; функция читать секторы int 13h
mov dl, [disk_start] ; номер диска (0=диск A…; 80h=тв.диск 0, 81h=тв.диск 1 …)
mov dh, 0 ; номер головки чтения
mov ch, 0 ; номер дорожки (цилиндра) от 0 до n
mov cl, 2 ; номер сектора, 1 — n
mov al, 1 ; число секторов (в сумме не больше чем один цилиндр
mov bx, 8000h ; адрес = 32768. Посчитал как 7C00h + 512 (загруженный сектор) + 512 (резерв), es уже равен cs (буфер ES:BX)
int 13h ; вызываем функцию. Если CF=1(флаг переноса), то ошибка и в ah — код ошибки
jc .ERROR ; если ошибка то переходим и показываем её код
mov bh, 0 ; выводим сообщение, что сектор загружен
inc [y] ; Y + 1, новая строка
mov dl, [x]
mov dh, [y]
mov ah, 02h ; устанавливаем курсор
int 10h
mov si, msg_load_complete ; адрес строки сообщения
call print_string ; выводим строку
; зафиксируем сообщения перед переходом на загруженный сектор
inc [y] ; Y + 1
mov dh, [y]
int 10h ; установка курсора
mov si, msg_press_key ; строка — нажмите клавишу
call print_string
mov ah, 00h ; функция ожидания нажатия клавиши
int 16h ; вызов функции
jmp 8000h ; переходим на адрес загруженного сектора (в пределах сегмента, ближний переход
; выводим об ошибке загрузки сектора, al — код ошибки
.ERROR:
mov bx, 0
inc [y] ; Y + 1
mov dl, [x]
mov dh, [y]
mov ah, 02h ; установка курсора
int 10h ; устанавливаем
mov si, msg_err_load ; строка сообщения об ошибки
call print_string
call WRITE_HEX_BYTE ; вывод байта
jmp $ ; зацикливаемся
; Подпрограммы
; вывод строки на экран. Регистр SI — входной, адрес выводимой строки
print_string:
push ax
push bx
push si
cld ; направление для строковых данных, машинный код FC. Флаг DF = 0. Указатель SI = +1
mov ah, 0Eh ; писать символ в активную видео страницу. AL — записываемый символ, BL — цвет переднего плана
mov bl, 0
.loops:
lodsb ; считать байт по адресу DS:SI в AL, машинный код AC
test al, al ; проверяем конец строки
jz .return
int 10h ; выводим символ
jmp .loops
.return:
pop si
pop bx
pop ax
ret ; возврат из процедуры. Машинный код C3 — близкий возврат, в пределах сегмента. Машинный код CB — дальний возврат
; вывод на экран слова (16-бит), регистр AX — входной
WRITE_HEX_DWORD:
push dx
mov dl, ah ; старший байт
call WRITE_HEX_BYTE ; передаём на подпрограмму вывода байта
mov dl, al ; младший байт
call WRITE_HEX_BYTE ; передаём на подпрограмму вывода байта
pop dx
ret
; вывод на экран байта (8-бит), регистр DL — входной
WRITE_HEX_BYTE:
push ax
push cx
push dx
mov dh, dl ; сохраняем байт, для вывода младших 4-бит
mov cx, 4 ; для сдвига на 4 бита
shr dl, cl ; сдвигаем старшие 4-бита в право
call WRITE_HEX_DIGIT ; выводим на экран старшие 4-бита
mov dl, dh ; возвращаем байт для обработки младших 4-бит
and dl, 0Fh ; сбрасываем старшие 4-бита, чтобы остались только младшие 4-бита
call WRITE_HEX_DIGIT ; выводим на экран младшие 4-бита
pop dx
pop cx
pop ax
ret
; перевод 4 бита в шестнадцатеричный символ. Регистр DL входной — 4 бита для перевода в символ ASCII
WRITE_HEX_DIGIT:
push dx
cmp dl, 10
jae .HEX_LETTER ; jae — переход если больше или равно, если флаг CF = 0 то переход
add dl, «0» ; складываем dl с кодом ASCII символа нуль (код 48)
jmp .WRITE_DIGIT
.HEX_LETTER:
add dl, «A» — 10 ; складываем dl с кодом ASCCI символа(A = 65) — 10, так как числа от 10 до 16 уже лежат dl
.WRITE_DIGIT:
call WRITE_HAR ; вывод символа на экран
pop dx
ret
; вывод символа на экран, регистр dl — входной
WRITE_HAR:
push ax
push bx
mov ah, 0eh ; функция — писать символ на активную видео страницу (эмуляция телетайпа)
mov al, dl ; al — выводимый символ
mov bh, 0 ; на всякий случай, видео страница=0
mov bl, 0 ; bl — цвет переднего плана (для графических режимов)
int 10h ; вызов функции
pop bx
pop ax
ret
data_text:
msg_start db «Bootloader start v1.0»,0 ; db — define byte — определить байт
msg_segment db «Loaded into segment #», 0
msg_press_key db «Press key…», 0
msg_load_complete db «Loading is complete», 0
msg_err_load db «Loading is error #», 0
msg_disk_start db «Disk start #», 0
data_v:
; в оперативной памяти храним координаты курсора X и Y
x db 0 ; Координата X
y db 0 ; Координата Y
disk_start db 0 ; здесь диск с которого стартовали
size: dw $ — start ; здесь размер кода вместе с данными
finish:
times 0x1fe — finish + start db 0 ; заполняем нулями оставшееся адресное пространство
signatura:
db 55h, 0xAA ; сигнатура загрузочного сектора
Ты прям с головой в программирование ушёл , а паяльник не продал ?
Нет, не продал 🙂 . Как раз керамические нагреватели пришли недавно для паяльника. Вчера же и поменял его.
Хорошо когда всё по полочкам разложено…