2
votes

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?

1
"changing the value of dx somehow changes the value of dl as well" - you know that dl is the low 8 bits of dx, right?Jester
No, I didn't. I apologize again... If you can't tell, I'm still very much a noob with asm. At the risk of sounding even more noobish, it seems that if I switch from using dl to bl, I get the same color across the screen, just in every other bank(bank 0: the color I'm looking for, bank 2: black, bank 3: my color, etc). I will have to do some more testing, but thank you for pointing that out to me.Zach Parker
possible duplicate (if this misunderstanding was your main bug): x86 Calculating AX given AH and AL? shows AX breaks down into AH:AL, and same for BX,CX,DX.Peter Cordes

1 Answers

2
votes

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)!