VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

I'm currently using the following to decode access from the CPU to the VGA:

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 operations!
}
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!
}

I'm using the int10_modes.cpp from Dosbox-X and the plotting and text mode fonts of Dosbox.

For some reason I'm getting wrong output with text modes. Anyone knows why?

Also, what's the effect of the byte/word/doubleword modes on this?
Does realoffset need to be multiplied by 1, 2 or 4 depending on it? I'm getting text output with empty space between the characters. So instead of "x86EMU" it displays "x 8 6 E M U" etc.

Edit: This is now fixed. But for some reason the screen keeps repeating the first graphics/text line.

VGA_MMU contains the CPU memory window and related effects. VGA_IO the CPU I/O. VGA_Sequencer contains the rendering script and VGA_Precalcs contains the calculated values using when rendering (byte/word/dw modes too).

Anyone knows why the mode 13h is going wrong (multiple screens), also for some reason the first scanline (either character line or graphics pixel) is repeated for the whole screen? All other modes (text mode and graphics modes up to 12h) are working correctly.

The attachment VGA_20150401_1957.zip is no longer available

Edit:
It seems that there's two byte/word/doubleword settings:

- The CRTC Mode Control's byte/word mode and Underline Location's Doubleword setting combine into byte/word/doubleword mode. The combine into a shift left by 0, 1 or 2?
- The CRTC Mode Control's Divide Memory Address by 2 and Underline Location's Divide Memory Address by 4. These combine into divide by 1, 2 or 4?

Anyone knows how these two combine during CPU reads/writes and how they combine/affect rendering? These two settings, how are they applied in a real VGA? Are they both applied at the rendering, when a character clock loads information from the four memory planes? Or are they applied when the CPU reads and writes to display memory?

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

Reply 1 of 6, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've almost fixed my VGA emulation to work with all video modes. Only the mode 13h display goes a bit wrong: it's displaying 640 pixels horizontally from a framebuffer of 640 pixels instead of 320 pixels. I'm using the Dosbox-X int10_modes.cpp to set the modes for my VGA emulator, character input is from the most recent Dosbox SVN. Is there anything that this mode sets that makes 320 pixels appear as 640 pixels on-screen without setting the DCR (Dot Clock Rate) in the Sequencer Clocking mode register? Anyone can tell me what's going wrong?

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

Reply 2 of 6, by SarahWalker

User metadata
Rank Member
Rank
Member

You want bit 6 (Clock select) of attribute register 0x10. This causes two 4-bit pixels to be interpreted as one 8-bit pixel.

Reply 3 of 6, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've gotten the attributes in 8-bit color mode working, I'm seeing all the pixels correctly on-screen. But according to my logs it tries to render 640 horizontal pels 1:1. The VGA memory only has 320 pels wide rows. So I get the second row (for each row, the left half is the row itself, the right half is 320 pixels of the next row, for a total of 640 pixels active display) on the right half of active display. So atm it's taking the first pixel, immediately reading the second pixel because of the 8-bit mode. It merges the values to 1 8-bit DAC lookup and outputs it on active display.

Atm the Dot Clock Rate takes care of the reloading of displayed pixels (every 8 pixels when off, every 16 pixels when set).

