Направи си сам стартиращ CD # 2

@keypress:
xor брадва, брадва; прочетете ключа
int 16h

тест al, al; проверете дали разширен ASCII или не
jz @extended_scancode

@extended_scancode:
cmp ах, 48h; стрелка нагоре
jz MoveCursorUp

cmp ах, 50h; стрелка надолу
jz MoveCursorDown
jmp @keypress
оттегляне

При натискане на бутоните "нагоре" и "надолу" се извикват съответните процедури за преместване на курсора MoveCursorUp и MoveCursorDown.

; Процедура за показване на един символ
; dh, dl - ред, колона; bl - цвят; ал - символ

Символ за печат:
пуша
xor bh, bh
mov ah, 02h; задайте курсора
int 10h
mov ах, 09h; и покажете символа в ал на екрана
mov cx, 1
int 10h
попа
оттегляне

Трябва да организираме движението на курсора нагоре и надолу, докато е необходимо да ограничим движението на курсора, така че да не излиза извън границите на менюто. За да определите позицията на курсора, създайте променлива MenuItemSelected, която ще се променя всеки път, когато позицията на курсора се променя и ще показва номера на избрания елемент от менюто (започвайки от нула). За целта ни трябват още две променливи (по принцип те могат да бъдат обявени за константи) - MenuFirstItemY - позицията на първия елемент от менюто и MenuLastItemY - позицията на последния елемент от менюто по оста Y. Разбира се, би било по-удобно е да се посочи позицията на първия елемент и броя на елементите от менюто, но това ще доведе до увеличаване на кода и не е разумно да се преизчислява MenuLastItemY всеки път. Ако координатата на курсора е равна на една от крайните позиции, тогава няма смисъл да се преначертава. Имайте предвид, че номерирането на редове и колони започва от нула, а не от една.

PositionXY dw 0000h; в тази променлива ще съхраняваме координатите на курсора
MenuItemSelected db 00h
MenuFirstItemY db 00h
MenuLastItemY db 00h

MoveCursorUp:
пуша
mov dx, [PositionXY]
cmp dh, [MenuFirstItemY]; проверете дали курсорът е в крайно положение
jz @ 1; ако да, тогава преминете към края на процедурата
mov бл, 2; зелен цвят
mov al, “; изтрийте стария курсор, като напишете интервал на негово място
обадете се PrintSymbol
dec dh; намалете координатата Y на курсора, като по този начин я издигнете нагоре
mov al, '>'; в символ на курсора
обадете се PrintSymbol
mov [PositionXY], dx; запишете новите координати на курсора
sub dh, [MenuFirstItemY]; изчислете броя на избрания елемент от менюто
mov [MenuItemSelected], dh
@one:
попа
jmp @keypress

; При тази процедура всичко е същото, само координатата Y на курсора се увеличава с
мерна единица

MoveCursorDown:
пуша
mov dx, [PositionXY]
cmp dh, [MenuLastItemY]
jz @ 2
mov bl, 2
mov al, ’’
обадете се PrintSymbol
вкл. dh; увеличете координатата Y на курсора, като по този начин я намалите надолу
mov al, '>'
обадете се PrintSymbol
mov [PositionXY], dx
sub dh, [MenuFirstItemY]
mov [MenuItemSelected], dh
@ 2:
попа
jmp @keypress

Е, сега вече има какво да видим. За това се нуждаем от емулатора на Bochs. Ако не можете да го намерите, можете да използвате програмата RawwriteWin
(http://uranus.it.swin.edu.au/

jn/linux) или подобен, който може да напише изображение на дискета. Такива програми са лесни за намиране в Интернет.
Нека създадем файл main.asm.

Основна_програма:
обадете се на DrawInterface

mov брадва, 0303h; задайте началната позиция на курсора (X = 3, Y = 3)
mov [PositionXY], брадва

mov [MenuFirstItemY], 2; задайте областта, в която курсорът може да се движи
mov [MenuLastItemY], 6

обадете се на MoveCursorUp; за да нарисувате курсора, поставете го
единица отдолу

обадете се на KeybInput
оттегляне

Въпреки че има призив към процедурите, отговорни за дизайна и клавиатурата и
инициализация на променливи, отговорни за курсора на менюто. Нека не забравяме да свържем съответните файлове:

включва „graphics.inc“
включва 'keyb.inc'

