x86 16-Bit Real Mode – Register & Sprungbefehle

1. Allgemeine Register (General Purpose)

RegisterBedeutungBemerkung
AXAccumulatorArithmetische Operationen
BXBaseBasisadresse
CXCounterSchleifen (LOOP)
DXDataMultiplikation/Division, I/O

AX, BX, CX, DX können in 8-Bit Register unterteilt werden: AH/AL, BH/BL, CH/CL, DH/DL

2. Segmentregister

RegisterBedeutung
CSCode Segment
DSData Segment
SSStack Segment
ESExtra Segment

3. Zeiger- und Indexregister

RegisterBedeutung
SPStack Pointer
BPBase Pointer
SISource Index
DIDestination Index

4. Status- und Steuerregister

RegisterBedeutung
IPInstruction Pointer
FLAGSStatusbits: Zero, Carry, Sign, Overflow, etc.

5. Wichtige Befehle

BefehlBeschreibungBeispiel
INCInkrementiert Register oder SpeicherINC AX → AX+1
DECDekrementiert Register oder SpeicherDEC CX → CX-1
MOVKopiert DatenMOV AX,BX
XORBitweises XORXOR AX,AX → AX=0
PUSHWert auf Stack legenPUSH AX
POPWert vom Stack holenPOP AX
CALLFunktionsaufrufCALL MyFunc
RETRückkehr von FunktionRET

6. Beispiel

MOV AX, 0005h   ; AX = 5
INC AX          ; AX = 6
DEC AX          ; AX = 5
    

7. Interaktive CMP & Sprungbefehle

Du kannst AX und BX verändern und die Auswirkungen auf Flags und Sprungbefehle sehen.

AX = 0005h | BX = 0005h

Vergleich & Flags

CMP AX, BX setzt Flags, ohne Register zu verändern:

Sprungbefehle

BefehlBedeutungBedingung
JE / JZJump if Equal / ZeroZF = 1
JNE / JNZJump if Not EqualZF = 0
JGJump if Greater (signed)ZF = 0, SF = OF
JLJump if Less (signed)SF ≠ OF
JAJump if Above (unsigned)CF = 0, ZF = 0
JBJump if Below (unsigned)CF = 1
JMPUnbedingter SprungImmer


MS-DOS / BIOS Interrupts Referenz

Textausgabe & Texteingabe

INT 10h / INT 21h
InterruptFunktionÜbergebene RegisterZurückgegebene Register
INT 10hZeichen ausgeben (Teletype)AH=0Eh, AL=ASCII, BH=SeiteKeine
INT 10hCursorposition setzenAH=02h, BH=Seite, DH=Zeile, DL=SpalteKeine
INT 10hTextmodus ändernAH=00h, AL=ModusKeine
INT 21hZeichen einlesen (mit Echo)AH=01hAL=Eingelesenes Zeichen
INT 21hString einlesenAH=0Ah, DS:DX=PufferAL=Anzahl gelesener Zeichen

Dateioperationen

INT 21h
InterruptFunktionÜbergebene RegisterZurückgegebene Register
INT 21hDatei öffnenAH=3Dh, AL=Zugriffsmodus, DS:DX=PfadnameAX=Handle oder CF=Fehler
INT 21hDatei schließenAH=3Eh, BX=HandleAX=0 bei Erfolg, CF=1 bei Fehler
INT 21hDatei lesenAH=3Fh, BX=Handle, CX=Anzahl Bytes, DS:DX=PufferAX=gelesene Bytes oder CF=Fehler
INT 21hDatei schreibenAH=40h, BX=Handle, CX=Anzahl Bytes, DS:DX=PufferAX=geschriebene Bytes oder CF=Fehler
INT 21hDatei erstellenAH=3Ch, CX=Attribute, DS:DX=PfadnameAX=Handle oder CF=Fehler
INT 21hDatei löschenAH=41h, DS:DX=PfadnameCF=0 bei Erfolg, CF=1 Fehlercode in AX

Sektoroperationen

INT 13h
InterruptFunktionÜbergebene RegisterZurückgegebene Register
INT 13hSektor lesenAH=02h, AL=Anzahl, CH=Zylinder, CL=Sektor, DH=Kopf, DL=Laufwerk, ES:BX=PufferCF=0 Erfolg, AH=Fehlercode
INT 13hSektor schreibenAH=03h, AL=Anzahl, CH=Zylinder, CL=Sektor, DH=Kopf, DL=Laufwerk, ES:BX=PufferCF=0 Erfolg, AH=Fehlercode
INT 13hLaufwerksparameter abrufenAH=08h, DL=LaufwerkAH=Sektoren/Kopf/Zylinder etc.

VGA & Grafik

INT 10h
InterruptFunktionÜbergebene RegisterZurückgegebene Register
INT 10hGrafikmodus setzenAH=00h, AL=ModusKeine
INT 10hPixel setzenAH=0Ch, AL=Farbe, CX=X, DX=Y, BH=SeiteKeine
INT 10hPixel lesenAH=0Dh, CX=X, DX=Y, BH=SeiteAL=Farbe
INT 10hPalette setzenAH=10h, AL=10h, BL=Farbe, BH=Seite, CX=PaletteKeine

Tastatur

INT 16h
InterruptFunktionÜbergebene RegisterZurückgegebene Register
INT 16hZeichen einlesen (Block)AH=00hAX=ScanCode+ASCII
INT 16hZeichen prüfen (nicht blockierend)AH=01hZF=0 Zeichen vorhanden, AX=ScanCode+ASCII

Maus

INT 33h
InterruptFunktionÜbergebene RegisterZurückgegebene Register
INT 33hMaustreiber initialisierenAX=0000hAX=0Fh=Anzahl Buttons
INT 33hCursorposition setzenAX=0004h, CX=X, DX=YKeine
INT 33hMaustastenstatusAX=0003hBX=Buttons, CX=X, DX=Y

Timer & RTC

INT 1Ah
InterruptFunktionÜbergebene RegisterZurückgegebene Register
INT 1AhSystemzeit abfragenAH=00hCX=Stunden/Minuten, DX=Sekunden/10ms
INT 1AhTimer-Dienst einrichtenAH=01hKeine

Drucker

INT 17h
InterruptFunktionÜbergebene RegisterZurückgegebene Register
INT 17hZeichen ausgebenAL=ASCIIKeine

Sound (PC Speaker)

INT 10h / Portzugriff
InterruptFunktionÜbergebene RegisterZurückgegebene Register
Port 42h/61hTöne ausgebenAX/FrequenzKeine

Speicherabfrage

