I am currently making my own operating system. As I will be going into 32bit mode at some point, I am going to need to print to the screen without interrupts as they won't exist.
Here is my code so far:
org 0x7c00 ; add to offsets
xor ax, ax ; make it zero
mov ds, ax ; ds=0
mov ss, ax ; stack starts at 0
cld
mov ax, 0xB800 ; Ax = address of video memory
mov es, ax
xor di, di
mov si, msg ; load msg into si
call print ; call thr print function
hlt
print:
mov ah, 07h
printchar:
lodsb ; Hear we load a letter from si
stosw
cmp al, 0
je done
jmp printchar
done:
ret ; return
msg db "Hello, World", 0 ; msg = 'test'
xpos db 0
ypos db 0
times 510-($-$$) db 0 ; make sure file is 510 bytes in size
dw 0xaa55 ; write boot signiture
When looking at the documentation, I know that to set the position of the character, I have to get position = (y_position * characters_per_line) + x_position;
.
The only problem is, it doesn't seem to work. Even if I add one to the address so it is 0xB801
, it does not move the text by one character. Instead, I get this: .
What is going on here and how am I meant to print a character on a new line and also increment the x position by one?
Characters in VGA text mode are 2 bytes; one for the character and one for the attributes. +1 bytes is not the start of a character.
But you're not adding 1 to the address, you're adding 1 to the segment base (0xB801
), so you're going forward 16 bytes or 8 characters relative to the 0,0 position at the start of VGA memory at linear address 0xB8000.
One character forward would be add di,2
, because your current code is using es:di to store into VGA memory. (Or start with mov di,2
instead of zeroing it.)
You wouldn't have to deal with segmentation if you switched to 32-bit protected mode with a flat 32-bit address space. You're not using any BIOS calls now, so you could.