Нека създадем файл make.bat. Лозунгът включва всъщност обединява два файла в един, така че е достатъчно да напишете файла, който започва всичко:

fasm bootsect.asm image.bin

Като стартираме този .bat, ще получим готовия файл с изображение image.bin. Би било хубаво да се уверите, че прозорецът не се затваря веднага, защото ако крайният файл не бъде създаден, ще се покаже грешка, така че в края
bat'nik е удобен за писане

За да започнете да емулирате Bochs, трябва да конфигурирате - задайте параметрите на емулираната машина. За това се използва конфигурационният файл. Създайте корекции на файл със следното съдържание
(това е за версия 2.1, но практически същото в други версии, подробна информация може да се намери в документацията на Bochs
http://bochs.sf.net/docs-html
и http://bochs.sf.net/doc/docbook/index.html):

floppya: 1_44 = диск \… \… \ image.bin, статус = вмъкнат
floppyb: 1_44 = a:, статус = изхвърлен
romimage: файл = BIOS-bochs-най-новите, адрес = 0xf0000
vgaromimage: VGABIOS-elpin-2.40
мега: 32
boot: флопи
vga_update_interval: 30000
keyboard_serial_delay: 250

floppy_command_delay: 5000
ips: 500000
мишка: активирано = 0
private_colormap: активирано = 0
i440fxsupport: активирано = 0
време0: 0
newharddrivesupport: активирано = 1
дневник: -
паника: действие = питане
грешка: действие = доклад
информация: действие = доклад
отстраняване на грешки: действие = игнориране

Този файл трябва да се намира в папката, където
Бохс. След последния ред трябва да има преход към следващия
линия, в противен случай Bochs започва да крещи и няма да започне.
Задвижване B: (реално задвижване) може да се включи чрез натискане на съответната икона в Bochs и поставяне на отметка.

След това нека създадем файл run.bat:

cd диск \ папка, в която е инсталиран Bochs \
bochs -q -f корекции

Bochs могат да се зареждат и от истинска дискета, за това трябва да напишете (за мястото на първия ред)

floppya: 1_44 = A:, статус = вмъкнат

б) При липса на Bochs или друг емулатор

При липса на емулатор ще трябва да направите всичко ръчно. Изображение се записва на дискета (не е задължително форматирано) с помощта на някаква програма (например Rawwrite или RawwriteWin), след което компютърът се рестартира и BIOS е настроен да стартира от дискетата. Ако използвате RawwriteWin, можете да създадете .bat файл:

rawwritewin —write —copies 1 —drive 0 image.bin

В този случай run.bat не е необходим.

На истинска машина, разбира се, е по-надежден, тъй като емулаторът все още е емулатор. Няколко пъти попаднах на ситуация, когато програмата напълно отказа да работи нормално в емулатора, въпреки че работеше добре на истинска машина (това не важи за програмата, която пишем сега, тя работеше и там, и там). Но на истинска машина няма такива възможности за отстраняване на грешки (ако са налични на истинска машина и при липса на операционна система 🙂), а когато се използва емулатор, компютърът не трябва постоянно да се рестартира.

Стартирайте run.bat и се насладете на резултата 😉 Въпреки това, при липса на емулатор, удоволствието ще бъде развалено донякъде от необходимостта да рестартирате компютъра.

Курсорът се движи, но засега нищо не може да бъде избрано, затова добавяме обработка към натискане на клавиша Enter във файла keyb.bat.
Нека добавим проверка за enter към безкраен цикъл:

cmp al, 0dh; въведете
jz @key_enter

В този манипулатор ще видим какво трябва да се направи в зависимост от броя на елемента от менюто.

; обработка Въведете хит
@key_enter:
cmp [MenuItemSelected], 0
jz BootFromCD

cmp [MenuItemSelected], 1
jz BootFromFloppy

cmp [MenuItemSelected], 2
jz BootFromHDA1

cmp [MenuItemSelected], 3
jz BootFromHDB1

cmp [MenuItemSelected], 4
jz @ MenuItem_Int19h
jmp @keypress

; Бързо рестартиране (използвайки int19h)
@ MenuItem_Int19h:
int 19h; Горещо зареждане
jmp @keypress

За „горещо“ рестартиране (при което BIOS проверява отново всичко, от което може да се стартира, без да рестартира компютъра напълно), трябва да извикате прекъсването int 19h без никакви параметри.