INT 12h / INT 21h
InterruptFunktionÜbergebene RegisterZurückgegebene Register
INT 12hBasis-SpeichergrößeKeineAX=Größe in KB
INT 21hFreier Speicher für ProgrammAH=48h, BX=Größe in ParagraphenAX=Segmentadresse, CF=Fehler

Programm beenden

INT 20h / INT 21h
InterruptFunktionÜbergebene RegisterZurückgegebene Register
INT 20hProgramm beendenKeineKehrt zu DOS zurück
INT 21hProgramm beenden mit RückgabewertAH=4Ch, AL=RückgabewertKehrt zu DOS zurück


Beispielcode 1 - Einfaches Hello World

BITS 16
ORG 100h                            ; .COM Programm startet bei 0x100

start:
    mov dx,msg                      ; Zeiger auf Nachricht
    mov ah,09h                      ; DOS Funktion - String ausgeben
    int 21h                         ; DOS Interrupt

    mov ah,4Ch                      ; DOS Funktion - Programm beenden
    int 21h

msg db 'Hello World from DOS!', '$' ; '$' = String-Ende für DOS

Beispielcode 2 - Hello World

BITS 16
ORG 100h

start:
    mov si, text
    xor cx, cx
lenloop:
    lodsb
    cmp al, 0
    je  lendone
    inc cx
    jmp lenloop
lendone:
    mov ax, cx
    shl ax, 1        ; AX = 2 * Länge
    mov bx, ax
    mov ax, 160
    sub ax, bx
    mov dx, ax       ; DX = Anzahl Bytes, um vom Ende der geschriebenen Zeichen

    mov ax, 0B800h
    mov es, ax
    xor di, di       ; Start = Zeile 0, Spalte 0

    mov cx, 10       ; Anzahl Zeilen
    mov bl, 1        ; Startfarbe (1..F)

printline:
    mov si, text

printchar:
    lodsb
    cmp al, 0
    je  endline
    mov [es:di], al  ; Zeichen
    inc di
    mov [es:di], bl  ; Attribut / Farbe
    inc di
    jmp printchar

endline:
    add di, dx       ; zum nächsten Zeilenanfang springen
    inc bl
    cmp bl, 0Fh
    jbe skipreset
    mov bl, 1
skipreset:
    loop printline

    mov ax, 4C00h
    int 21h

text db 'Hello World !!!', 0


Beispielcode 3 - Hello World

BITS 16
ORG 100h

start:
    mov ax, 0B800h         ; Textspeicher Adresse für 80x25 Textmodus
    mov es, ax
    xor di, di             ; Start bei Position 0
    mov si, text
    mov bl, 1              ; Startfarbe (1 = blau auf schwarz)

printloop:
    lodsb
    cmp al, 0
    je done

    mov [es:di], al        ; Zeichen schreiben
    inc di
    mov [es:di], bl        ; Farbbyte schreiben
    inc di

    inc bl                 ; Farbe wechseln
    cmp bl, 0Fh
    jbe continue
    mov bl, 1
continue:
    jmp printloop

done:
    ret

text db 'Hello World !!!', 0

Beispielcode 4 - Hello World

BITS 16
ORG 100h

start:
    mov ax, 0003h          ; 80x25 Textmodus sicher aktivieren
    int 10h

    mov si, text           ; Zeiger auf String
    mov bl, 1              ; Startfarbe (1 = blau auf schwarz)
    mov dh, 10             ; Zeile = 10
    mov dl, 10             ; Spalte = 10
    mov bh, 0              ; Seite 0

nextchar:
    lodsb
    test al, al
    jz waitkey

    mov ah, 02h
    int 10h

    mov ah, 09h
    mov cx, 1
    int 10h

    inc dl                 ; Spalte ++
    inc bl                 ; Farbe ++
    cmp bl, 0Fh
    jbe short nextchar
    mov bl, 1
    jmp short nextchar

waitkey:
    mov ah, 00h
    int 16h                ; Warten auf Taste

    mov ax, 4C00h
    int 21h

text db 'Hello World !!!', 0

Beispielcode 5 - Input Texteingabe

BITS 16
ORG 100h                     ; .COM-Programme starten immer bei Adresse 0100h

start:
    mov dx, msg_eingabe      ; Adresse des Textes in DX laden
    mov ah, 09h              ; DOS Funktion 09h = String ausgeben ($-terminiert)
    int 21h                  ; DOS aufrufen für Text wird angezeigt

    mov dx, buffer           ; Adresse des Eingabepuffers
    mov ah, 0Ah              ; DOS Funktion 0Ah = Zeileneingabe
    int 21h                  ; DOS liest Text bis ENTER gedrückt wird der Text landet in "buffer"

    mov dx, newline          ; Zeilenumbruch String in DX
    mov ah, 09h
    int 21h

    mov dx, msg_ausgabe
    mov ah, 09h
    int 21h

    mov si, buffer + 2       ; SI zeigt auf den ersten Buchstaben
    mov cl, [buffer + 1]     ; CL = tatsächliche Länge der Eingabe
    add si, cx               ; SI = Ende des Textes
    mov byte [si], '$'       ; Setze '$' als Endzeichen

    mov dx, buffer + 2       ; Zeiger auf Textanfang
    mov ah, 09h
    int 21h

    mov ax, 4C00h            ; DOS-Funktion 4Ch = Programmende
    int 21h

msg_eingabe db 'Bitte Text eingeben: $'
msg_ausgabe db 'Du hast eingegeben: $'
newline     db 13,10,'$'

buffer db 255                ; Maximale Eingabelänge = 255 Zeichen
       db 0                  ; Tatsächliche Eingabelänge (wird von DOS gesetzt)
       times 255 db 0        ; Speicher für Text


Beispielcode 6 - VGA Rechteck Zeichen

org 100h

start:
    mov AH,0
    mov AL,12h
    int 10h

    mov AH,0Bh
    mov BX,0           ; 0 = Schwarz
    int 10h

    ; Obere Linie
    mov word [y_beg],100
    mov word [x_beg],100
    mov word [y_end],100
    mov word [x_end],200
    call linie

    ; Untere Linie
    mov word [y_beg],200
    mov word [x_beg],100
    mov word [y_end],200
    mov word [x_end],200
    call linie

    ; Linke Linie
    mov word [y_beg],100
    mov word [x_beg],100
    mov word [y_end],200
    mov word [x_end],100
    call linie

    ; Rechte Linie
    mov word [y_beg],100
    mov word [x_beg],200
    mov word [y_end],200
    mov word [x_end],200
    call linie

    call readchar

    mov AH,0
    mov AL,03h
    int 10h

    mov AH,4Ch
    int 21h

readchar:
    mov AH,6
    mov DL,0FFh       ; ohne warten
    int 21h
    jz  readchar
    ret