void VGA_ActiveDisplay(SEQ_DATA *Sequencer, VGA_Type *VGA)
{
byte loadcharacterplanes;
//Render our active display here! Start with text mode!
static VGA_AttributeInfo attributeinfo; //Our collected attribute info!
static VGA_Sequencer_Mode activemode[2] = {VGA_Sequencer_TextMode,VGA_Sequencer_GraphicsMode}; //Our display modes!
static VGA_Sequencer_Mode activedisplayhandlers[2] = {VGA_ActiveDisplay_noblanking,VGA_Blank}; //For giving the correct output sub-level!
word tempx = Sequencer->tempx; //Load tempx!

othernibble: //Retrieve the current DAC index!
Sequencer->activex = tempx++; //Active X!
activemode[VGA->precalcs.graphicsmode](VGA,Sequencer,&attributeinfo); //Get the color to render!
if (VGA_AttributeController(&attributeinfo,VGA,Sequencer)) goto othernibble; //Apply the attribute through the attribute controller!
//activedisplayhandlers[blanking](VGA,Sequencer,&attributeinfo); //Blank or active display! Blanking doesn't work yet?
VGA_ActiveDisplay_noblanking(VGA, Sequencer, &attributeinfo); //Always active display!

if (++Sequencer->active_pixelrate > VGA->registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.DCR) //To write back the pixel clock every or every other pixel?
{
Sequencer->active_pixelrate = 0; //Reset for the new block!
if (VGA->precalcs.graphicsmode) //Graphics mode?
{
loadcharacterplanes = ((tempx & 7)==0); //Load the character planes?
}
else //Text mode?
{
loadcharacterplanes = (VGA->CRTC.charcolstatus[(Sequencer->tempx<<1)] != VGA->CRTC.charcolstatus[(tempx<<1)]); //Load the character planes?
}
if (loadcharacterplanes) //First of a new block? Reload our pixel buffer!
{
VGA_loadcharacterplanes(VGA, Sequencer, tempx); //Load data from the graphics planes!
}
Sequencer->tempx = tempx; //Write back tempx!
}
}

Tempx is reset every row.

This works in all other modes (640 pels with 320 displayed pixels). But for some reason mode 13h doesn't set the bit, making it a 640x200 pixel mode? Anyone knows how the VGA actually makes this 320 instead of 640 pixels from VRAM (double pixels) without setting this bit?

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

Reply 4 of 6, by Jepael

User metadata
Rank Oldbie
Rank
Oldbie

I don't think you understood SarahWalker. It is not the Dot Clock Rate bit that is used here. You really need the attribute controller register 0x10, bit 6 to be in 256-color mode, and maybe some other registers too.

Mode 13h is really a 640x400 mode if you look at pixels and lines. Thus no DCR bit is used to divide the clock to 320 pixels.

Instead, in mode 13h you basically still have 640 4-bit pixels, but the sequencer (shift register) output is latched every 2 pixels, so instead of 640 4-bit pixels being fed to DAC, the DAC sees only 320 8-bit pixels and because they are updated every other pixel clock, the 8-bit pixels are double as wide.

http://www.osdever.net/FreeVGA/vga/vgaseq.htm

Reply 5 of 6, by superfury

User metadata
Rank l33t++
Rank
l33t++

So if I understand it correctly, the 8-bit color mode actually behaves the same as the DCR when being set? What happens when the DCR bit is set and 8-bit mode is enabled? Do they stack? So every pixel is quadrupled (2 times 2, since DCR doubles pixels and 8-bit mode doubles pixels)?

My VGA emulation is now fully working with all video modes set by Dosbox-X (modes 0 to 13h).

This is my current version:

The attachment vga_20150423_1823.zip is no longer available

Anyone can tell me if anything is missing that needs to be emulated? Anyone knows what effect the misc output register has on the CPU's VRAM window (O/E Page Select)? Does it only have effect when using a 128K memory aperture? Does it only have effect on the high 64K of the 128K window?

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

Reply 6 of 6, by superfury

User metadata
Rank l33t++
Rank
l33t++

This is my latest version:

The attachment vga_20150425_1331.zip is no longer available

All video modes are running fine now. Almost all horizontal CRTC timing works and all vertical CRTC timing works. Also fixed some bugs in the CPU Host Memory Aperture @vga_mmu.c (Misc. Graphics register according to the Intel® OpenSource HD Graphics Programmer’s Reference Manual) and the Shift Register Interleave Mode has been fixed.

For some reason, mode 0/1, 4/5 and D don't have a left empty space (I'm using Dosbox-X's int10_modes.cpp). Does Dosbox-X have an error programming the horizontal CRTC registers during modes 0,1,4,5 and D? Or is there an error in my CRTC emulation? (The emulation's fully in VGA_Sequencer.c (execution part), with timings gotten from vga_crtcontroller.c and vga_precalcs.c, which is drawn according to signals by VGA_CRTController.c).

I also notice all modes are not vertically centered on the rendered screen? All modes have some space at the top of the screen, but not at the bottom? Is this an error in my emulation or an error with the Dosbox-X VGA programming?

Anyone knows how to fix these 'border'/blanked rows/column timing?

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