2

I heard that int 10h, ah = 0Ch is pretty slow, and to get a reasonable speed I would need to go to the memory and put the value into the pixel I want to, I set my video mode to be 13h with int 10h. the call to change the video mode:

mov ah , 0
mov al , 13h
int 10h

and this is the procedure I wrote in order to put a pixel in the given coordinates:

drawFaster proc
    ; bp + 2 - row (dx)
    ; bp + 4 - column (cx)
    ; bp + 6 - color
    mov bp , sp
    pushad
    mov ax , 0A000h - presumably the memory address of the screen
    mov es , ax
    mov ax , [bp + 2]
    mov bx , [bp + 4]
    mov cx , 320
    mul cx

    add ax , bx
    mov di , ax
    mov ax , [bp + 6]

    mov [es:di] , al 

    popad
    ret 6
endp

code that calls the function:

    push bp
    mov ax , 30
    push ax
    mov cx , 50
    push cx
    mov dx , 50
    push dx
    call drawFaster
    pop bp

but for some reason, this yields no results, I don't know if the memory address is incorrect or if something else is. I need your help. Thanks!

The strange thing is that the following piece of code works

mov ax , 0A000H
mov es , ax
mov [es:0] , 30

but the following piece of code doesnt:

mov ax , 0A000H
mov bx , 0
mov es , ax
mov [es:bx] , 30
Guy Sudai
  • 217
  • 2
  • 12
  • 1
    The code to write to video memory looks right to me. Here are a couple things to check: 1) Check that the parameters are passed correctly. The comments mention registers as well as stack locations. If the pixel value [bp+6] is 0, that would be black. 2) Are you sure the color palette is set up the way you want? I would guess that the BIOS sets the palette to default values when you set the video mode, but I haven't found confirmation of that. – prl May 19 '18 at 23:17
  • 2
    A couple additional comments on the code: 1) It doesn't restore bp, which in most calling conventions is assumed to be preserved. 2) Please don't use pusha; only save the registers you need to, in this case bx, di, and bp, if you are using a typical calling convention. You could easily avoid using bx, to avoid having to preserve it. I think es probably should also be preserved. – prl May 19 '18 at 23:21
  • 1
    Are you sure about that address? See [this](https://retrocomputing.stackexchange.com/a/3054) which suggests it's B8000. – David Wohlferd May 20 '18 at 00:12
  • @DavidWohlferd: changing video mode apparently can change the VGA base to `0A0000h`. [Memory-Mapped Graphics Output](https://stackoverflow.com/q/33050699) – Peter Cordes May 20 '18 at 00:33
  • @PeterCordes is right (he usually is). For mode 13h (which OP specifies), a000 is the right address. Which makes me wonder what's in the word at `[bp + 6]`? And this is only going to write 1 pixel per call. Did OP look *really* close to see if it worked? – David Wohlferd May 20 '18 at 01:26
  • 2
    @DavidWohlferd : bp+6 is the color of the pixel(8-bit). I'm assuming he's using 320x200 which has 8 bit color. – Michael Petch May 20 '18 at 02:37
  • 1
    @PeterCordes Yes, but if he's passing "black", then everything would "work" but still "yield no results." – David Wohlferd May 20 '18 at 03:58
  • Can you show us the code that calls the procedure. In fact making this an [mcve] should help people figure this out. The function should work. – Michael Petch May 20 '18 at 04:59
  • I'm pretty sure int 10h, ah 13h makes it a 256 bit color @MichaelPetch – Guy Sudai May 20 '18 at 06:29
  • @prl I checked and they are passed correctly. and i've even tried hardcoding white in there just to make sure the color isn't the issue, and for the next time I won't use pusha if I don't need to, thanks for the tips! – Guy Sudai May 20 '18 at 06:30
  • @prl I restore bp in the functions I call drawFaster in, with push bp and pop bp – Guy Sudai May 20 '18 at 06:31
  • @MichaelPetch just edited the question now. Thanks for the feedback. – Guy Sudai May 20 '18 at 06:34
  • related: https://stackoverflow.com/a/38270279/4271923 not answering why your doesn't work (because it should), but it's verified working code (for NASM, unfortunately you look to be using commercial obsolete TASM), and also it may give you idea how to draw pixels directly in efficient way, your convoluted "draw pixel" with arguments passed through stack and `pusha/popa` is like 10-30x slower than optimized "draw some shape" variants writing several pixels in one go, with minimal setup per pixel. Your way will be only marginally faster than calling BIOS (although it will be faster). – Ped7g May 20 '18 at 06:58
  • Another example of the principle of moving initializations outside of loops and having minimal setup "per pixel" is here: https://stackoverflow.com/q/50425914/4271923 ... it's not verified my variant is correct (didn't bother to try myself, so confident I am), but if you will check just the general idea what the original code is trying to do, and what my code is trying to do, you should extract that principal idea how to avoid redundancy in asm code, and make it truly faster. The speed of asm code doesn't come from using asm instructions, but from minimizing the amount of work done by CPU. – Ped7g May 20 '18 at 07:03
  • BTW, if you are using turbo debugger for debugging this, be aware it doesn't save VRAM content by default, so whenever you switch between graphics mode, and the TD text UI, the VRAM gets cleared or corrupted. Set Options -> Display options -> Display swapping to **always**. Then checking the graphic screen through Alt+F5 should display at least pixels (with corrupted palette reset to default one every time). – Ped7g May 20 '18 at 07:05
  • @Ped7g yes I am debugging with tasm, I didn't know it doesnt swap display. Thanks! Ill try it again, just checked and it was on always – Guy Sudai May 20 '18 at 07:55
  • the strange thing is if i use `es:0` it works, but if I use `mov bx , 0` and then `es:bx` it doesnt. Any ideas? – Guy Sudai May 20 '18 at 08:10
  • that doesn't make sense, those two last examples should modify the same piece of memory, unless you have there some nasty typo (running something slightly different than in your question, where the code is correct), the problem is probably in a way how you evaluate "does/doesn't work" or some problem with your tools, but all of this sounds highly unlikely and "ridiculous". You may eventually try to set `es` to data segment, and put as first thing in data `fakescreen db 320*4 dup (0)` to have 320x4 fake screen in easy spot to check with TD, and check the code first there, then es=A000 for real. – Ped7g May 20 '18 at 08:32
  • I mean, this is getting to a point where one would need to see your screen/machine to get some idea what is going on, sorry, but your understanding how the things should work and how you write your code is spot on, it's not like you understand it completely wrong. Must be some tiny detail somewhere. :/ I have run out of ideas. – Ped7g May 20 '18 at 08:35
  • @Ped7g I thought it didn't make any sense either. But I resolved it with a workaround, not sure if it's a good answer but if it works. I'm pleased for now. I might try to change it later on. – Guy Sudai May 20 '18 at 08:36
  • Thanks for all of your help guys! I'm really thanksful for all of your help and advice! – Guy Sudai May 20 '18 at 08:37
  • your workaround is quite valid approach, I did use `ds=A000` sometimes too, when I was unable to write pixels with simple `movs/stos` or I was doing some more manipulation with them. It just doesn't explain your problems with other variants. Can you produce non-working example EXE/COM and upload it somewhere and put link here in comment? I may try in my own dosbox to see, if it will work for me. – Ped7g May 20 '18 at 08:41
  • a non-working example of what? – Guy Sudai May 20 '18 at 08:44
  • @fdsaddsa of the `mov [es:bx],30` "non working" executable... – Ped7g May 20 '18 at 09:11

1 Answers1

1

I found a workaround, but it is probably not the best way to go at it, instead of using es (because it doesnt work)

I changed the data segment's address to lead to 0A000H,

and then I change the pixel with mov [di] , al and it works!

But if you are trying this, be sure to move the data segment's address back to its original place.

my function in its working state, if anyone is interested:

drawFaster proc
    ; bp + 2 - row (dx)
    ; bp + 4 - column (cx)
    ; bp + 6 - color
    mov bp , sp ; changing bp to access the stack segment
    ; pushing the values to not lose them in the process of calling the function
    push ax
    push bx
    push cx
    push dx
    mov ax, 0A000h ; 0A000h is the video memory address (for some video modes like 13h)
    mov ds , ax
    mov ax , [bp + 2] ; getting the row ( Y )
    mov bx , [bp + 4] ; getting the column ( X )
    mov cx , 320 ; multiplying the row by 320 to get the offset, and then adding the column
    mul cx

    add ax , bx
    mov di , ax
    mov ax , [bp + 6] ; getting the desired color to paint the pixel in 
    mov [di] , al ; changing the color of the chosen pixel with the desired color
    ; changing the data segment's address back to its original state 
    ; VERY CRUCIAL PLEASE DON'T MISS THIS IF YOU DO IT THE SAME WAY
    mov ax , @data
    mov ds, ax
    ; changing the values back to what they were
    pop dx
    pop cx
    pop bx
    pop ax
    ret 6
endp
Guy Sudai
  • 217
  • 2
  • 12