linie:
    mov DX,[y_beg]    ; Start Y
    mov CX,[x_beg]    ; Start X

draw:
    mov AL,15
    mov AH,0Ch        ; VGA Pixel schreiben
    int 10h           ; DX=Y, CX=X, AL=Farbe

    mov AL,0
    cmp CX,[x_end]
    je  row
    add CX,1
    mov AL,1
row:
    cmp DX,[y_end]
    je  col
    add DX,1
    mov AL,1
col:
    cmp AL,1
    jz draw
    ret
	
x_beg dw 0
y_beg dw 0
x_end dw 0
y_end dw 0 

Beispielcode 7 - VGA ausgefülltes Rechteck zeichnen

org 100h

start:
    mov AX,0013h      ; 13h = 320x200, 256 Farben
    int 10h

    mov AH,0Bh
    mov BX,9          ; 9 = hellblau
    int 10h

    mov word [y_beg],50
    mov word [x_beg],50
    mov word [y_end],150
    mov word [x_end],200
    call fill_rect

    call readchar

    mov AH,0
    mov AL,03h
    int 10h

    mov AH,4Ch
    int 21h

readchar:
    mov AH,6
    mov DL,0FFh       ; ohne warten
    int 21h
    jz readchar
    ret

fill_rect:
    mov DX,[y_beg]
fill_row:
    mov CX,[x_beg]
fill_col:
    mov AL,14         ; gelb
    mov AH,0Ch        ; VGA Pixel schreiben
    int 10h           ; DX=Y, CX=X, AL=Farbe
    inc CX
    cmp CX,[x_end]
    jle fill_col
    inc DX
    cmp DX,[y_end]
    jle fill_row
    ret

; Variablen
x_beg dw 0
y_beg dw 0
x_end dw 0
y_end dw 0

Beispielcode 8 - VGA Moving Ball

BITS 16
ORG 100h

start:
    mov ax, 0013h      ; VGA 320x200, 256 Farben
    int 10h

    ; Anfangsposition
    mov bx, 50         ; X
    mov dx, 80         ; Y

main_loop:
    lea si, [ball]
    mov ax, 0A000h
    mov es, ax
    mov al, 9
    call draw_ball

    call getkey
    cmp al, 'w'
    je move_up
    cmp al, 'a'
    je move_down
    cmp al, 'n'
    je move_left
    cmp al, 'm'
    je move_right
    cmp al, 27          ; ESC = Ende
    je exit_program

    jmp main_loop

move_up:
    dec dx
    jmp main_loop
move_down:
    inc dx
    jmp main_loop
move_left:
    dec bx
    jmp main_loop
move_right:
    inc bx
    jmp main_loop

exit_program:
    mov ax, 0003h
    int 10h
    mov ax, 4C00h
    int 21h

draw_ball:
    push ax
    push bx
    push dx
    push si

    mov cx, 16          ; Höhe
row_loop:
    push cx
    mov cx, 16          ; Breite
    mov di, dx
    imul di, 320
    add di, bx
draw_pixel:
    lodsb
    mov [es:di], al
    inc di
    loop draw_pixel

    add si, 0
    inc dx
    pop cx
    dec cx
    jnz row_loop

    pop si
    pop dx
    pop bx
    pop ax
    ret

getkey:
    mov ah, 0
    int 16h
    ret

ball:
    db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    db 0,0,0,0,14,14,14,14,14,14,14,0,0,0,0,0
    db 0,0,0,14,14,15,14,14,14,15,14,14,0,0,0,0
    db 0,0,14,14,15,12,15,14,15,12,15,14,14,0,0,0
    db 0,14,14,15,12,12,12,15,15,12,12,12,15,14,0,0
    db 0,14,14,15,12,12,15,14,15,12,12,15,14,14,0,0
    db 0,14,14,14,15,15,14,14,14,15,15,14,14,14,0,0
    db 0,14,14,14,14,14,14,15,14,14,14,14,14,14,0,0
    db 0,14,14,14,14,14,14,15,14,14,14,14,14,14,0,0
    db 0,14,14,14,15,15,14,14,14,15,15,14,14,14,0,0
    db 0,14,14,15,12,12,15,14,15,12,12,15,14,14,0,0
    db 0,14,14,15,12,12,12,15,15,12,12,12,15,14,0,0
    db 0,0,14,14,15,12,15,14,15,12,15,14,14,0,0,0
    db 0,0,0,14,14,15,14,14,14,15,14,14,0,0,0,0
    db 0,0,0,0,14,14,14,14,14,14,14,0,0,0,0,0
    db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

Beispielcode 9 - VGA Text Ausgabe

BITS 16
ORG 100h

start:
    mov  ax,0013h
    int  10h

    ; Farbe 10 - Rot
    mov  dx,3C8h
    mov  al,10
    out  dx,al
    mov  dx,3C9h
    mov  al,63
    out  dx,al
    xor  al,al
    out  dx,al
    xor  al,al
    out  dx,al

    ; Farbe 11 - Grün
    mov  dx,3C8h
    mov  al,11
    out  dx,al
    mov  dx,3C9h
    xor  al,al
    out  dx,al
    mov  al,63
    out  dx,al
    xor  al,al
    out  dx,al

    ; Farbe 12 - Blau
    mov  dx,3C8h
    mov  al,12
    out  dx,al
    mov  dx,3C9h
    xor  al,al
    out  dx,al
    xor  al,al
    out  dx,al
    mov  al,63
    out  dx, al

    ; Farbe 13 - Gelb
    mov  dx,3C8h
    mov  al,13
    out  dx,al
    mov  dx,3C9h
    mov  al,63
    out  dx,al
    mov  al,63
    out  dx,al
    xor  al,al
    out  dx,al
	
    ; Farbe 15 - Weiß
    mov  dx,3C8h
    mov  al,14
    out  dx,al
    mov  dx,3C9h
    mov  al,63
    out  dx,al
    mov  al,63
    out  dx,al
    mov  al,63
    out  dx,al

    mov  ax,0A000h
    mov  es,ax

    mov  si,text1
    mov  bx,20
    mov  dx,30
    mov  al,10
    call draw_string_color

    mov  si,text2
    mov  bx,20
    mov  dx,50
    mov  al,11
    call draw_string_color

    mov  si, text3
    mov  bx,20
    mov  dx,70
    mov  al,12
    call draw_string_color

    mov  si,text4
    mov  bx,20
    mov  dx,90
    mov  al,13
    call draw_string_color

    mov  si,text5
    mov  bx,20
    mov  dx,110
    mov  al,14
    call draw_string_color