Сега нека създадем файл boot.inc, в който описваме съответните процедури. Общият код за четене за всички дискове е един и същ (идва след маркера @boot_system), тъй като bootsector винаги е на едно място: глава 0, цилиндър 0, сектор 1. След стартиране от CD-ROM устройството ще стане диск B, изображението ще бъде диск А. И така, устройства: dl = 01h - устройство B, dl = 80h - Primary Master, dl = 81h - Primary Slave. След опит за четене има проверка за грешки. Ако те не са там, тогава ще проверим наличието на 55AAh подпис и ако той е налице, ще прехвърлим контрола към заредения сектор за зареждане.

BootFromFloppy:
mov dl, 01h
jmp @boot_system

BootFromHDA1:
mov dl, 80h
jmp @boot_system

BootFromHDB1:
mov dl, 81h

@boot_system:
натиснете 0000
поп ес
mov bx, 7c00h

mov ах, 02ч
mov cl, 01h
mov al, 01h
mov dh, 00h
mov ch, 00h
int 13h
jc @read_error; проверете дали има грешки при четене

mov bx, 7DFEh
mov брадва, [bx]
cmp брадва, 55AAh
jz @invalid_signature

В случай на грешка, на екрана ще се покажат нецензурни известия. За целта ще напишем спомагателна процедура за показване на линия и за да не посочваме всеки път координатите на курсора в dx, цвят в bl и т.н., ще напишем помощна процедура. Тази процедура ще покаже низ в следния формат: X, Y, цвят, 'текст', 0

PrintStrF:
пуша
mov dx, [si]
добавете si, 2
mov bl, [si]
вкл
@put_symb:
lodsb
cmp al, 0
jz @end_of_string
обадете се PrintSymbol
вкл
jmp @put_symb
@end_of_string:
попа
оттегляне

Нека създадем файл text.inc, в който ще съхраним всички етикети и не забравяйте да го свържете:

За да избегнем проблеми с това, че част от стария надпис остава на екрана, ще изведем всички надписи с еднаква дължина с интервали.

FloppyDriveReadError db 5,9,4, ‘Грешка при четене на Floppy Drive B:’, 0
HDA1ReadEror db 5,9,4, „Грешка при четене на основния главен твърд диск“, 0
HDB1ReadEror db 5,9,4, „Грешка при четене на основен подчинен твърд диск“, 0
InvalidSignature db 5,9,4, 'Невалиден подпис за зареждане. Продължаване все пак (г/н)? ', 0

Нека покажем различни съобщения, в зависимост от грешката (boot.inc):

@read_error:
lea si, [FloppyDriveReadError]
cmp dl, 01h
jz @PrintError

Lea Si, [HDA1ReadEror]
cmp dl, 80h
jz @PrintError

@PrintError:
обадете се PrintStrF
jmp @keypress

@invalid_signature:
lea si, [InvalidSignature]
обадете се PrintStrF
xor брадва, брадва; прочетете ключа
int 16h
cmp al, 'Y'; ако Y след това продължете
jz @boot_anyway
jmp @keypress

Сега забавлението започва - зареждане от дискетата, на която е написана нашата програма. В края на краищата няма нормален сектор за зареждане, където би трябвало да бъде. Ако някой има желание, тук можете сами да напишете буутлоудър за DOS. И ще го направим по-лесно - ще използваме готов сектор за зареждане. За да го получим, нека създадем нормална дискета за стартиране, като стартираме формат dos с параметъра \ s:

За съжаление това работи без проблеми само за потребителите на Windows 98 и DOS и това
едва ли някой го използва сега. Потребителите на NT ще се сблъскат с проблем - къде да получат дос. Е, със сигурност имате някакъв стартиращ компактдиск и ето го (ако не е лицензиран Windows или
Linux) dos е. Не е лесно да го извадите от там - той е под формата на изображение или е скрит някъде в началото на диска и не се вижда като файл и не е необходимо. Трябва само да стартирате от този диск и да форматирате дискетата, както е описано по-горе.

Сега секторът за зареждане трябва да бъде премахнат. За да направите това, можете да използвате Norton Disk Editor или друга подобна програма. Можете сами да напишете програмата за извличане на сектора за зареждане. Нека просто прочетем първия сектор на дискетата (както направихме по-горе) и да го запазим с помощта на DOS функции. Използването на DOS функции не означава неговата неработоспособност под Windows - тя работи под всяка версия.