Reputation: 21
I apologize in advance if this question seems slightly stupid...
I'm currently developing a simple 16 bit real mode OS using x86 assembly(NASM) with Ubuntu Mate Linux 16.04.3 LTS as my development platform and Virtualbox for debugging the system. The bootloader and underlying kernel code written so far are working fine, however I seem to have run into some issues with the graphics code I'm writing. I've switched into 640x480x256 resolution SVGA via INT10h:
Services.screen_textmode.enter_svga:
pusha
mov ax, 4F02h
mov bx, 101h
int 10h
popa
ret
Control then get's transferred back to the kernel which saves the color of the pixels for the next function(the one I'm having trouble with) in the dl register and calls the function:
mov dl, 2
call Services.svga.draw_background
Now the problem that I'm having is when the following code is run, every time a video memory bank is switched it seems to obscure the byte that the dl register is holding and that changes the color of each bank, or the entire screen is solid black. Here is the code:
Services.svga.draw_background:
pusha
xor cx, cx
xor dx, dx
mov word [svga_bank], dx
mov ax, 0A000h
mov es, ax
.start_bank:
mov di, cx
mov [es:di], dl
.finish_bank:
inc cx
mov di, cx
mov [es:di], dl
cmp cx, 65535
je .switch_bank
jmp .finish_bank
.switch_bank:
xor cx, cx
mov word dx, [svga_bank]
inc dx
mov word [svga_bank], dx
push ax
push bx
mov ax, 4F05h
xor bx, bx
int 10h
pop ax
pop bx
cmp dx, 5
je .done
jmp .start_bank
.done:
popa
ret
The idea behind why I want dl set before the Services.svga.draw_background function runs is that the OS will eventually be able to load configuration files that will set up the color scheme for applications and menus, making the system more customizable.
I've tried everything: different ways I've found for bank switching, directly setting dl in .start_bank, etc. Nothing is working and I can't find anything after exhaustive research. Apparently if I don't store the value of dx during bank switching it never changes even though the instruction "inc dx" is present which causes the system to enter an infinite loop, and when bank switching is working properly the act of changing the value of dx somehow changes the value of dl as well... Does anyone know how to fix this?
Upvotes: 2
Views: 827
Reputation: 39166
Because DL
is already part of DX
you can't at the same time use DL
to hold the color and use DX
to hold the bank number. This was already noticed by Jester
Your effort to put the color in the BL
register instead, also failed because of an additional problem in the Services.svga.draw_background routine.
push ax push bx mov ax, 4F05h xor bx, bx int 10h pop ax pop bx
This snippet does not correctly restore the registers! The pop
's need to be in the reverse order to the push
's.
push ax
push bx
...
pop bx
pop ax
xor dx, dx mov word [svga_bank], dx
It's not enough to move zero in this svga_bank variable and start writing to the 1st bank. The physical bank selection could point to any other bank. e.g. at the end of this Services.svga.draw_background routine the physical bank is at 5, a bank number that's not even valid (valid range here is [0,4])!
I've written this for your convenience. I've put the color in CL
.
Services.svga.draw_background:
pusha
push ds
mov ax, 0A000h
mov ds, ax ; DS:DI is start of video
xor di, di
mov ch, cl ; CL holds the color [0,255]
xor dx, dx ; Initial bank
.again:
mov ax, 4F05h ; VESA.SelectBank 0, 1, 2, 3
xor bx, bx
int 10h
.color:
mov [di], cx
add di, 2
jnz .color
inc dx
cmp dx, 4
jb .again
mov ax, 4F05h ; VESA.SelectBank 4
xor bx, bx
int 10h
.LastBank:
mov [di], cx
add di, 2
cmp di, 45056
jb .LastBank
pop ds
mov word [svga_bank], dx
popa
ret
A resolution of 640 x 480 gives 307200 bytes. That's 4 times 65536 bytes and a leftover of 45056 bytes.
Tip
You can speed this up by writing dwords (ECX
) instead of words (CX
)!
Upvotes: 2