Finding x,y pixel address in mode 13h VRAM?

I'm currently working with linear VRAM (a buffer with 256KB memory, divided into four 64k planes, so plane 0 at 0x00000, plane 1 at 0x10000, plane 2 at 0x20000, plane 3 at 0x30000). Just add the index of the plane to that for the full address in VRAM.

I'm still wondering how to get a specific pixel from VRAM (x,y coordinate) when doing graphic modes (none color modes work, only the black/white pixels (1-bit) graphic mode works).

Anyone knows how I can get specific pixels from the VGA VRAM (having linear access described above) using Shift Register Interleave mode (VGA modes 4&5), 16-bit planar mode (Most VGA modes) etc.
You have to grab the individual bits from each spot and assemble the pixel yourself.

Address of pixel in plane = (bytes_per_line * y) + (x % 8);
bytes_per_line depends on the video mode.


Uh, wait... why are you going on about planes if you are only using HGC modes?


Perhaps you ought to explain exactly what you want to accomplish before I go get my VGA book.

[edit] The title of your post also says "mode 13h", which is a 256-color mode and does not use planes. Unless you are playing with a mode-X.
Last edited on
I'm currently working on emulating VGA VRAM access for mode 13h operations. Also still working on the 4-color modes. I'm trying to get it working like an actual VGA.

Is that bytes_per_line just the offset register, or the offset register multiplied by 2, multiplied by the VRAM memory address size (1,2 or 4)? At the moment the address in VRAM is calculated by taking the Start Address register (together 16-bit), adding (Offset Register * VRAM memory address size(1, 2 or 4) * 2)*y, finally adding x for the offset in linear VRAM.

The actual layout used is described above (during planar access by the CPU example: so plane 0 offset 100 is at 0x100, plane 1 offset 100 is at 0x10100, plane 2 offset 100 is at 0x20100, plane 3 offset 100 is at 0x30100).
Ah, well, you need to study up quite a bit more. Here's a good place to start.
http://wiki.osdev.org/VGA_Hardware


Remember, mode 13H is the 256-color mode. It is a chained mode, so you don't need to worry about planes when using it, but you very much do need to worry about planes when doing proper emulation, particularly as you'll want to support the X modes.


It has been a very long time since I've played with VGA hardware directly, so I don't remember all the little bits and details, and I don't care enough to run for my book just to be someone's encyclopaedia. But IIRC, the meaning of the offset register's contents depends on the video mode. When I say bytes_per_line I mean the number of bytes per raster in the display plane, as mapped to the VRAM addresses.

Good luck! Make sure to click the link. There are other people who have done what you are doing, and there are links to existing projects you might want to take a look at.
I've found out that my emulator is missing the support for the MAP13, MAP14 and AW bits of the CRTC Mode Control Register.

Is this correct?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
uint_32 patch_map1314(VGA_Type *VGA, uint_32 vram_addr, uint_32 rowscancounter, uint_32 rowscanaddress) //Patch full VRAM address!
{
uint_32 result = vram_addr; //Default: VRAM addr!
if (!VGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.MAP13) //Map row scan address bit 0=Memory address bit 13?
{
	result = (result&(~0x2000))|((rowscanaddress&1)<<13); //Use row scan counter bit 0 for bit 13!
}

if (!VGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.MAP14) //Map row scan address bit 0=Memory address bit 13?
{
	result = (result&(~0x4000))|((rowscancounter&2)<<13); //Use row scan counter bit 0 for bit 13!
}

return result; //Give the linear address!
}

uint_32 addresswrap(VGA_Type *VGA, uint_32 memoryaddress) //Wraps memory arround 64k!
{
if (VGA->precalcs.VRAMmemaddrsize==2) //Word mode?
{
if (!VGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.AW) //Appear as if only 64k memory is present?
{
return (memoryaddress&0xFFFF); //Map to 64K!
}
}
return memoryaddress; //Normal operating mode!
}


BTW precalcs.VRAMmemaddrsize is 1,2 or 4, depending on the Byte/Word and DWord addressing mode of the CRT Mode control register.

Code for retrieving pixel from VRAM:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
byte VGA_getpixel(VGA_Type *VGA, int x, int y)
{
	word vramstart = ((VGA->registers->CRTControllerRegisters.REGISTERS.STARTADDRESSHIGHREGISTER<<8)|VGA->registers->CRTControllerRegisters.REGISTERS.STARTADDRESSLOWREGISTER); //Start address of VRAM display!
	
	uint_32 offset; //The offset!
	byte bit; //The bit we need!

	if (VGA->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.Color256ShiftMode) //256-color mode?
	{
		//TODO!
		offset = getVRAMScanlineStart(VGA,y)+x; //The full offset (in pixels)!
		byte plane = offset%4; //The plane we use!
		offset /= 4; //The offset within the plane!

		uint_32 fulloffset = vramstart+(plane*0x10000)+offset; //Full offset within the correct plane!

		if (VGA->precalcs.VRAMmemaddrsize==2) //Word mode?
		{
			if (!VGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.AW) //Appear as if only 64k memory is present?
			{
				fulloffset &= 0xFFFF; //Force plane #0 (65k mem)
			}
		}
		
		return readVRAMdirect(VGA,0,patch_map1314(VGA,addresswrap(VGA,fulloffset),y,offset)); //The full offset of the plane!
	}
	else if (VGA->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.ShiftRegisterInterleaveMode) //Shift Register Interleave mode?
	{
		//TODO!
		uint_32 planeindex = getVRAMScanlineStart(VGA,y)+(x/8); //The full offset (in pixels)!
		byte planebase = (x/4)%2; //Base plane (0/1)! OK!
		uint_32 scanlinestart = 0; //Default: no scanline start!
		byte planelow = readVRAMdirect(VGA,0,patch_map1314(VGA,addresswrap(VGA,vramstart+scanlinestart+(planebase*0x10000)+planeindex),y,planeindex)); //Lower plane: OK!
		byte planehigh = readVRAMdirect(VGA,0,patch_map1314(VGA,addresswrap(VGA,vramstart+scanlinestart+((planebase+2)*0x10000)+planeindex),y,planeindex)); //Higher plane: OK!
		byte shift = 6-((x%4)*2); //OK!
		byte bitmask = 3<<shift; //The bitmask for the lower&higher planes: OK!
		return ( //This should be OK!
			((planelow&bitmask)>>shift)|
			(((planehigh&bitmask)>>shift)<<2)
			); //Give the VRAM value of the specified pixel!
	}
	else
	{
		//Should be OK?
		byte result;
		offset = (getVRAMScanlineStart(VGA,y)+((x/8)*getVRAMMemAddrSize(VGA))); //Offset!
		bit = 7-(x%8); //The bit in the byte!
		//16-color mode!
		result = (getBitPlaneBit(VGA,vramstart,0,offset,bit)| //Bit0
			(getBitPlaneBit(VGA,vramstart,1,offset,bit)<<1)| //Bit1
			(getBitPlaneBit(VGA,vramstart,2,offset,bit)<<2)| //Bit2
			(getBitPlaneBit(VGA,vramstart,3,offset,bit)<<3)); //Bit3
		if (!VGA->registers->ExternalRegisters.MISCOUTPUTREGISTER.IO_AS) //Monochrome mode uses only plane 0?
		{
			result &= 0x1; //Only bit0!
		}
		return result; //Give the result!
	}
}
Last edited on
Topic archived. No new replies allowed.