Created
October 15, 2023 01:58
-
-
Save BrentFarris/6bc6765a40328815ea0003c3910a5dca to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BITS 16 ; Instruct the system this is 16-bit code | |
; This is the entry point, nothing should happen before this | |
; other than setting the instruction size | |
main: | |
mov ax, 07C0h ; Setup 4KB stack space after this bootloader | |
add ax, 288 ; (4096+515) / 16 bytes (aligned) per paragraph | |
cli ; Disable interrupts (solvs old DOS bug) | |
mov ss, ax ; Assign current stack segment | |
mov sp, 4096 ; Setup our stack pointer | |
sti ; Enable interrupts (solvs old DOS bug) | |
mov ax, 07C0h ; 07C0h is where our program is located | |
mov ds, ax ; Set data segment to the load point of our program | |
call run ; Start the main loop | |
;------------------------------------------------------------------------------ | |
; Constants | |
;------------------------------------------------------------------------------ | |
s_hi db "Hello, World!", 0Dh, 0Ah, "- Brent", 0Dh, 0Ah, 00h | |
s_nl db 0Dh, 0Ah, 00h | |
;------------------------------------------------------------------------------ | |
; The main loop of our program | |
;------------------------------------------------------------------------------ | |
run: | |
mov si, s_hi ; Set our SI register to hello message pointer | |
call print ; Call our print subroutine | |
.loop: | |
call read_keyboard ; Call our keyboard input subroutine | |
je .loop ; Return to loop if no key was pressed | |
call ah_to_str ; A key was pressed, so let's print it! | |
mov si, s_nl ; Move the new line bytes into SI register | |
call print ; Print a new line for readability | |
jmp .loop ; Infinite loop to hold control of the computer | |
;------------------------------------------------------------------------------ | |
; Reading keyboard input | |
;------------------------------------------------------------------------------ | |
read_keyboard: | |
mov ah, 00h ; 00h is the get key and clear buffer function in BIOS | |
int 16h ; Call the BIOS interrupt for keyboard functions | |
test ah, ah ; AH will be 0 if no key was pressed, allow je after | |
ret ; Return to caller with ZF and AH set | |
;------------------------------------------------------------------------------ | |
; Debug printing of bytes | |
;------------------------------------------------------------------------------ | |
ah_to_str: | |
push ax ; Save the state of our AX register | |
push cx ; Save the state of our CX register | |
mov ch, 80h ; Set bit flag for AND as 10000000 | |
mov al, ah ; Copy AH to AL so we can change AH | |
.ah_to_str_loop: | |
mov ah, al ; Restore original value of AH | |
and ah, ch ; Get the bit value for printing | |
test ah, ah ; Check to see if the bit is zero or 1 | |
je .ah_to_str_zero ; The bit was 0 so jump to print 0 | |
mov ah, 31h ; The bit was 1 so set AH to ascii 1 | |
jmp .ah_to_str_print ; Jump to print the character | |
.ah_to_str_zero: | |
mov ah, 30h ; The bit was 0 so set AH to ascii 0 | |
.ah_to_str_print: | |
call print_char ; Call our print_char routine below | |
SHR ch, 01h ; Shift CH right by 1 (0100000 first time) | |
cmp ch, 00h ; Check to see if we shifted all the way | |
jne .ah_to_str_loop ; If we haven't finished, return to loop | |
pop cx ; Restore the state of our CX register | |
pop ax ; Restore the state of our AX register | |
ret ; Return to caller location | |
print_char: | |
push ax ; Save the state of our AX register | |
push cx ; Save the CX register (due to int 10h clobbering) | |
mov al, ah ; AL is used for the character to print | |
mov ah, 0Eh ; Teletype BIOS interrupt function | |
mov bl, 0Fh ; Don't worry about me until the end of this guide | |
int 10h ; BIOS interrupt 10h (0x10 or 16 in decimal) | |
pop cx ; Restore the state of our CX register | |
pop ax ; Restore the state of our AX register | |
ret ; Return to caller location | |
;------------------------------------------------------------------------------ | |
; Print string subroutine (null terminated string print) | |
;------------------------------------------------------------------------------ | |
print: | |
push ax ; Save the current value of the AX register | |
mov ah, 0Eh ; Our first BIOS interrupt: Teletype output | |
mov bl, 0Fh ; Don't worry about me until the end of this guide | |
.repeat: | |
lodsb ; Load next character into AL register | |
cmp al, 00h ; Check if we are at end of string (0 = end of string) | |
je .done ; If AL is 0 then jump to done label | |
int 10h ; BIOS interrupt 10h (0x10 or 16 in decimal) | |
jmp .repeat ; Continue to next character in the string | |
.done: | |
pop ax ; Restore the value to the AX register | |
ret ; Return to caller location | |
;------------------------------------------------------------------------------ | |
; Boot loaders are 512 bytes in size so pad the remaining bytes with 0 | |
;------------------------------------------------------------------------------ | |
times 510-($-$$) db 0 ; Pad (510 - current position) bytes of 0 | |
dw 0xAA55 ; Boot sector code trailer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BITS 16 ; Instruct the system this is 16-bit code | |
; This is the entry point, nothing should happen before this | |
; other than setting the instruction size | |
main: | |
mov ax, 07C0h ; Setup 4KB stack space after this bootloader | |
add ax, 288 ; (4096+515) / 16 bytes (aligned) per paragraph | |
cli ; Disable interrupts (solvs old DOS bug) | |
mov ss, ax ; Assign current stack segment | |
mov sp, 4096 ; Setup our stack pointer | |
sti ; Enable interrupts (solvs old DOS bug) | |
mov ax, 07C0h ; 07C0h is where our program is located | |
mov ds, ax ; Set data segment to the load point of our program | |
call run ; Start the main loop | |
;------------------------------------------------------------------------------ | |
; Constants | |
;------------------------------------------------------------------------------ | |
s_hi db "Hello, World!", 0Dh, 0Ah, "- Brent", 0Dh, 0Ah, 00h | |
s_nl db 0Dh, 0Ah, 00h | |
;------------------------------------------------------------------------------ | |
; The main loop of our program | |
;------------------------------------------------------------------------------ | |
run: | |
call set_graphics ; Go into graphics mode | |
call plot_pixel ; Plot our white pixel on the screen | |
.loop: | |
call read_keyboard ; Call our keyboard input subroutine | |
je .loop ; Return to loop if no key was pressed | |
call ah_to_str ; A key was pressed, so let's print it! | |
mov si, s_nl ; Move the new line bytes into SI register | |
call print ; Print a new line for readability | |
jmp .loop ; Infinite loop to hold control of the computer | |
;------------------------------------------------------------------------------ | |
; Set graphics mode | |
;------------------------------------------------------------------------------ | |
set_graphics: | |
mov ah, 00h | |
mov al, 12h ; 640x480 VGA | |
int 10h | |
ret | |
;------------------------------------------------------------------------------ | |
; Plot a pixel | |
;------------------------------------------------------------------------------ | |
plot_pixel: | |
mov ah, 0Ch ; Write pixel function code | |
mov al, 0Fh ; Color (white) | |
mov cx, 0Fh ; X position | |
mov dx, 0Fh ; Y position | |
int 10h ; BIOS interrupt for screen functions | |
ret | |
;------------------------------------------------------------------------------ | |
; Reading keyboard input | |
;------------------------------------------------------------------------------ | |
read_keyboard: | |
mov ah, 00h ; 00h is the get key and clear buffer function in BIOS | |
int 16h ; Call the BIOS interrupt for keyboard functions | |
test ah, ah ; AH will be 0 if no key was pressed, allow je after | |
ret ; Return to caller with ZF and AH set | |
;------------------------------------------------------------------------------ | |
; Debug printing of bytes | |
;------------------------------------------------------------------------------ | |
ah_to_str: | |
push ax ; Save the state of our AX register | |
push cx ; Save the state of our CX register | |
mov ch, 80h ; Set bit flag for AND as 10000000 | |
mov al, ah ; Copy AH to AL so we can change AH | |
.ah_to_str_loop: | |
mov ah, al ; Restore original value of AH | |
and ah, ch ; Get the bit value for printing | |
test ah, ah ; Check to see if the bit is zero or 1 | |
je .ah_to_str_zero ; The bit was 0 so jump to print 0 | |
mov ah, 31h ; The bit was 1 so set AH to ascii 1 | |
jmp .ah_to_str_print ; Jump to print the character | |
.ah_to_str_zero: | |
mov ah, 30h ; The bit was 0 so set AH to ascii 0 | |
.ah_to_str_print: | |
call print_char ; Call our print_char routine below | |
SHR ch, 01h ; Shift CH right by 1 (0100000 first time) | |
cmp ch, 00h ; Check to see if we shifted all the way | |
jne .ah_to_str_loop ; If we haven't finished, return to loop | |
pop cx ; Restore the state of our CX register | |
pop ax ; Restore the state of our AX register | |
ret ; Return to caller location | |
print_char: | |
push ax ; Save the state of our AX register | |
push cx ; Save the CX register (due to int 10h clobbering) | |
mov al, ah ; AL is used for the character to print | |
mov ah, 0Eh ; Teletype BIOS interrupt function | |
mov bl, 0Fh ; Don't worry about me until the end of this guide | |
int 10h ; BIOS interrupt 10h (0x10 or 16 in decimal) | |
pop cx ; Restore the state of our CX register | |
pop ax ; Restore the state of our AX register | |
ret ; Return to caller location | |
;------------------------------------------------------------------------------ | |
; Print string subroutine (null terminated string print) | |
;------------------------------------------------------------------------------ | |
print: | |
push ax ; Save the current value of the AX register | |
mov ah, 0Eh ; Our first BIOS interrupt: Teletype output | |
mov bl, 0Fh ; Don't worry about me until the end of this guide | |
.repeat: | |
lodsb ; Load next character into AL register | |
cmp al, 00h ; Check if we are at end of string (0 = end of string) | |
je .done ; If AL is 0 then jump to done label | |
int 10h ; BIOS interrupt 10h (0x10 or 16 in decimal) | |
jmp .repeat ; Continue to next character in the string | |
.done: | |
pop ax ; Restore the value to the AX register | |
ret ; Return to caller location | |
;------------------------------------------------------------------------------ | |
; Boot loaders are 512 bytes in size so pad the remaining bytes with 0 | |
;------------------------------------------------------------------------------ | |
times 510-($-$$) db 0 ; Pad (510 - current position) bytes of 0 | |
dw 0xAA55 ; Boot sector code trailer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BITS 16 ; Instruct the system this is 16-bit code | |
; This is the entry point, nothing should happen before this | |
; other than setting the instruction size | |
main: | |
mov ax, 07C0h ; Setup 4KB stack space after this bootloader | |
add ax, 288 ; (4096+515) / 16 bytes (aligned) per paragraph | |
cli ; Disable interrupts (solves old DOS bug) | |
mov ss, ax ; Assign current stack segment | |
mov sp, 4096 ; Setup our stack pointer | |
sti ; Enable interrupts (solvs old DOS bug) | |
mov ax, 07C0h ; 07C0h is where our program is located | |
mov ds, ax ; Set data segment to the load point of our program | |
call run ; Start the main loop | |
;------------------------------------------------------------------------------ | |
; Constants | |
;------------------------------------------------------------------------------ | |
s_hi db "Hello, World!", 0Dh, 0Ah, "- Brent", 0Dh, 0Ah, 00h | |
;------------------------------------------------------------------------------ | |
; The main loop of our program | |
;------------------------------------------------------------------------------ | |
run: | |
mov si, s_hi ; Set our si register to point to the hello message | |
call print ; Call our print subroutine to print the message | |
.loop: | |
jmp .loop ; Infinite loop to hold control of the computer | |
;------------------------------------------------------------------------------ | |
; Print string subroutine (null terminated string print) | |
;------------------------------------------------------------------------------ | |
print: | |
push ax ; Save the current value of the AX register | |
mov ah, 0Eh ; Our first BIOS interrupt: Teletype output | |
mov bl, 0Fh ; Don't worry about me until the end of this guide | |
.repeat: | |
lodsb ; Load next character into AL register | |
cmp al, 00h ; Check if we are at end of string (0 = end of string) | |
je .done ; If AL is 0 then jump to done label | |
int 10h ; BIOS interrupt 10h (0x10 or 16 in decimal) | |
jmp .repeat ; Continue to next character in the string | |
.done: | |
pop ax ; Restore the value to the AX register | |
ret ; Return to caller location | |
;------------------------------------------------------------------------------ | |
; Boot loaders are 512 bytes in size so pad the remaining bytes with 0 | |
;------------------------------------------------------------------------------ | |
times 510-($-$$) db 0 ; Pad (510 - current position) bytes of 0 | |
dw 0xAA55 ; Boot sector code trailer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
print_char: | |
push ax ; Save the state of our AX register | |
push cx ; Save the CX register (due to int 10h clobbering) | |
mov al, ah ; AL is used for the character to print | |
mov bl, 01h ; BLUE TEXT!!! | |
mov ah, 0Eh ; Teletype BIOS interrupt function | |
int 10h ; BIOS interrupt 10h (0x10 or 16 in decimal) | |
pop cx ; Restore the state of our CX register | |
pop ax ; Restore the state of our AX register | |
ret ; Return to caller location |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BITS 16 ; Instruct the system this is 16-bit code | |
; This is the entry point, nothing should happen before this | |
; other than setting the instruction size | |
main: | |
mov ax, 07C0h ; Setup 4KB stack space after this bootloader | |
add ax, 288 ; (4096+515) / 16 bytes (aligned) per paragraph | |
cli ; Disable interrupts (solvs old DOS bug) | |
mov ss, ax ; Assign current stack segment | |
mov sp, 4096 ; Setup our stack pointer | |
sti ; Enable interrupts (solvs old DOS bug) | |
mov ax, 07C0h ; 07C0h is where our program is located | |
mov ds, ax ; Set data segment to the load point of our program | |
call run ; Start the main loop | |
;------------------------------------------------------------------------------ | |
; Constants | |
;------------------------------------------------------------------------------ | |
s_hi db "Hello, World!", 0Dh, 0Ah, "- Brent", 0Dh, 0Ah, 00h | |
s_nl db 0Dh, 0Ah, 00h | |
;------------------------------------------------------------------------------ | |
; The main loop of our program | |
;------------------------------------------------------------------------------ | |
run: | |
mov si, s_hi ; Set our SI register to hello message pointer | |
call print ; Call our print subroutine | |
mov ah, 09h ; Set the AH register to 9 so we can print it | |
call ah_to_str ; This should output 00001001 to the screen | |
.loop: | |
jmp .loop ; Infinite loop to hold control of the computer | |
;------------------------------------------------------------------------------ | |
; Debug printing of bytes | |
;------------------------------------------------------------------------------ | |
ah_to_str: | |
push ax ; Save the state of our AX register | |
push cx ; Save the state of our CX register | |
mov ch, 80h ; Set bit flag for AND as 10000000 | |
mov al, ah ; Copy AH to AL so we can change AH | |
.ah_to_str_loop: | |
mov ah, al ; Restore original value of AH | |
and ah, ch ; Get the bit value for printing | |
test ah, ah ; Check to see if the bit is zero or 1 | |
je .ah_to_str_zero ; The bit was 0 so jump to print 0 | |
mov ah, 31h ; The bit was 1 so set AH to ascii 1 | |
jmp .ah_to_str_print ; Jump to print the character | |
.ah_to_str_zero: | |
mov ah, 30h ; The bit was 0 so set AH to ascii 0 | |
.ah_to_str_print: | |
call print_char ; Call our print_char routine below | |
SHR ch, 01h ; Shift CH right by 1 (0100000 first time) | |
cmp ch, 00h ; Check to see if we shifted all the way | |
jne .ah_to_str_loop ; If we haven't finished, return to loop | |
pop cx ; Restore the state of our CX register | |
pop ax ; Restore the state of our AX register | |
ret ; Return to caller location | |
print_char: | |
push ax ; Save the state of our AX register | |
push cx ; Save the CX register (due to int 10h clobbering) | |
mov al, ah ; AL is used for the character to print | |
mov ah, 0Eh ; Teletype BIOS interrupt function | |
mov bl, 0Fh ; Don't worry about me until the end of this guide | |
int 10h ; BIOS interrupt 10h (0x10 or 16 in decimal) | |
pop cx ; Restore the state of our CX register | |
pop ax ; Restore the state of our AX register | |
ret ; Return to caller location | |
;------------------------------------------------------------------------------ | |
; Print string subroutine (null terminated string print) | |
;------------------------------------------------------------------------------ | |
print: | |
push ax ; Save the current value of the AX register | |
mov ah, 0Eh ; Our first BIOS interrupt: Teletype output | |
mov bl, 0Fh ; Don't worry about me until the end of this guide | |
.repeat: | |
lodsb ; Load next character into AL register | |
cmp al, 00h ; Check if we are at end of string (0 = end of string) | |
je .done ; If AL is 0 then jump to done label | |
int 10h ; BIOS interrupt 10h (0x10 or 16 in decimal) | |
jmp .repeat ; Continue to next character in the string | |
.done: | |
pop ax ; Restore the value to the AX register | |
ret ; Return to caller location | |
;------------------------------------------------------------------------------ | |
; Boot loaders are 512 bytes in size so pad the remaining bytes with 0 | |
;------------------------------------------------------------------------------ | |
times 510-($-$$) db 0 ; Pad (510 - current position) bytes of 0 | |
dw 0xAA55 ; Boot sector code trailer |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment