VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I'm currently using the Dosbox int10_modes.cpp to set the mode for all graphics modes (with some table changes for modes incorrectly set).

I have the current settings set to this:

VideoModeBlock ModeList_VGA[0x14] = {  //VGA Modelist!
/* mode ,type ,sw ,sh ,tw ,th ,cw,ch ,pt,pstart ,plength,htot,vtot,hde,vde special flags */
{ 0x000, M_TEXT, 360, 400, 40, 25, 9, 16, 8, 0xB8000, 0x0800, 50, 449, 40, 400, _EGA_HALF_CLOCK },
{ 0x001, M_TEXT, 360, 400, 40, 25, 9, 16, 8, 0xB8000, 0x0800, 50, 449, 40, 400, _EGA_HALF_CLOCK },
{ 0x002, M_TEXT, 720, 400, 80, 25, 9, 16, 8, 0xB8000, 0x1000, 100, 449, 80, 400, 0 },
{ 0x003, M_TEXT, 720, 400, 80, 25, 9, 16, 8, 0xB8000, 0x1000, 100, 449, 80, 400, 0 },
{ 0x004, M_CGA4, 320, 200, 40, 25, 8, 8, 1, 0xB8000, 0x4000, 50, 449, 40, 400, _EGA_HALF_CLOCK | _EGA_LINE_DOUBLE },
{ 0x005, M_CGA4, 320, 200, 40, 25, 8, 8, 1, 0xB8000, 0x4000, 50, 449, 40, 400, _EGA_HALF_CLOCK | _EGA_LINE_DOUBLE },
{ 0x006, M_CGA2, 640, 200, 80, 25, 8, 8, 1, 0xB8000, 0x4000, 100, 449, 80, 400, _EGA_HALF_CLOCK | _EGA_LINE_DOUBLE },
{ 0x007, M_TEXT, 720, 400, 80, 25, 9, 16, 8, 0xB0000, 0x1000, 100, 449, 80, 400, 0 },

{ 0x00D, M_EGA, 320, 200, 40, 25, 8, 8, 8, 0xA0000, 0x2000, 50, 449, 40, 400, _EGA_HALF_CLOCK | _EGA_LINE_DOUBLE },
{ 0x00E, M_EGA, 640, 200, 80, 25, 8, 8, 4, 0xA0000, 0x4000, 100, 449, 80, 400, _EGA_LINE_DOUBLE },
{ 0x00F, M_EGA, 640, 350, 80, 25, 8, 14, 2, 0xA0000, 0x8000, 100, 449, 80, 350, 0 },/*was EGA_2*/
{ 0x010, M_EGA, 640, 350, 80, 25, 8, 14, 2, 0xA0000, 0x8000, 100, 449, 80, 350, 0 },
{ 0x011, M_EGA, 640, 480, 80, 30, 8, 16, 1, 0xA0000, 0xA000, 100, 525, 80, 480, 0 },/*was EGA_2 */
{ 0x012, M_EGA, 640, 480, 80, 30, 8, 16, 1, 0xA0000, 0xA000, 100, 525, 80, 480, 0 },
{ 0x013, M_VGA, 320, 200, 40, 25, 8, 8, 1, 0xA0000, 0x2000, 100, 449, 80, 400, _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE }
}; //VGA Modelist!

The rest of the tables are set the same as Dosbox.

Also, I've changed CRTC Mode Control to 0xA2, which should be the correct value (word mode, not byte mode?). I've also enabled odd/even mode: it's a CGA mode, which uses odd/even maps? Dosbox sets this incorrectly?

Now I'm getting output with 2 times the screen height and width. The top-left screen contains the full written output, the other 3 quarters of the active display area contain invalid output.

Should I remove the _EGA_HALF_CLOCK setting? We have 640 pixels horizontally, not 320 pixels to convert to 640 pixels?

Do I need to change more of the int10_modes.cpp to get this working on a real VGA? The scanline doubling doesn't seem enough for vertical output to fill the screen?

Anyone knows how to get the Dosbox mode 6h working on a REAL VGA?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 3, by SarahWalker

User metadata
Rank Member
Rank
Member

CRTC Mode Control should be 0xC2. I'm not familiar with how DOSbox defines modes but I believe _EGA_HALF_CLOCK should be removed. _EGA_LINE_DOUBLE should be correct.

Reply 2 of 3, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've changed the CRTC mode control to 0xC2 and removed the _EGA_HALF_CLOCK option from mode 6h. I'll check this once I have the time to compile it and check the results.

Edit: I've found the error: The VRAM window used by the CPU works in an odd way:

