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; //Resetet34k(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 masksuint_32 Tseng4k_wrap_y[8] = { 1,2,4,8,~0,~0,~0,~0 }; //Y wrapping masksvoid 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