baby steps #2 - bios print
Posted: Sun May 19, 2002 12:39 pm
Quick review: (1) boot sector loaded by BIOS is 512 bytes (2) the code in the boot sector of the disk is loaded by the BIOS at 0000:7c00 (3) machine starts in real mode (4) be aware that the CPU is being interrupted unless you CLI
**************
Many (but not all) BIOS interrupts expect DS to be filled with a real-mode segment value. This is why many BIOS interrupts won't work in protected mode. So if you want to use int 10h/ah=0eh to print to the screen, then you need to make sure that your seg:offset for the characters to print is correct.
It doesn't matter if you use 0000:7c00 or 07c0:0000, but if you use ORG, you need to be aware of what's happening.
;------------------------
mov ax, 0x07c0
mov ds, ax
mov si, msg
ch_loop:lodsb
or al,al ;zero=end of str
jz hang ;get out
mov ah,$0e
int $10
jmp ch_loop
hang:
jmp hang
msg db 'Welcome to Macintosh', 13, 10, 0
times 512-($-$$) db 0
;------------------------
Here's the ORG version. Note that you still need to tell DS what to be
;------------------------
[ORG 0x7c00]
xor ax, ax ;make it zero
mov ds, ax
mov si, msg
ch_loop:lodsb
or al,al ;zero=end of str
jz hang ;get out
mov ah,$0e
int $10
jmp ch_loop
hang:
jmp hang
msg db 'Welcome to Macintosh', 13, 10, 0
times 512-($-$$) db 0
;------------------------
New topic: Typically 'procedures' are separated from the code using CALL/RET like he following
;------------------------
[ORG 0x7c00]
xor ax, ax ;make it zero
mov ds, ax
mov si, msg
call bios_print
hang:
jmp hang
msg db 'Welcome to Macintosh', 13, 10, 0
bios_print:
lodsb
or al,al ;zero=end of str
jz done ;get out
mov ah,$0e
int $10
jmp bios_print
done:
ret
times 512-($-$$) db 0
;------------------------
For some inexplicable reason, loading SI *then* jumping to the procedure lways bugged me. Fortunately for psychos like me NASM's macros let you retend that you are passing a parameter (macro definition has to go before t's being called).
;------------------------
%macro BiosPrint 1
mov si, word %1
ch_loop:lodsb
or al,al ;zero=end of str
jz done ;get out
mov ah,$0e
int $10
jmp ch_loop
done:
%endmacro
[ORG 0x7c00]
xor ax, ax ;make it zero
mov ds, ax
BiosPrint msg
hang:
jmp hang
msg db 'Welcome to Macintosh', 13, 10, 0
times 512-($-$$) db 0
;------------------------
And in case your code is becoming long and unreadable, you can break it up into ifferent files, then include the files at the beginning of your main code. Like o:
;------------------------
jmp main
%include "othercode.inc"
main:
;... rest of your code here
;------------------------
**************
Many (but not all) BIOS interrupts expect DS to be filled with a real-mode segment value. This is why many BIOS interrupts won't work in protected mode. So if you want to use int 10h/ah=0eh to print to the screen, then you need to make sure that your seg:offset for the characters to print is correct.
It doesn't matter if you use 0000:7c00 or 07c0:0000, but if you use ORG, you need to be aware of what's happening.
;------------------------
mov ax, 0x07c0
mov ds, ax
mov si, msg
ch_loop:lodsb
or al,al ;zero=end of str
jz hang ;get out
mov ah,$0e
int $10
jmp ch_loop
hang:
jmp hang
msg db 'Welcome to Macintosh', 13, 10, 0
times 512-($-$$) db 0
;------------------------
Here's the ORG version. Note that you still need to tell DS what to be
;------------------------
[ORG 0x7c00]
xor ax, ax ;make it zero
mov ds, ax
mov si, msg
ch_loop:lodsb
or al,al ;zero=end of str
jz hang ;get out
mov ah,$0e
int $10
jmp ch_loop
hang:
jmp hang
msg db 'Welcome to Macintosh', 13, 10, 0
times 512-($-$$) db 0
;------------------------
New topic: Typically 'procedures' are separated from the code using CALL/RET like he following
;------------------------
[ORG 0x7c00]
xor ax, ax ;make it zero
mov ds, ax
mov si, msg
call bios_print
hang:
jmp hang
msg db 'Welcome to Macintosh', 13, 10, 0
bios_print:
lodsb
or al,al ;zero=end of str
jz done ;get out
mov ah,$0e
int $10
jmp bios_print
done:
ret
times 512-($-$$) db 0
;------------------------
For some inexplicable reason, loading SI *then* jumping to the procedure lways bugged me. Fortunately for psychos like me NASM's macros let you retend that you are passing a parameter (macro definition has to go before t's being called).
;------------------------
%macro BiosPrint 1
mov si, word %1
ch_loop:lodsb
or al,al ;zero=end of str
jz done ;get out
mov ah,$0e
int $10
jmp ch_loop
done:
%endmacro
[ORG 0x7c00]
xor ax, ax ;make it zero
mov ds, ax
BiosPrint msg
hang:
jmp hang
msg db 'Welcome to Macintosh', 13, 10, 0
times 512-($-$$) db 0
;------------------------
And in case your code is becoming long and unreadable, you can break it up into ifferent files, then include the files at the beginning of your main code. Like o:
;------------------------
jmp main
%include "othercode.inc"
main:
;... rest of your code here
;------------------------