OPTINLINE void decodeCPUaddress(byte towrite, uint_32 offset, byte *planes, uint_32 *realoffset)
{
if (ActiveVGA->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.Chain4Enable) //Chain 4 mode?
{
*realoffset = offset; //Original offset to start with!
offset &= 0x3; //Walk through the planes!
*planes = (1 << offset); //Lower bits, create bitmask!
*realoffset >>= 2; //Rest of the bits. Multiples of 4 wont get written!
return; //Done!
}
if (ActiveVGA->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.OddEvenMode) //Odd/Even mode?
{
//Odd/even mode used (compatiblity case)?
//Do the same as VPC!
register byte calcplanes;
register uint_32 newoffset;
newoffset = offset; //Take the default offset!
newoffset &= 0xFFFE; //Take the offset within the plane!
if (ActiveVGA->registers->GraphicsRegisters.REGISTERS.MISCGRAPHICSREGISTER.EnableOddEvenMode) //Chain using A0 selected? 0=0/2, 1=1/3!
{
calcplanes = offset;
calcplanes &= 1; //Take 1 bit to determine the plane (0/1)!
}
else //Normal operations?
{
calcplanes = 0; //The plane calculated is always 0!
newoffset |= (offset & 1); //Linear!
}
calcplanes = (0x5 << calcplanes); //Convert to used plane (0/2 or 1/3)!
*planes = calcplanes; //Load the planes to address!
*realoffset = newoffset; //Load the offset to address!
return; //Done!
}

if (towrite) //Writing access?
{
*planes = 0xF; //Write to all planes possible, map mask register does the rest!
}
else
{
*planes = 1; //Load plane 0!
*planes <<= ActiveVGA->registers->GraphicsRegisters.REGISTERS.READMAPSELECTREGISTER.ReadMapSelect; //Take this plane!
}
*realoffset = offset; //Direct offset into VRAM!
//The offset is used directly!
}

Anyone can confirm this? I've based it on: https://01.org/linuxgraphics/sites/default/fi … _vol3_part1.pdf

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 3 of 3, by superfury

User metadata
Rank l33t++
Rank
l33t++

Anyone knows how the VGA's byte/word/doubleword mode is applied? Is the address in VRAM shifted left, or is the address to be used as a plane offset shifted left?

Current CPU decoding window code:

word addresswrap(word offset)
{
//word address2;
//address2 = memoryaddress; //Load the address for calculating!
if (ActiveVGA->precalcs.BWDModeShift == 1) //Word mode?
{
if (ActiveVGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.AW) //MA15 has to be on MA0
{
//address2 >>= 15;
offset &= 0x3FFF; //Wrap around 16KB!
}
}
/*else //MA13 has to be on MA0?
{
address2 >>= 13;
}*/
//address2 &= 1; //Only load 1 bit!
//result &= 0xFFFE; //Clear bit 0!
//result |= address2; //Add bit MA15 at position 0!
return offset; //Give the result!
}

/*

The r/w operations from the CPU!

*/

//decodeCPUaddress(Write from CPU=1; Read from CPU=0, offset (from VRAM start address), planes to read/write (4-bit mask), offset to read/write within the plane(s)).
OPTINLINE void decodeCPUaddress(byte towrite, uint_32 offset, byte *planes, uint_32 *realoffset)
{
if (ActiveVGA->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.Chain4Enable) //Chain 4 mode?
{
*realoffset = offset; //Original offset to start with!
offset &= 0x3; //Walk through the planes!
*planes = (1 << offset); //Lower bits, create bitmask!
*realoffset >>= 2; //Rest of the bits. Multiples of 4 wont get written!
*realoffset <<= ActiveVGA->precalcs.BWDModeShift; //Apply memory address size!
*realoffset = addresswrap(*realoffset); //
return; //Done!
}
if (ActiveVGA->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.OddEvenMode) //Odd/Even mode?
{
//Odd/even mode used (compatiblity case)?
//Do the same as VPC!
register byte calcplanes;
register uint_32 newoffset;
newoffset = offset; //Take the default offset!
if (ActiveVGA->registers->GraphicsRegisters.REGISTERS.MISCGRAPHICSREGISTER.EnableOddEvenMode) //Chain using A0 selected? 0=0/2, 1=1/3!
{
calcplanes = offset;
calcplanes &= 1; //Take 1 bit to determine the plane (0/1)!
}
else //Normal operations?
{
calcplanes = 0; //The plane calculated is always 0!
newoffset |= (offset & 1); //Linear!
}
newoffset &= 0xFFFE; //Take the offset within the plane!
newoffset <<= ActiveVGA->precalcs.BWDModeShift; //Apply memory address size!
Show last 22 lines
		newoffset = addresswrap(newoffset); //Perform address wrap!
calcplanes = (0x5 << calcplanes); //Convert to used plane (0/2 or 1/3)!
*planes = calcplanes; //Load the planes to address!
*realoffset = newoffset; //Load the offset to address!
return; //Done!
}

//Planar access?
if (towrite) //Writing access?
{
*planes = 0xF; //Write to all planes possible, map mask register does the rest!
}
else
{
*planes = 1; //Load plane 0!
*planes <<= ActiveVGA->registers->GraphicsRegisters.REGISTERS.READMAPSELECTREGISTER.ReadMapSelect; //Take this plane!
}
*realoffset = offset; //Direct offset into VRAM!
*realoffset <<= ActiveVGA->precalcs.BWDModeShift; //Apply memory address size!
*realoffset = addresswrap(*realoffset);
//The offset is used directly!
}

Anyone knows if this is correct?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io