wait_key:
    mov  ah,0
    int  16h

    mov  ax,0003h
    int  10h
    mov  ax,4C00h
    int  21h

draw_string_color:
    push ax
    push bx
    push dx

    mov  [color],al
	
nextchar:
    lodsb
    cmp  al, 0
    je   done

    push si
    push dx

    mov  ah, al       ; ASCII in AH
    call draw_char    ; BL enthält immer die Farbe

    pop  dx
    pop  si

    add  bx, 8
    jmp  nextchar

done:
    pop  dx
    pop  bx
    pop  ax
    ret

draw_char:
    push ax
    push bx
    push dx
    push di
    push si

    mov  si,font_table
    mov  al,ah        ; ASCII in AL für Font-Index
    sub  al,32
    xor  ah,ah
    shl  ax,3
    add  si,ax

    mov  di,dx
    imul di,320
    add  di,bx

    mov  cx,8
row:
    mov  al,[si]      ; Font-Bit für diese Zeile
    inc  si
    mov  bh,8
col:
    test al,80h
    jz   skip
    mov  bl, [color]  ; BL wiederherstellen
    mov  [es:di], bl
skip:
    shl  al,1
    inc  di
    dec  bh
    jnz  col
    add  di,320-8
    loop row

    pop  si
    pop  di
    pop  dx
    pop  bx
    pop  ax
    ret

text1 db "Hallo VGA!!! 0123456789",0
text2 db "Jede Zeile hat eine andere Farbe!",0
text3 db "Palette per OUT 3C8/3C9 gesetzt.",0
text4 db "Fonts aus eigener Tabelle ABC xyz!",0
text5 db "0123456789 !@#$%^&*() []{}<>?",0

color: dw 0

