Page 1 of 1

plot pixels without BIOS

Posted: Sun Aug 19, 2012 12:00 pm
by GAT
I've been trying to write a function in real mode x86 asm for video mode 12h that, given an x and y value and a color, could plot a pixel on the screen without using BIOS.
I've searched, and there is code out there to do it, but it is optimized or crufted up in such a way that I can't understand it or use it. Could anyone give me a hand?

Re: plot pixels without BIOS

Posted: Sun Aug 19, 2012 12:19 pm
by turdus
GAT wrote:I've been trying to write a function in real mode x86 asm that, given an x and y value and a color, could plot a pixel on the screen without using BIOS.
I've searched, and there is code out there to do it, but it is optimized or crufted up in such a way that I can't understand it or use it. Could anyone give me a hand?
http://wiki.osdev.org/Getting_VBE_Mode_Info will return all information required to manually plot a pixel.

Re: plot pixels without BIOS

Posted: Sun Aug 19, 2012 12:40 pm
by GAT
But I'm not in VBE mode, I'm in video mode 12h (realized I left that out, amending).

Re: plot pixels without BIOS

Posted: Sun Aug 19, 2012 12:57 pm
by bluemoon
Check the video mode info on how the pixel buffer formatted, and plot pixel by the mov instruction.
for plotting on mode 12h (640x480, 16 color) on real mode, you need to work on bank switching.

Check VGA_Hardware for detail.

Re: plot pixels without BIOS

Posted: Sun Aug 19, 2012 3:33 pm
by DavidCooper
The whole screen is accessible within a single segment, but you can think of writes to it as affecting four different levels of memory (planes) at the same time instead of just one. This means that writing what appears to be a single byte of screen memory is actually able to write to up to four screen memory bytes at the same time. To control which of the four planes a write will affect, you have to set a register to select which planes are to be affected by writes (and reads). The address of that register is 3C5h. To select which bit(s) is/are written, you use the bitmask register at 3CFh.

Here's my routine for writing a pixel (sorry that it's in machine code rather than assembly language, but the comments explain it all). Bear in mind that I had to use trial and error to work it all out as all I knew at the time was what I've just told you in the paragraph above, so there may be a better way of doing it, but this certainly works:-

Code: Select all

[On entry, DI holds the screen address for the byte containing the required pixel, CL holds the bitmask value for the required pixel, and BL holds the required colour value.]

186 197 3 (DX = 3C5h, the port address of the plane-selection register)
176 15 (AL = 0Fh)
238 (out - the value 0Fh is sent to the plane-selection register to select all four planes)
138 7 (read byte of screen memory using the screen address in DI)
[The above step seems to be necessary to preserve the bits you aren't trying to change.]
178 207 (DL = CFh, so DX now holds the port address of the bitmask register)
145 (move value from CL to AL - this is the bitmask value to select which bit is to be written)
238 (out)
176 0 (AL = 0)
136 7 (write 0 to screen to clear whatever was there in all four planes for that pixel)
178 197 (DL = C5h, so DX holds the port address of the plane-selection register again)
147 (move BL to AL - this is the colour value which will select which planes are written to)
238 (out - the register is now set to enable only the planes required for that colour)
176 255 (AL = FFh)
136 7 (write FFh to screen - this value works for any colour and any pixel)
195 (ret).

Re: plot pixels without BIOS

Posted: Mon Aug 20, 2012 6:15 pm
by GAT
ok. So how do I calculate the bitmask.
I'd get the screen address with [0xA000:y*bytes_per_line + x*bytes_per pixel], right?
(Sorry for my ignorance of the topic)

Re: plot pixels without BIOS

Posted: Tue Aug 21, 2012 1:02 am
by Combuster
I'd get the screen address with [0xA000:y*bytes_per_line + x*bytes_per pixel], right?
Please read the links that have been posted - 16-color memory is all over the place, and it in turn causes arbitrary pixel writes to become the most annoying operation that exists: you have to read 4 locations in ram, and in each of them set or clear a specific bit to modify the pixel itself. Also, reading from video ram in 16-colour modes typically does not return the value you just wrote to it.

That said, David's method depends on VGA write modes and the corresponding internal circuitry to work. It is mostly optimal for setting a few random pixels with random colours, but is going to be awfully slow for setting many pixels. There's a complete description of write mode 0 on the very same wiki page where you can look up the terminology.

Re: plot pixels without BIOS

Posted: Tue Aug 21, 2012 2:13 pm
by DavidCooper
GAT wrote:ok. So how do I calculate the bitmask.
I'd get the screen address with [0xA000:y*bytes_per_line + x*bytes_per pixel], right?
(Sorry for my ignorance of the topic)
It's no longer about ignorance - this part of it is something you shouldn't have to ask about. Even so, if my method of doing it isn't the right one, abandon it now. Personally, I lost interest in this mode a long time ago, and there can't be many machines left working that don't have the ability to use a much better screen mode with more colours. Ask yourself seriously whether you really need to spend time writing new software for museum exhibits which will likely never even be switched on again.