Reply 20 of 69, by superfury
Anyone knows how the horizontal and vertical wrappings affect addresses and counters used when starting or continuing a new BitBlt transfer?
This is what I've gotten so far:
void Tseng4k_startAccelerator()
{
uint_32 horizontalwrappings,horizontalsize;
//Start the accelerator's function.
//Load all internal precalcs required and initialize all local required CPU-readonly variables.
Tseng4k_decodeAcceleratorRegisters(); //Load all registers into the accelerator's precalcs!
//TODO: Load the read-only variables for the accelerator to start using. Also depends on the reloadPatternAddress and reloadSourceAddress ACL settings.
if (et34k(getActiveVGA())->W32_ACLregs.reloadPatternAddress == 0) //To reload the pattern address?
{
et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress = et34k(getActiveVGA())->W32_ACLregs.patternmapaddress; //Pattern address reload!
}
if (et34k(getActiveVGA())->W32_ACLregs.reloadSourceAddress == 0) //To reload the pattern address?
{
et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress = et34k(getActiveVGA())->W32_ACLregs.sourcemapaddress; //Pattern address reload!
}
//Perform what wrapping?
et34k(getActiveVGA())->W32_ACLregs.patternwrap_x = Tseng4k_wrap_x[et34k(getActiveVGA())->W32_ACLregs.Xpatternwrap]; //What horizontal wrapping to use!
et34k(getActiveVGA())->W32_ACLregs.patternwrap_y = Tseng4k_wrap_x[et34k(getActiveVGA())->W32_ACLregs.Ypatternwrap]; //What horizontal wrapping to use!
et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x = Tseng4k_wrap_x[et34k(getActiveVGA())->W32_ACLregs.Xsourcewrap]; //What horizontal wrapping to use!
et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y = Tseng4k_wrap_x[et34k(getActiveVGA())->W32_ACLregs.Ysourcewrap]; //What horizontal wrapping to use!
//Perform wrapping of the inputs!
//First, wrap pattern!
et34k(getActiveVGA())->W32_ACLregs.patternmap_x = et34k(getActiveVGA())->W32_ACLregs.Xposition; //Don't wrap our idea of X!
et34k(getActiveVGA())->W32_ACLregs.patternmap_y = et34k(getActiveVGA())->W32_ACLregs.Yposition; //Don't wrap our idea of Y!
/*
horizontalwrappings = 0; //Default: nothing is horizontally wrapped!
horizontalsize = (et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1); //How large is the horizontal row?
if (et34k(getActiveVGA())->W32_ACLregs.patternwrap_x!=(uint_32)~0) //X wrapping?
{
horizontalwrappings = et34k(getActiveVGA())->W32_ACLregs.Xposition / (et34k(getActiveVGA())->W32_ACLregs.patternwrap_x + 1); //How many times is X wrapped?
et34k(getActiveVGA())->W32_ACLregs.patternmap_x = et34k(getActiveVGA())->W32_ACLregs.Xposition & et34k(getActiveVGA())->W32_ACLregs.patternwrap_x; //Wrap our idea of X!
}
et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress -= horizontalwrappings * (et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1); //How many times is X wrapped, adding to Y at the address level?
if (et34k(getActiveVGA())->W32_ACLregs.patternwrap_y!=(uint_32)~0) //Y wrapping?
{
horizontalwrappings -= (et34k(getActiveVGA())->W32_ACLregs.patternmap_y / (et34k(getActiveVGA())->W32_ACLregs.patternwrap_y + 1)) * (et34k(getActiveVGA())->W32_ACLregs.patternwrap_y + 1); //How much is wrapped in the Y coordinate!
et34k(getActiveVGA())->W32_ACLregs.patternmap_y = et34k(getActiveVGA())->W32_ACLregs.patternmap_y & et34k(getActiveVGA())->W32_ACLregs.patternwrap_y; //Wrap our idea of Y!
}
else
{
horizontalwrappings = 0; //Nothing to wrap!
}
et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress -= horizontalwrappings * (et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1); //How many times is X wrapped, adding to Y at the address level?
*/
//Next, wrap source!
et34k(getActiveVGA())->W32_ACLregs.sourcemap_x = et34k(getActiveVGA())->W32_ACLregs.Xposition; //Don't wrap our idea of X!
et34k(getActiveVGA())->W32_ACLregs.sourcemap_y = et34k(getActiveVGA())->W32_ACLregs.Yposition; //Don't wrap our idea of Y!
/*
horizontalwrappings = 0; //Default: nothing is horizontally wrapped!
horizontalsize = (et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1); //How large is the horizontal row?
if (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x != (uint_32)~0) //X wrapping?
{
horizontalwrappings = et34k(getActiveVGA())->W32_ACLregs.Xposition / (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x + 1); //How many times is X wrapped?
et34k(getActiveVGA())->W32_ACLregs.sourcemap_x = et34k(getActiveVGA())->W32_ACLregs.Xposition & et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x; //Wrap our idea of X!
}
if (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y != (uint_32)~0) //Y wrapping?
{
horizontalwrappings -= (et34k(getActiveVGA())->W32_ACLregs.sourcemap_y / (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y + 1)) * (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y + 1); //How much is wrapped in the Y coordinate!
et34k(getActiveVGA())->W32_ACLregs.sourcemap_y = et34k(getActiveVGA())->W32_ACLregs.sourcemap_y & et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y; //Wrap our idea of Y!
}
et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress -= horizontalwrappings * (et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1); //How many times is X wrapped, adding to Y at the address level?
*/
//Backup the original values before starting!
et34k(getActiveVGA())->W32_ACLregs.patternmap_x_backup = et34k(getActiveVGA())->W32_ACLregs.patternmap_x; //Backup!
et34k(getActiveVGA())->W32_ACLregs.sourcemap_x_backup = et34k(getActiveVGA())->W32_ACLregs.sourcemap_x; //Backup!
et34k(getActiveVGA())->W32_ACLregs.patternmapaddress_backup = et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress; //Backup!
et34k(getActiveVGA())->W32_ACLregs.sourcemapaddress_backup = et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress; //Backup!
et34k(getActiveVGA())->W32_ACLregs.destinationaddress_backup = et34k(getActiveVGA())->W32_ACLregs.destinationaddress; //Backup!
if ((et34k(getActiveVGA())->W32_MMUregisters[1][0x9C] & 7) == 0) //No CPU version?
{
et34k(getActiveVGA())->W32_acceleratorleft = 1; //Always more left until finishing! This keeps us running!
}
}
Each x and y step it simply wraps around the x multiple and y multiple (adding or substracting a multiple of the Y map offset for the source or pattern maps.
byte et4k_stepy()
{
++et34k(getActiveVGA())->W32_ACLregs.Yposition;
et34k(getActiveVGA())->W32_ACLregs.destinationaddress = et34k(getActiveVGA())->W32_ACLregs.destinationaddress_backup; //Make sure that we're jumping from the original!
if (et34k(getActiveVGA())->W32_ACLregs.XYdirection&2) //Negative Y?
{
et34k(getActiveVGA())->W32_ACLregs.destinationaddress -= et34k(getActiveVGA())->W32_ACLregs.destinationYoffset + 1; //Next address!
et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress -= et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1; //Next address!
et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress -= et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1; //Next address!
--et34k(getActiveVGA())->W32_ACLregs.patternmap_y;
if (et34k(getActiveVGA())->W32_ACLregs.patternmap_y == ((uint_32)~0)) //Overflow?
{
if (et34k(getActiveVGA())->W32_ACLregs.patternwrap_y != (uint_32)~0) //Wrapping Y?
{
et34k(getActiveVGA())->W32_ACLregs.patternmap_y = et34k(getActiveVGA())->W32_ACLregs.patternwrap_y; //Returning to the bottom!
et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress += ((et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1) * (((uint_64)et34k(getActiveVGA())->W32_ACLregs.patternwrap_y) + 1)); //Apply Y address wrap!
}
}
--et34k(getActiveVGA())->W32_ACLregs.sourcemap_y;
if (et34k(getActiveVGA())->W32_ACLregs.sourcemap_y == ((uint_32)~0)) //Overflow?
{
if (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y != (uint_32)~0) //Wrapping Y?
{
et34k(getActiveVGA())->W32_ACLregs.sourcemap_y = et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y; //Returning to the bottom!
et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress += ((et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1) * (((uint_64)et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y) + 1)); //Apply Y address wrap!
}
}
}
else //Positive Y?
{
et34k(getActiveVGA())->W32_ACLregs.destinationaddress += et34k(getActiveVGA())->W32_ACLregs.destinationYoffset + 1; //Next address!
et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress += et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1; //Next address!
et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress += et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1; //Next address!
++et34k(getActiveVGA())->W32_ACLregs.patternmap_y;
if ((uint_64)et34k(getActiveVGA())->W32_ACLregs.patternmap_y > (uint_64)et34k(getActiveVGA())->W32_ACLregs.patternwrap_y) //Wrapping point reached?
{
et34k(getActiveVGA())->W32_ACLregs.patternmap_y = 0; //Reset!
et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress -= (et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1) * (et34k(getActiveVGA())->W32_ACLregs.patternwrap_y + 1); //Go back to the backup address!
}
++et34k(getActiveVGA())->W32_ACLregs.sourcemap_y;
if ((uint_64)et34k(getActiveVGA())->W32_ACLregs.sourcemap_y > (uint_64)et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y) //Wrapping point reached?
{
et34k(getActiveVGA())->W32_ACLregs.sourcemap_y = 0; //Reset!
et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress -= (et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1) * (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y + 1); //Go back to the backup address!
}
}
et34k(getActiveVGA())->W32_ACLregs.destinationaddress_backup = et34k(getActiveVGA())->W32_ACLregs.destinationaddress; //Save the new line on the destination address to jump back to!
if (et34k(getActiveVGA())->W32_ACLregs.Yposition>et34k(getActiveVGA())->W32_ACLregs.Ycount)
{
//Leave Y position and addresses alone!
return 2; //Y count reached!
}
return 0; //No overflow!
}
byte et4k_stepx()
{
byte result;
++et34k(getActiveVGA())->W32_ACLregs.Xposition;
if (et34k(getActiveVGA())->W32_ACLregs.XYdirection&1) //Negative X?
{
--et34k(getActiveVGA())->W32_ACLregs.destinationaddress; //Next address!
--et34k(getActiveVGA())->W32_ACLregs.patternmap_x; //Next address!
--et34k(getActiveVGA())->W32_ACLregs.sourcemap_x; //Next address!
if ((uint_64)et34k(getActiveVGA())->W32_ACLregs.patternmap_x == ((uint_32)~0)) //X overflow according to wrapping?
et34k(getActiveVGA())->W32_ACLregs.patternmap_x += (uint_32)(et34k(getActiveVGA())->W32_ACLregs.patternwrap_x + 1); //Wrap it!
if ((uint_64)et34k(getActiveVGA())->W32_ACLregs.sourcemap_x == ((uint_32)~0)) //X overflow according to wrapping?
et34k(getActiveVGA())->W32_ACLregs.sourcemap_x += (uint_32)(et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x + 1); //Wrap it!
}
else //Positive X?
{
++et34k(getActiveVGA())->W32_ACLregs.destinationaddress; //Next address!
++et34k(getActiveVGA())->W32_ACLregs.patternmap_x; //Next address!
++et34k(getActiveVGA())->W32_ACLregs.sourcemap_x; //Next address!
if ((uint_64)et34k(getActiveVGA())->W32_ACLregs.patternmap_x > (uint_64)et34k(getActiveVGA())->W32_ACLregs.patternwrap_x) //X overflow according to wrapping?
et34k(getActiveVGA())->W32_ACLregs.patternmap_x -= (et34k(getActiveVGA())->W32_ACLregs.patternwrap_x+1); //Wrap it!
if ((uint_64)et34k(getActiveVGA())->W32_ACLregs.sourcemap_x > (uint_64)et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x) //X overflow according to wrapping?
et34k(getActiveVGA())->W32_ACLregs.sourcemap_x -= (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x+1); //Wrap it!
}
if (et34k(getActiveVGA())->W32_ACLregs.Xposition>et34k(getActiveVGA())->W32_ACLregs.Xcount)
{
//X overflow? Step vertically!
et34k(getActiveVGA())->W32_ACLregs.Xposition = 0; //Reset
et34k(getActiveVGA())->W32_ACLregs.patternmap_x = et34k(getActiveVGA())->W32_ACLregs.patternmap_x_backup; //Restore the backup!
et34k(getActiveVGA())->W32_ACLregs.sourcemap_x = et34k(getActiveVGA())->W32_ACLregs.sourcemap_x_backup; //Restore the backup!
result = 1 | (et4k_stepy()); //Step Y! X count reached!
return result; //Give the result!
}
return 0; //No overflow!
}
So theoretically, the X and Y pattern steps and wrapping should be correctly applied during execution.
The main issue is with the initialization during startAccelerator(), where it tries to determine the X and Y coordinate and map displacement to start with?
Anyone?
Btw WhatVGA's unwrapped transfer works like a charm. It's the wrapped transfer that somehow gives weird results?
Edit: I currently just base the X and Y wrapping initial locations and values on a combination of the wrap settings and the given X and Y positions(MMU registers 94h and 96h), combined applied to said setting (simply wrapping around the X and Y coordinates using division and modulo) to obtain the vertical displacement based on wrapping(and performing the horizontal wrapping by performing a simple modulo)? Then it applies the vertical wrappings to the start address in memory just like the normal Y stepping does.
FInally, it performs the same using a division for the Y divisor(added to the address) and Y modulo(used as the Y row to start counting at)?
Would that be correct behaviour?
uint_32 Tseng4k_wrap_x[8] = { 0,0,3,7,0xF,0x1F,0x3F,~0 }; //X wrapping masks
uint_32 Tseng4k_wrap_y[8] = { 1,2,4,8,~0,~0,~0,~0 }; //Y wrapping masks
void Tseng4k_startAccelerator()
{
int_64 horizontalwrappings,horizontalsize;
//Start the accelerator's function.
//Load all internal precalcs required and initialize all local required CPU-readonly variables.
Tseng4k_decodeAcceleratorRegisters(); //Load all registers into the accelerator's precalcs!
//TODO: Load the read-only variables for the accelerator to start using. Also depends on the reloadPatternAddress and reloadSourceAddress ACL settings.
if (et34k(getActiveVGA())->W32_ACLregs.reloadPatternAddress == 0) //To reload the pattern address?
{
et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress = et34k(getActiveVGA())->W32_ACLregs.patternmapaddress; //Pattern address reload!
}
if (et34k(getActiveVGA())->W32_ACLregs.reloadSourceAddress == 0) //To reload the pattern address?
{
et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress = et34k(getActiveVGA())->W32_ACLregs.sourcemapaddress; //Pattern address reload!
}
//Perform what wrapping?
et34k(getActiveVGA())->W32_ACLregs.patternwrap_x = Tseng4k_wrap_x[et34k(getActiveVGA())->W32_ACLregs.Xpatternwrap]; //What horizontal wrapping to use!
et34k(getActiveVGA())->W32_ACLregs.patternwrap_y = Tseng4k_wrap_x[et34k(getActiveVGA())->W32_ACLregs.Ypatternwrap]; //What horizontal wrapping to use!
et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x = Tseng4k_wrap_x[et34k(getActiveVGA())->W32_ACLregs.Xsourcewrap]; //What horizontal wrapping to use!
et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y = Tseng4k_wrap_x[et34k(getActiveVGA())->W32_ACLregs.Ysourcewrap]; //What horizontal wrapping to use!
//Perform wrapping of the inputs!
//First, wrap pattern!
et34k(getActiveVGA())->W32_ACLregs.patternmap_x = et34k(getActiveVGA())->W32_ACLregs.Xposition; //Don't wrap our idea of X!
et34k(getActiveVGA())->W32_ACLregs.patternmap_y = et34k(getActiveVGA())->W32_ACLregs.Yposition; //Don't wrap our idea of Y!
horizontalwrappings = 0; //Default: nothing is horizontally wrapped!
horizontalsize = (et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1); //How large is the horizontal row?
if (et34k(getActiveVGA())->W32_ACLregs.patternwrap_x!=(uint_32)~0) //X wrapping?
{
horizontalwrappings = (int_64)(et34k(getActiveVGA())->W32_ACLregs.Xposition / (et34k(getActiveVGA())->W32_ACLregs.patternwrap_x + 1)); //How many times is X wrapped?
et34k(getActiveVGA())->W32_ACLregs.patternmap_x = et34k(getActiveVGA())->W32_ACLregs.Xposition & et34k(getActiveVGA())->W32_ACLregs.patternwrap_x; //Wrap our idea of X!
}
et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress -= horizontalwrappings * (et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1); //How many times is X wrapped, adding to Y at the address level?
if (et34k(getActiveVGA())->W32_ACLregs.patternwrap_y!=(uint_32)~0) //Y wrapping?
{
horizontalwrappings -= (int_64)((et34k(getActiveVGA())->W32_ACLregs.patternmap_y / (et34k(getActiveVGA())->W32_ACLregs.patternwrap_y + 1)) * (et34k(getActiveVGA())->W32_ACLregs.patternwrap_y + 1)); //How much is wrapped in the Y coordinate!
et34k(getActiveVGA())->W32_ACLregs.patternmap_y = et34k(getActiveVGA())->W32_ACLregs.patternmap_y & et34k(getActiveVGA())->W32_ACLregs.patternwrap_y; //Wrap to our idea of Y!
}
else
{
horizontalwrappings = 0; //Nothing to wrap!
}
et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress -= horizontalwrappings * (et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1); //How many times is X wrapped, adding to Y at the address level?
//Next, wrap source!
et34k(getActiveVGA())->W32_ACLregs.sourcemap_x = et34k(getActiveVGA())->W32_ACLregs.Xposition; //Don't wrap our idea of X!
et34k(getActiveVGA())->W32_ACLregs.sourcemap_y = et34k(getActiveVGA())->W32_ACLregs.Yposition; //Don't wrap our idea of Y!
horizontalwrappings = 0; //Default: nothing is horizontally wrapped!
horizontalsize = (et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1); //How large is the horizontal row?
if (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x != (uint_32)~0) //X wrapping?
{
horizontalwrappings = (int_64)(et34k(getActiveVGA())->W32_ACLregs.Xposition / (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x + 1)); //How many times is X wrapped?
et34k(getActiveVGA())->W32_ACLregs.sourcemap_x = et34k(getActiveVGA())->W32_ACLregs.Xposition & et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x; //Wrap our idea of X!
}
et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress -= horizontalwrappings * (et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1); //How many times is X wrapped, adding to Y at the address level?
if (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y != (uint_32)~0) //Y wrapping?
{
horizontalwrappings -= (int_64)((et34k(getActiveVGA())->W32_ACLregs.sourcemap_y / (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y + 1)) * (et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y + 1)); //How much is wrapped in the Y coordinate!
et34k(getActiveVGA())->W32_ACLregs.sourcemap_y = et34k(getActiveVGA())->W32_ACLregs.sourcemap_y & et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y; //Wrap to our idea of Y!
}
else
{
horizontalwrappings = 0; //Nothing to wrap!
}
et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress -= horizontalwrappings * (et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1); //How many times is X wrapped, adding to Y at the address level?
//Backup the original values before starting!
et34k(getActiveVGA())->W32_ACLregs.patternmap_x_backup = et34k(getActiveVGA())->W32_ACLregs.patternmap_x; //Backup!
et34k(getActiveVGA())->W32_ACLregs.sourcemap_x_backup = et34k(getActiveVGA())->W32_ACLregs.sourcemap_x; //Backup!
et34k(getActiveVGA())->W32_ACLregs.patternmapaddress_backup = et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress; //Backup!
et34k(getActiveVGA())->W32_ACLregs.sourcemapaddress_backup = et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress; //Backup!
et34k(getActiveVGA())->W32_ACLregs.destinationaddress_backup = et34k(getActiveVGA())->W32_ACLregs.destinationaddress; //Backup!
if ((et34k(getActiveVGA())->W32_MMUregisters[1][0x9C] & 7) == 0) //No CPU version?
{
et34k(getActiveVGA())->W32_acceleratorleft = 1; //Always more left until finishing! This keeps us running!
}
}
Anyone?
Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io