font_table:
db 00000000b,00000000b,00000000b,00000000b,00000000b,00000000b,00000000b,00000000b ; 32  ' '
db 00011000b,00011000b,00011000b,00011000b,00011000b,00000000b,00011000b,00000000b ; 33  '!'
db 00100100b,00100100b,00100100b,00000000b,00000000b,00000000b,00000000b,00000000b ; 34  '"'
db 00100100b,00100100b,11111111b,00100100b,11111111b,00100100b,00100100b,00000000b ; 35  '#'
db 00011000b,00111110b,01011000b,00111100b,00011010b,01111100b,00011000b,00000000b ; 36  '$'
db 01100010b,01100100b,00001000b,00010000b,00100000b,01001100b,10001100b,00000000b ; 37  '%'
db 00110000b,01001000b,00110000b,01101000b,10001100b,10001100b,01110110b,00000000b ; 38  '&'
db 00011000b,00011000b,00010000b,00100000b,00000000b,00000000b,00000000b,00000000b ; 39  '''
db 00001100b,00011000b,00110000b,00110000b,00110000b,00011000b,00001100b,00000000b ; 40  '('
db 00110000b,00011000b,00001100b,00001100b,00001100b,00011000b,00110000b,00000000b ; 41  ')'
db 00000000b,00100100b,00011000b,01111110b,00011000b,00100100b,00000000b,00000000b ; 42  '*'
db 00000000b,00011000b,00011000b,01111110b,00011000b,00011000b,00000000b,00000000b ; 43  '+'
db 00000000b,00000000b,00000000b,00000000b,00011000b,00011000b,00010000b,00100000b ; 44  ','
db 00000000b,00000000b,00000000b,01111110b,00000000b,00000000b,00000000b,00000000b ; 45  '-'
db 00000000b,00000000b,00000000b,00000000b,00011000b,00011000b,00000000b,00000000b ; 46  '.'
db 00000010b,00000100b,00001000b,00010000b,00100000b,01000000b,10000000b,00000000b ; 47  '/'
db 00111100b,01000010b,01000110b,01001010b,01010010b,01100010b,00111100b,00000000b ; 48  '0'
db 00001000b,00011000b,00101000b,00001000b,00001000b,00001000b,00111110b,00000000b ; 49  '1'
db 00111100b,01000010b,00000010b,00011100b,00100000b,01000000b,01111110b,00000000b ; 50  '2'
db 00111100b,01000010b,00000010b,00011100b,00000010b,01000010b,00111100b,00000000b ; 51  '3'
db 00000100b,00001100b,00010100b,00100100b,01111110b,00000100b,00000100b,00000000b ; 52  '4'
db 01111110b,01000000b,01111100b,00000010b,00000010b,01000010b,00111100b,00000000b ; 53  '5'
db 00111100b,01000010b,01000000b,01111100b,01000010b,01000010b,00111100b,00000000b ; 54  '6'
db 01111110b,00000010b,00000100b,00001000b,00010000b,00010000b,00010000b,00000000b ; 55  '7'
db 00111100b,01000010b,01000010b,00111100b,01000010b,01000010b,00111100b,00000000b ; 56  '8'
db 00111100b,01000010b,01000010b,00111110b,00000010b,01000010b,00111100b,00000000b ; 57  '9'
db 00000000b,00011000b,00011000b,00000000b,00011000b,00011000b,00000000b,00000000b ; 58  ':'
db 00000000b,00011000b,00011000b,00000000b,00011000b,00011000b,00010000b,00100000b ; 59  ';'
db 00000100b,00001000b,00010000b,00100000b,00010000b,00001000b,00000100b,00000000b ; 60  '<'
db 00000000b,00000000b,01111110b,00000000b,01111110b,00000000b,00000000b,00000000b ; 61  '='
db 00100000b,00010000b,00001000b,00000100b,00001000b,00010000b,00100000b,00000000b ; 62  '>'
db 00111100b,01000010b,00000100b,00001000b,00010000b,00000000b,00010000b,00000000b ; 63  '?'
db 00111100b,01000010b,01011010b,01010110b,01011110b,01000000b,00111100b,00000000b ; 64  '@'
db 00111100b,01000010b,01000010b,01111110b,01000010b,01000010b,01000010b,00000000b ; 65  'A'
db 01111100b,01000010b,01000010b,01111100b,01000010b,01000010b,01111100b,00000000b ; 66  'B'
db 00111100b,01000010b,01000000b,01000000b,01000000b,01000010b,00111100b,00000000b ; 67  'C'
db 01111100b,01000010b,01000010b,01000010b,01000010b,01000010b,01111100b,00000000b ; 68  'D'
db 01111110b,01000000b,01000000b,01111100b,01000000b,01000000b,01111110b,00000000b ; 69  'E'
db 01111110b,01000000b,01000000b,01111100b,01000000b,01000000b,01000000b,00000000b ; 70  'F'
db 00111100b,01000010b,01000000b,01001110b,01000010b,01000010b,00111100b,00000000b ; 71  'G'
db 01000010b,01000010b,01000010b,01111110b,01000010b,01000010b,01000010b,00000000b ; 72  'H'
db 00111100b,00011000b,00011000b,00011000b,00011000b,00011000b,00111100b,00000000b ; 73  'I'
db 00011110b,00000100b,00000100b,00000100b,00000100b,01000100b,00111000b,00000000b ; 74  'J'
db 01000010b,01000100b,01001000b,01110000b,01001000b,01000100b,01000010b,00000000b ; 75  'K'
db 01000000b,01000000b,01000000b,01000000b,01000000b,01000000b,01111110b,00000000b ; 76  'L'
db 01000010b,01100110b,01011010b,01000010b,01000010b,01000010b,01000010b,00000000b ; 77  'M'
db 01000010b,01100010b,01010010b,01001010b,01000110b,01000010b,01000010b,00000000b ; 78  'N'
db 00111100b,01000010b,01000010b,01000010b,01000010b,01000010b,00111100b,00000000b ; 79  'O'
db 01111100b,01000010b,01000010b,01111100b,01000000b,01000000b,01000000b,00000000b ; 80  'P'
db 00111100b,01000010b,01000010b,01000010b,01001010b,01000100b,00111010b,00000000b ; 81  'Q'
db 01111100b,01000010b,01000010b,01111100b,01001000b,01000100b,01000010b,00000000b ; 82  'R'
db 00111100b,01000010b,01000000b,00111100b,00000010b,01000010b,00111100b,00000000b ; 83  'S'
db 01111110b,00011000b,00011000b,00011000b,00011000b,00011000b,00011000b,00000000b ; 84  'T'
db 01000010b,01000010b,01000010b,01000010b,01000010b,01000010b,00111100b,00000000b ; 85  'U'
db 01000010b,01000010b,01000010b,01000010b,00100100b,00100100b,00011000b,00000000b ; 86  'V'
db 01000010b,01000010b,01000010b,01000010b,01011010b,01111110b,01000010b,00000000b ; 87  'W'
db 01000010b,00100100b,00011000b,00011000b,00011000b,00100100b,01000010b,00000000b ; 88  'X'
db 01000010b,00100100b,00011000b,00010000b,00010000b,00010000b,00010000b,00000000b ; 89  'Y'
db 01111110b,00000010b,00000100b,00001000b,00010000b,00100000b,01111110b,00000000b ; 90  'Z'
db 00111110b,00100000b,00100000b,00100000b,00100000b,00100000b,00111110b,00000000b ; 91  '['
db 10000000b,01000000b,00100000b,00010000b,00001000b,00000100b,00000010b,00000000b ; 92  '\'
db 00111110b,00000010b,00000010b,00000010b,00000010b,00000010b,00111110b,00000000b ; 93  ']'
db 00010000b,00101000b,01000100b,00000000b,00000000b,00000000b,00000000b,00000000b ; 94  '^'
db 00000000b,00000000b,00000000b,00000000b,00000000b,00000000b,00000000b,00000000b ; 
db 00000000b,00000000b,00000000b,00000000b,00000000b,00000000b,11111111b,00000000b ; 95  '_'
db 00000000b,00000000b,00111100b,00000010b,00111110b,01000010b,00111110b,00000000b ; 96  'a'
db 01000000b,01000000b,01111100b,01000010b,01000010b,01000010b,01111100b,00000000b ; 97  'b'
db 00000000b,00000000b,00111100b,01000010b,01000000b,01000010b,00111100b,00000000b ; 98  'c'
db 00000010b,00000010b,00111110b,01000010b,01000010b,01000010b,00111110b,00000000b ; 99  'd'
db 00000000b,00000000b,00111100b,01000010b,01111110b,01000000b,00111100b,00000000b ; 100 'e'
db 00001100b,00010010b,00010000b,00111100b,00010000b,00010000b,00010000b,00000000b ; 101 'f'
db 00000000b,00000000b,00111110b,01000010b,01000010b,00111110b,00000010b,00111100b ; 102 'g'
db 01000000b,01000000b,01111100b,01000010b,01000010b,01000010b,01000010b,00000000b ; 103 'h'
db 00010000b,00000000b,00110000b,00010000b,00010000b,00010000b,00111000b,00000000b ; 104 'i'
db 00000100b,00000000b,00000100b,00000100b,00000100b,01000100b,00111000b,00000000b ; 105 'j'
db 01000000b,01001000b,01010000b,01100000b,01010000b,01001000b,01000100b,00000000b ; 106 'k'
db 00110000b,00010000b,00010000b,00010000b,00010000b,00010000b,00111000b,00000000b ; 107 'l'
db 00000000b,00000000b,01100110b,01011010b,01000010b,01000010b,01000010b,00000000b ; 108 'm'
db 00000000b,00000000b,01111100b,01000010b,01000010b,01000010b,01000010b,00000000b ; 109 'n'
db 00000000b,00000000b,00111100b,01000010b,01000010b,01000010b,00111100b,00000000b ; 110 'o'
db 00000000b,00000000b,01111100b,01000010b,01000010b,01111100b,01000000b,01000000b ; 111 'p'
db 00000000b,00000000b,00111110b,01000010b,01000010b,00111110b,00000010b,00000010b ; 112 'q'
db 00000000b,00000000b,01101100b,00010010b,00010000b,00010000b,00010000b,00000000b ; 113 'r'
db 00000000b,00000000b,00111100b,01000000b,00111100b,00000010b,01111100b,00000000b ; 114 's'
db 00010000b,00010000b,00111100b,00010000b,00010000b,00010010b,00001100b,00000000b ; 115 't'
db 00000000b,00000000b,01000010b,01000010b,01000010b,01000010b,00111110b,00000000b ; 116 'u'
db 00000000b,00000000b,01000010b,01000010b,00100100b,00100100b,00011000b,00000000b ; 117 'v'
db 00000000b,00000000b,01000010b,01000010b,01011010b,01111110b,01000010b,00000000b ; 118 'w'
db 00000000b,00000000b,01000010b,00100100b,00011000b,00100100b,01000010b,00000000b ; 119 'x'
db 00000000b,00000000b,01000010b,01000010b,01000010b,00111110b,00000010b,00111100b ; 120 'y'
db 00000000b,00000000b,01111110b,00000100b,00001000b,00010000b,01111110b,00000000b ; 121 'z'
db 00000110b,00001000b,00001000b,00010000b,00001000b,00001000b,00000110b,00000000b ; 122 '{'
db 00011000b,00011000b,00011000b,00000000b,00011000b,00011000b,00011000b,00000000b ; 123 '|'
db 01100000b,00010000b,00010000b,00001000b,00010000b,00010000b,01100000b,00000000b ; 124 '}'
db 00000000b,00000000b,00100010b,01010100b,00001000b,00000000b,00000000b,00000000b ; 125 '~'

Bootloader "Hello World" im 40x25 Textmodus (schwarzer Hintergrund, bunte Schrift)

Zusätzliche Erklärung: Aufbau eines Bootsektors

Ein Bootsektor ist der erste Sektor512 Bytes groß und wird vom BIOS beim Starten direkt in den Speicher bei Adresse 0x7C00 geladen und ausgeführt.

Offset (Hex)GrößeInhaltBeschreibung
0x000 – 0x1BD446 BytesBootloader CodeHier befindet sich unser Assembler Programm, z.B. „Hello World“.
0x1BE – 0x1FD64 BytesPartitionstabelleNur bei Festplatten wichtig (MBR). Bei einfachen Bootloadern bleibt dieser Bereich leer.
0x1FE – 0x1FF2 Bytes0x55AABootsignatur: Das BIOS prüft diese Bytes. Fehlen sie, wird der Datenträger nicht gebootet.

Warum dw 0xAA55 am Ende stehen muss

Die beiden letzten Bytes 0x55 und 0xAA (in dieser Reihenfolge im Speicher) sind die sogenannte Bootsignatur. Diese ist zwingend erforderlich, damit das BIOS erkennt: „Dieser Sektor ist bootfähig“. Fehlt sie, wird das BIOS einfach die nächste Bootquelle versuchen und dein Code wird nie ausgeführt.

Im Quellcode steht daher am Ende:

times 510-($-$$) db 0 ; Rest des Sektors auffüllen bis 510 Bytes dw 0xAA55 ; Bootsignatur am Ende

Erklärung:

Ohne diese Signatur wird der Stick oder das Image nicht als bootfähig erkannt.


Diese Anleitung zeigt Schritt für Schritt, wie du einen einfachen Bootloader unter Windows erstellst, der:

Schritt 1: Bootloader 1 Quellcode erstellen

Erstelle eine Datei boot.asm mit folgendem Inhalt:

bits 16
org 0x7C00

start:
    cli
    xor  ax,ax
    mov  ds,ax
    mov  es,ax
    mov  ss,ax
    mov  sp,0x7C00
    sti

    ; 40x25 Textmodus aktivieren
    mov  ax,0x0001           ; Modus 1 = 40x25 Text
    int  0x10

    ; Segment für Textspeicher setzen (0xB800)
    mov  ax,0xB800
    mov  es,ax
    xor  di,di

    ; Bildschirm löschen (40*25)
    mov  cx,1000             ; 40 Spalten * 25 Zeilen
clear:
    mov  byte [es:di],0
    inc  di
    mov  byte [es:di],0x00   ; schwarzer Hintergrund
    inc  di
    loop clear

    ; Position: Mitte (Zeile 12, Spalte 14 bei 40 Spalten)
    mov  si,text
    mov  cx,text_len
    mov  bx,0
    mov  di,(12*40+14)*2

print_loop:
    lodsb
    mov  [es:di],al
    mov  al,color_table[bx]
    mov  [es:di+1],al
    add  di,2
    inc  bx
    cmp  bx,color_count
    jl   skip_reset
    xor  bx,bx
skip_reset:
    loop print_loop

hang:
    cli
    hlt
    jmp  hang

text        db 'Hello World!'
text_len    equ $-msg

; Vordergrundfarben bunt, Hintergrund schwarz (0x0)
color_table db 0x04,0x02,0x06,0x03,0x01,0x05,0x07,0x0E,0x0C,0x0A,0x09,0x0F
color_count equ $-color_table

times 510-($-$$) db 0
dw    0xAA55

Schritt 2: NASM installieren und kompilieren

Unter Windows kannst du NASM verwenden:

nasm -f bin boot.asm -o boot.bin

Schritt 3: Bootfähiges Image erstellen

fsutil file createnew disk.img 1474560 copy /b boot.bin + disk.img disk.img

Schritt 4: Mit QEMU testen

Falls du QEMU noch nicht installiert hast, kannst du es hier herunterladen:

➡ QEMU Download (offizielle Seite)

cd "C:\Program Files\qemu" .\qemu-system-i386.exe -fda "C:\Users\DeinName\Desktop\disk.img" -boot a -m 16M

Schritt 5: Auf USB Stick schreiben (optional)

Fertig!

Der Bildschirm startet nun im 40x25 Textmodus, löscht den Inhalt auf schwarzem Hintergrund und zeigt „Hello World!“ mittig mit bunten Buchstaben an.




Zusätzliche Erklärung: NASM & QEMU Befehle

🧰 NASM Befehl

nasm -f bin boot.asm -o boot.bin

Merke: Ein Bootsektor muss genau 512 Bytes groß sein – das macht NASM hier automatisch für dich durch times 510 ... im Code.

💻 QEMU Befehl

.\qemu-system-i386.exe -fda "C:\Users\DeinName\Desktop\disk.img" -boot a -m 16M

Tipp: Du kannst den Speicherwert auch ändern, z.B. -m 4M oder -m 32M. Für einfache Assembler-Bootloader ist das egal, da sie kaum Speicher brauchen.

📌 Wichtige Hinweise


💾 Erklärung - Image erstellen mit Windows Bordmitteln

fsutil file createnew disk.img 1474560
copy /b boot.bin + disk.img disk.img

Hinweis: Das erzeugte Image ist jetzt bootfähig, solange dein Bootloader korrekt ist und die Bootsignatur 0xAA55 am Ende hat.



Bootloader 2 - Von Real Mode zu Protected Mode

org 0x7C00
bits 16

start:
    ; NMI deaktivieren
    in    al,0x70             ; aktuellen CMOS Wert lesen
    or    al,0x80             ; NMI-Disable Bit setzen
    out   0x70,al

    cli                       ; normale Interrupts aus
    xor   ax,ax
    mov   ds,ax
    mov   ss,ax
    mov   sp,0x7C00
    mov   es,ax

    ; Kurz in Real Mode Text ausgeben
    mov   si,real_text
    call  print16

    ; A20 aktivieren
    call  enable_a20

    ; Aktuelle Cursor Position merken (Zeile)
    mov   ah,0x03             ; BIOS - Get cursor position
    mov   bh,0x00             ; Seite 0
    int   0x10
    mov   [cursor_row],dh

    ; GDT laden
    lgdt  [gdt_descriptor]

    ; Protected Mode aktivieren
    mov   eax,cr0
    or    eax,1               ; PE Bit setzen
    mov   cr0,eax

    ; NMI wieder aktivieren (optional, kann auch nach PM init kommen)
    in    al,0x70
    and   al,0x7F
    out   0x70,al

    ; Far Jump zu Protected Mode Code Segment
    jmp   0x08:protected_mode_start

[bits 32]
protected_mode_start:
    mov   ax,0x10
    mov   ds,ax
    mov   es,ax
    mov   fs,ax
    mov   gs,ax
    mov   ss,ax
    mov   esp,0x90000

    ; VRAM Adresse für nächste Zeile berechnen
    mov   edi,0xB8000
    movzx eax,byte [cursor_row]
    add   eax,1               ; nächste Zeile
    imul  eax,80              ; 80 Spalten
    shl   eax,1               ; 2 Bytes pro Zeichen
    add   edi,eax

    mov   esi, prot_text
    call  print32

halt:
    hlt
    jmp halt

; ----------------------
print16:
    pusha
print16_loop:
    lodsb
    test  al,al
    jz    done16
    mov   ah,0x0E
    int   0x10
    jmp   print16_loop
done16:
    popa
    ret

print32:
    pusha
print32_loop:
    lodsb
    test  al,al
    jz    done32
    mov   ah,0x0F
    mov   [edi],ax
    add   edi,2
    jmp print32_loop
done32:
    popa
    ret

; ----------------------
enable_a20:
wait_input_empty:
    in    al,0x64
    test  al,2
    jnz   wait_input_empty
    mov   al,0xD1
    out   0x64,al
wait_input_empty2:
    in    al,0x64
    test  al,2
    jnz   wait_input_empty2
    mov   al,0xDF
    out   0x60,al
    ret

; ----------------------
cursor_row: db 0
real_text:  db "Hello World in Real Mode!",0
prot_text:  db "Hello World in Protected Mode!",0

; ----------------------
gdt_start:
    dq 0                      ; Null Descriptor

gdt_code:
    dw 0xFFFF
    dw 0x0000
    db 0x00
    db 10011010b              ; Code Segment
    db 11001111b
    db 0x00

gdt_data:
    dw 0xFFFF
    dw 0x0000
    db 0x00
    db 10010010b              ; Data Segment
    db 11001111b
    db 0x00

gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start - 1
    dd gdt_start

times 510-($-$$) db 0
dw 0xAA55


Bootloader 2 - Tron (Mini Game)

org 7C00h

start:
    xor  ax,ax
    mov  ss,ax
    mov  sp,0FFFEh
    mov  ax,07C0h
    mov  ds,ax
    mov  es,ax

    mov  ax,13h                      ; VGA 320x200, 256 Farben
    int  10h
    mov  ax,0A000h
    mov  es,ax

    call reset_game

main_loop:
    mov  ax,[player1_y]              ; - Spieler 1 Position berechnen und prüfen
    mov  bx,320
    mul  bx
    add  ax,[player1_x]
    mov  di,ax
    mov  al,[es:di]
    cmp  al,0
    jne  collision_p1                ; nur Spieler 1
    mov  al,12                       ; rot
    mov  [es:di],al

    mov  ax,[player2_y]              ; - Spieler 2 Position berechnen und prüfen
    mov  bx,320
    mul  bx
    add  ax,[player2_x]
    mov  di,ax
    mov  al,[es:di]
    cmp  al,0
    jne  collision_p2                ; nur Spieler 2
    mov  al,9                        ; blau
    mov  [es:di],al

    mov  ah,01h                      ; - Tastatur prüfen
    int  16h
    jz   no_key
    mov  ah,00h
    int  16h

    cmp  ah,4Dh                      ; Pfeil rechts
    je   p1_turn_right
    cmp  ah,4Bh                      ; Pfeil links
    je   p1_turn_left
    cmp  ah,1Eh                      ; Taste 'A'
    je   p2_turn_left
    cmp  ah,2Ch                      ; Taste 'Y'
    je   p2_turn_right
no_key:
    mov  al,[p1_dir]                 ; - Spieler 1 Bewegung
    cmp  al,0
    je   p1_up
    cmp  al,1
    je   p1_right
    cmp  al,2
    je   p1_down
    cmp  al,3
    je   p1_left
p1_up:
    dec  word [player1_y]
    jmp  p1_check
p1_right:
    inc  word [player1_x]
    jmp  p1_check
p1_down:
    inc  word [player1_y]
    jmp  p1_check
p1_left:
    dec  word [player1_x]
p1_check:
    mov  ax,[player1_x]
    cmp  ax,0
    jl   collision_p1
    cmp  ax,319
    jg   collision_p1
    mov  ax,[player1_y]
    cmp  ax,0
    jl   collision_p1
    cmp  ax,199
    jg   collision_p1

    mov  al,[p2_dir]                 ; - Spieler 2 Bewegung
    cmp  al,0
    je   p2_up
    cmp  al,1
    je   p2_right
    cmp  al,2
    je   p2_down
    cmp  al,3
    je   p2_left
p2_up:     
    dec  word [player2_y]
    jmp  p2_check
p2_right:
    inc  word [player2_x]
    jmp  p2_check
p2_down:
    inc  word [player2_y]
    jmp  p2_check
p2_left:
    dec  word [player2_x]
p2_check:
    mov  ax,[player2_x]
    cmp  ax,0
    jl   collision_p2
    cmp  ax,319
    jg   collision_p2
    mov  ax,[player2_y]
    cmp  ax,0
    jl   collision_p2
    cmp  ax,199
    jg   collision_p2

    mov  cx,100                      ; - Verzögerung in der Spielroutine
outer_delay:
    mov  dx,60000
inner_delay:
    dec  dx
    jnz  inner_delay
    dec  cx
    jnz  outer_delay

    jmp  main_loop

p1_turn_right:                       ; - Steuerung Player 1
    mov  al,[p1_dir]
    add  al,1
    and  al,3
    mov  [p1_dir],al
    jmp  no_key
p1_turn_left:
    mov  al,[p1_dir]
    add  al,3
    and  al,3
    mov  [p1_dir],al
    jmp  no_key

p2_turn_right:                       ; - Steuerung Player 2
    mov  al,[p2_dir]
    add  al,1
    and  al,3
    mov  [p2_dir],al
    jmp  no_key
p2_turn_left:
    mov  al,[p2_dir]
    add  al,3
    and  al,3
    mov  [p2_dir],al
    jmp  no_key

collision_p1:                        ; - Kollisions-Explosion nur für Spieler 1
    mov  bx,[player1_y]
    mov  cx,[player1_x]
    call explode_red
    jmp  wait_key

collision_p2:                        ; - Kollisions-Explosion nur für Spieler 2
    mov  bx,[player2_y]
    mov  cx,[player2_x]
    call explode_blue
    jmp  wait_key

explode_red:                         ; - Explosion 5x5 rot
    sub  bx,2
    sub  cx,2
    mov  si,0
expl_row_r:
    mov  di,bx
    imul di,320
    add  di,cx
    mov  dx,0
expl_col_r:
    mov  byte [es:di],12             ; rot statt weiß
    inc  di
    inc  dx
    cmp  dx,5
    jl   expl_col_r
    inc  bx
    inc  si
    cmp  si,5
    jl   expl_row_r
    ret


explode_blue:                        ; - Explosion 5x5 blau
    sub  bx,2
    sub  cx,2
    mov  si,0
expl_row_b:
    mov  di,bx
    imul di,320
    add  di,cx
    mov  dx,0
expl_col_b:
    mov  byte [es:di],9
    inc  di
    inc  dx
    cmp  dx,5
    jl   expl_col_b
    inc  bx
    inc  si
    cmp  si,5
    jl   expl_row_b
    ret

wait_key:                            ; - Warten auf Tastendruck
    mov  ah,01h
    int  16h
    jz   wait_key
    call reset_game

reset_game:                          ; - Neustart bei Kollision
    xor  di,di
    mov  cx,320*200/2
    xor  ax,ax
    rep  stosw

    mov  word [player1_x],160        ; - Spieler 1 in Mitte rechts starten
    mov  word [player1_y],100
    mov  byte [p1_dir],1

    mov  word [player2_x],159        ; - Spieler 2 in Mitte links starten
    mov  word [player2_y],100
    mov  byte [p2_dir],3

    jmp  main_loop

player1_x dw 0
player1_y dw 0
p1_dir    db 0

player2_x dw 0
player2_y dw 0
p2_dir    db 0

times 510-($-$$) db 0
dw 0AA55h

Bootloader 3 - Hexdump Track 0 (Sektoren 1-18)

org 7C00h

start:
    cli
    xor  ax,ax
	mov  ds,ax
	mov  es,ax
    mov  ss,ax
    mov  sp,07C00h
	sti
    
	mov  ax,1112h                   ; Load 8x8 Font (VGA)
    mov  bl,0
    int  10h

    mov  ax,1201h
    mov  bl,20h
    int  10h

    mov  [BootDrive],dl
    mov  [SectorNum],byte 1         ; Sektor 1

next_sector:
    call cls
    mov  ah,02h
    mov  al,1
    mov  ch,0
    mov  cl,[SectorNum]
    mov  dh,0
    mov  dl,[BootDrive]
    mov  bx,0500h
    int  13h
    jc   disk_error

    mov  si,0500h
    mov  cx,512
    xor  dx,dx                     ; Offset im Sektor

dump_loop:
    push cx

    mov  al,'S'
    call print_char
    mov  al,[SectorNum]
    call print_sector_dec
    mov  al,':'
    call print_char

    push dx
    mov  ax,dx
    call print_hex16
    pop  dx
    mov  al,':'
    call print_char
    mov  al,' '
    call print_char

    push si
    mov  bx,si
    mov  cx,16

print_hex_bytes:
    lodsb
    call print_hex8
    mov  al,' '
    call print_char
    loop print_hex_bytes

    mov  si,bx
    mov  cx,16

    mov  al,' '
    call print_char
    mov  al,' '
    call print_char

print_ascii:
    lodsb
    cmp  al,20h
    jb   dot
    cmp  al,7Eh
    ja   dot
    jmp  show
dot:
    mov  al,'.'
show:
    call print_char
    loop print_ascii

    call newline

    pop  si
    add  si,16
    add  dx,16
    pop  cx
    sub  cx,16
    jg   dump_loop

    mov  si,info_msg
    call print_string
	
    call wait_key_or_exit
    inc  byte [SectorNum]
    cmp  byte [SectorNum],19
    jl   next_sector

hang:
    call cls
    mov  si,final_msg
    call print_string
hang1:
    jmp  hang1

wait_key_or_exit:
    mov  ah,01h                    ; BIOS: Prüfen auf Tastendruck
    int  16h
    jz   wait_key                  ; Wenn keine Taste, wieder warten
    mov  ah,00h                    ; BIOS: Taste lesen
    int  16h
    cmp  al,1Bh                    ; ESC?
    je   hang
    ret
wait_key:
    jmp  wait_key_or_exit

newline:
    mov  ah,0Eh
    mov  al,0Dh
    int  10h
    mov  al,0Ah
    int  10h
    ret

print_char:
    mov  ah,0Eh
    int  10h
    ret

print_hex8:
    push ax
    push bx

    mov  bl,al                     ; AL sichern
    mov  al,bl
    shr  al,4                      ; oberes Nibble
    call nibble_to_ascii
    call print_char

    mov  al,bl
    and  al,0Fh                    ; unteres Nibble
    call nibble_to_ascii
    call print_char

    pop  bx
    pop  ax
    ret

print_hex16:
    push ax
    xchg al,ah
    call print_hex8
    xchg al,ah
    call print_hex8
    pop  ax
    ret

nibble_to_ascii:
    cmp  al,9
    jbe  num
    add  al,7
num:
    add  al,'0'
    ret

print_sector_dec:
    mov  al,[SectorNum]           ; AL = Sektor
    cmp  al,10
    jb   single_digit             ;  größer 10 → führende Null

    mov  ah,al                    ; Kopie
    sub  al,10                    ; AL = Einerstelle
    mov  al,ah                    ; Zehnerstelle = 1
    mov  al,'1'
    call print_char
    mov  al,[SectorNum]
    sub  al,10                    ; Einerstelle = AL - 10
    add  al,'0'
    call print_char
    ret

single_digit:
    mov  al, '0'
    call print_char               ; führende Null
    mov  al, [SectorNum]
    add  al, '0'
    call print_char
    ret

print_string:
next:
    lodsb
    or   al,al
    jz   done
    call print_char
    jmp  next
done:
    ret
	
cls:
    mov ah, 06h
    mov al, 0
    mov bh, 07h
    mov cx, 0000h
    mov dx, 314Fh                 ; Zeile 49 (0x31), Spalte 79 (0x4F) bei 50 Zeilen
    int 10h
 
    mov ah, 02h                   ; - Cursor nach oben links
    xor bh, bh
    xor dh, dh
    xor dl, dl
    int 10h
    ret
 
disk_error:
    mov  si,err_msg
    call print_string
    jmp  hang

BootDrive  db 0
SectorNum  db 0
err_msg    db 'Disk read error!',0
info_msg   db 'Press any key to continue!',0
final_msg  db 'Finsih !!!',0
times 510-($-$$) db 0
dw    0AA55h