VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

What effect does the byte/word/doubleword mode have when rendering data from VRAM?

First an address is calculated according to the current horizontal pixel (divide by pixels per character or 8 in graphics modes).
Finally the scanline start is added to the address calculated to generate the Display Memory address.

How does the byte/word/doubleword affect this? Does it affect every byte read from VRAM individually (effect on VRAM reads themselves) or does it affect the address within a VRAM plane (the calculated address above)?

My code for calculating the address:

loadedlocation = x; //X!
loadedlocation &= 0xFFF; //Limit!
if (VGA->precalcs.graphicsmode) //Graphics mode?
{
loadedlocation >>= 3; //We take portions of 8 pixels, so increase our location every 8 pixels!
}
else //Gotten character width? Just here for safety!
{
loadedlocation <<= 1; //Multiply by 2 for our index!
loadedlocation = VGA->CRTC.charcolstatus[loadedlocation]; //Divide by character width in text mode to get the correct character by using the horizontal clock!
}

loadedlocation >>= VGA->precalcs.characterclockshift; //Apply VGA shift: the shift is the ammount to move at a time!
loadedlocation <<= VGA->precalcs.BWDModeShift; //Apply byte/word/doubleword mode at the character level!

//Row logic
loadedlocation += Sequencer->charystart; //Apply the line and start map to retrieve!

//Now calculate and give the planes to be used!
planesbuffer[0] = readVRAMplane(VGA, 0, loadedlocation, 0x80); //Read plane 0!
planesbuffer[1] = readVRAMplane(VGA, 1, loadedlocation, 0x80); //Read plane 1!
planesbuffer[2] = readVRAMplane(VGA, 2, loadedlocation, 0x80); //Read plane 2!
planesbuffer[3] = readVRAMplane(VGA, 3, loadedlocation, 0x80); //Read plane 3!
//Now the buffer is ready to be processed into pixels!

planesdecoder[VGA->precalcs.graphicsmode](VGA); //Use the decoder to get the pixels or characters!

The BWDModeShift variable is the byte/word/doubleword mode (0, 1 or 2). Is this correct? It's currently applied to the loadedlocation before the final calculations of VRAM read (readVRAMplane). Or is this to be applied to the final value of loadedlocation before passed to readVRAMplane?

My readVRAMplane function:

//Planar access to VRAM
byte readVRAMplane(VGA_Type *VGA, byte plane, word offset, byte mode) //Read from a VRAM plane!
{
if (!VGA) return 0; //Invalid VGA!
if (!VGA->VRAM_size) return 0; //No size!
word patchedoffset = offset; //Default offset to use!

if (mode&1) patchedoffset = addresswrap(VGA,patchedoffset); //Apply address wrap?
if (mode&0x80) patchedoffset = patch_map1314(VGA, patchedoffset); //Patch MAP13&14!

plane &= 3; //Only 4 planes are available! Wrap arround the planes if needed!

register uint_32 fulloffset2;
fulloffset2 = patchedoffset; //Load the offset!
fulloffset2 <<= 2; //We cylce through the offsets!
fulloffset2 |= plane; //The plane goes from low to high, through all indexes!

if ((mode & 84) == 0x84) //Special sequencer panning?
{
fulloffset2 += ((SEQ_DATA *)VGA->Sequencer)->bytepanning; //Apply byte panning at the memory level!
}

if (mode & 2)
{
if (mode & 0x80) //Apply DW mode only during rendering!
{
if (VGA->precalcs.BWDModeShift == 2) //DW mode enabled?
{
fulloffset2 <<= 2; //Apply DW mode!
}
}
else
{
fulloffset2 <<= VGA->precalcs.BWDModeShift; //Apply B/W/DW mode from CPU!
}
}

if (VGA->VRAM_size == 0x40000) fulloffset2 &= 0x3FFFF; //Wrap arround memory!

if (fulloffset2<VGA->VRAM_size) //VRAM valid, simple check?
{
return VGA->VRAM[fulloffset2]; //Read the data from VRAM!
}
return 0; //Nothing there: invalid VRAM!
}

And it's required special actions:

//Below patches input addresses for rendering only.
OPTINLINE word patch_map1314(VGA_Type *VGA, word addresscounter) //Patch full VRAM address!
{ //Check this!
word memoryaddress = addresscounter; //New row scan to use!
SEQ_DATA *Sequencer;
Sequencer = (SEQ_DATA *)VGA->Sequencer; //The sequencer!

register word rowscancounter = Sequencer->Scanline; //Load the row scan counter!
rowscancounter = VGA->CRTC.charrowstatus[rowscancounter << 1]; //Take the row status as our source!
rowscancounter >>= VGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.SLDIV; //Apply scanline division!
rowscancounter >>= VGA->precalcs.scandoubling; //Apply Scan Doubling here: we take effect on content!

register word bit; //Load row scan counter!
if (!VGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.MAP13) //a13=Bit 0 of the row scan counter!
{
//Row scan counter bit 1 is placed on the memory bus bit 14 during active display time.
//Bit 1, placed on memory address bit 14 has the effect of quartering the memory.
bit = rowscancounter; //Current row scan counter!
bit &= 1; //Bit0 only!
bit <<= 13; //Shift to our position (bit 13)!
memoryaddress &= 0xDFFF; //Clear bit13!
memoryaddress |= bit; //Set bit13 if needed!
}

if (!VGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.MAP14) //a14<=Bit 1 of the row scan counter!
{
bit = rowscancounter; //Current row scan counter!
bit &= 2; //Bit1 only!
bit <<= 13; //Shift to our position (bit 14)!
memoryaddress &= 0xBFFF; //Clear bit14;
memoryaddress |= bit; //Set bit14 if needed!
}

return memoryaddress; //Give the linear address!
}

OPTINLINE uint_32 addresswrap(VGA_Type *VGA, word memoryaddress) //Wraps memory arround 64k!
{
register word address2; //Load the initial value for calculating!
register word result;
register byte temp;
if (VGA->precalcs.BWDModeShift == 1) //Word mode?
{
result = memoryaddress; //Default: don't change!
address2 = memoryaddress; //Load the address for calculating!
temp = 0xD; //Load default location (13)
temp |= (VGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.AW << 1); //MA15 instead of MA13 when set!
address2 >>= temp; //Apply MA15/MA13 to bit 0!
address2 &= 1; //Only load bit 0!
result &= 0xFFFE; //Clear bit 0!
result |= address2; //Add bit MA15/MA13 at bit 0!
return result; //Give the result!
}
return memoryaddress; //Original address!
}

Anyone can tell me why mode 13h (256 color mode) goes wrong?

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