VOGONS


Reply 60 of 69, by superfury

User metadata
Rank l33t
Rank
l33t

Hmmm.... Right now experimenting with the 16-bit color mode using the accelerator.
I see, when looking at the VRAM data that's transformed into the sprite that's displayed for the cursor, that somehow every other byte seems to be always 0xAA (so all odd bytes in the bitmap sprite structure is 4 transparent 4-bit pixels)? That's kind of weird behaviour?
It also seems to display only half the horizontal size of the sprite somehow?

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

Reply 61 of 69, by superfury

User metadata
Rank l33t
Rank
l33t

Hmmm... Selecting basic acceleration functions (slider 1 to the right of the left side) in the properties of the ET4000/W32 seems to render text properly as well in 16-bit color mode?
It's still using a broken sprite though?
Edit: Selecting "Most accelerator functions" causes corrupted text?

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

Reply 62 of 69, by superfury

User metadata
Rank l33t
Rank
l33t

While still having the accererator fully enabled, added a little bugfix. Each time it starts a new accelerator operation (except when setting the XYST bit in the status register from 0 to 1), it will reset the bit number (for the mix map in0uts) to process for the next pixel it's processing to start at the first bit (bit 0 for increasing x addresses, bit 7 for decreasing x addresses).

The text output seems to improve slightly. Still not really readable, but text can be vaguely made out of it.

1413-windows9x_run_16bitcolors_accelerated.png
Filename
1413-windows9x_run_16bitcolors_accelerated.png
File size
10.43 KiB
Views
149 views
File comment
UniPCemu ET4000/W32 Win95 Run dialog with alphabet a-z and 0-9
File license
Fair use/fair dealing exception
1415-notepad_alphabet_numbers0through9_alphabet.png
Filename
1415-notepad_alphabet_numbers0through9_alphabet.png
File size
12.11 KiB
Views
149 views
File comment
UniPCemu ET4000/W32 Win95 Notepad with alphabet on the first row, 0-9 on second row, word "alphabet" on the third row.
File license
Fair use/fair dealing exception
1416-notepad_saveandquit.png
Filename
1416-notepad_saveandquit.png
File size
15.12 KiB
Views
149 views
File comment
UniPCemu ET4000/W32 Win95 Notepad save and quit dialog
File license
Fair use/fair dealing exception
1417-windows95_shutdownmenu.png
Filename
1417-windows95_shutdownmenu.png
File size
12.2 KiB
Views
149 views
File comment
UniPCemu ET4000/W32 Win95 Shutdown menu
File license
Fair use/fair dealing exception

Anyone has any idea what's going wrong there?
The accelerator code can be found here: https://bitbucket.org/superfury/unipcemu/src/ … ga/svga/tseng.c

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

Reply 64 of 69, by superfury

User metadata
Rank l33t
Rank
l33t

Well, the row addition algorithm is the same in all acl modes. It's the et4k_stepx function for wrapping horizontally(if used) and the et4k_stepy function for wrapping vertically(handles the row advancement logic).
And since images are rendered correctly, together with windowing etc., that shouldn't be the cause?
It simply adds/substracts the value of the y offset register plus 1 to the addresses(destination/pattern/source) and wraps them afterwards(wrapping is based on PCem's code, as there's no proper documentation on wrapping behaviour of the W32 ACL I can find anywhere).

When starting the accelerator, the address from the start of the previous row is restored from a backup, which is saved after the y increment completes and when an accelerated operation is started. It adds/substracts the source/pattern/destination Y offset register + 1 to said addresses when the X position overflows the X count.

Details
void et4k_dowrappatternsourceyinc(uint_32 *patternsourcey, uint_32 *patternsourceaddress, byte patternsourcewrapbit6, uint_32 patternsourceaddress_backup, uint_32 patternsourcewrapy, uint_32 patternsourcewrapx, uint_32 yoffset)
{
++*patternsourcey;
if (*patternsourcey == patternsourcewrapy)
{
*patternsourcey = 0;
*patternsourceaddress = patternsourceaddress_backup;
}
}

void et4k_dowrappatternsourceydec(uint_32* patternsourcey, uint_32* patternsourceaddress, byte patternsourcewrapbit6, uint_32 patternsourceaddress_backup, uint_32 patternsourcewrapy, uint_32 patternsourcewrapx, uint_32 yoffset)
{
--*patternsourcey;
if ((*patternsourcey == (uint_32)(~0)) && (!patternsourcewrapbit6))
{
*patternsourcey = patternsourcewrapy - 1;
*patternsourceaddress = patternsourceaddress_backup + (yoffset * (patternsourcewrapy - 1));
}
}

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!
et4k_dowrappatternsourceydec(
&et34k(getActiveVGA())->W32_ACLregs.patternmap_y,
&et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress,
et34k(getActiveVGA())->W32_ACLregs.patternwrap_bit6,
et34k(getActiveVGA())->W32_ACLregs.patternmapaddress_backup,
et34k(getActiveVGA())->W32_ACLregs.patternwrap_y,
et34k(getActiveVGA())->W32_ACLregs.patternwrap_x,
(et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1) //Y offset!
);
et4k_dowrappatternsourceydec(
&et34k(getActiveVGA())->W32_ACLregs.sourcemap_y,
&et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress,
et34k(getActiveVGA())->W32_ACLregs.sourcewrap_bit6,
et34k(getActiveVGA())->W32_ACLregs.sourcemapaddress_backup,
et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y,
et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x,
(et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1) //Y offset!
);
}
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!
et4k_dowrappatternsourceyinc(
&et34k(getActiveVGA())->W32_ACLregs.patternmap_y,
&et34k(getActiveVGA())->W32_ACLregs.internalpatternaddress,
et34k(getActiveVGA())->W32_ACLregs.patternwrap_bit6,
et34k(getActiveVGA())->W32_ACLregs.patternmapaddress_backup,
et34k(getActiveVGA())->W32_ACLregs.patternwrap_y,
et34k(getActiveVGA())->W32_ACLregs.patternwrap_x,
Show last 58 lines
			(et34k(getActiveVGA())->W32_ACLregs.patternYoffset + 1) //Y offset!
);
et4k_dowrappatternsourceyinc(
&et34k(getActiveVGA())->W32_ACLregs.sourcemap_y,
&et34k(getActiveVGA())->W32_ACLregs.internalsourceaddress,
et34k(getActiveVGA())->W32_ACLregs.sourcewrap_bit6,
et34k(getActiveVGA())->W32_ACLregs.sourcemapaddress_backup,
et34k(getActiveVGA())->W32_ACLregs.sourcewrap_y,
et34k(getActiveVGA())->W32_ACLregs.sourcewrap_x,
(et34k(getActiveVGA())->W32_ACLregs.sourceYoffset + 1) //Y offset!
);
}
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_mixmapposition = 0; //Reset mix map position!
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!
et34k(getActiveVGA())->W32_acceleratorleft = 0; //Starting a new operation, so start with new byte data inputs!
result = 1 | (et4k_stepy()); //Step Y! X count reached!
return result; //Give the result!
}
return 0; //No overflow!
}

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

Reply 65 of 69, by superfury

User metadata
Rank l33t
Rank
l33t

Improved the handling of the ET4000/W32 ACL MMU queues when using terminating/suspending. Said request now overwrites (when the bit is written with 1) the MMU queue for the memory aperture(it's aborting it after all). One difference now is that queued writes to MMU registers are left intact and will be written to said register before the suspend/terminate is executed.

VDIAG doesn't seem to like this? Most blits don't modify video memory.
The texts in the bottom right are still seen, as is the Stat error.
New is that it now mentions that all of said earlier-working blit tests all seem to fail(all but the first blit with yellowish color)?

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

Reply 66 of 69, by superfury

User metadata
Rank l33t
Rank
l33t

Just improved the suspend handling a bit.
When executing the suspend command, it will keep a flag saying it's what was last done as an operation. It will still report the last written values of pattern and source addresses at that time.
Then when a loading of the queue is performed using the operation state register, it will load the internal pattern and source address registers into the reported values instead of their actual values, allowing for them to be read back by the algorithm.
Any loading of the queues after that will simply load the queue and report those pattern/source address values instead.
Thus now being compatible with the State-Restore interrupt handler and it's handling of the ISA/IPA(internal source/pattern address) handling of said registers.

I've also modified the XYST bit being set to set said bit and the SSO bit, but not actually start the accelerator again until the resume operation is performed using the operation state register or a new operation is actually started.

Edit: Just also modified the Sync bit to be set on powerup (and terminate). Also don't require the Operation State to be set for the operation to start (as PCem seems to do). I had it in there, but don't quite remember where I've read that.

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

Reply 67 of 69, by superfury

User metadata
Rank l33t
Rank
l33t

Just fixed the queued register writes to no longer be kept from processing by active transfers...
Now with that fixed as well, the VDIAG software no longer complains about anything (except the VSS powerup sequence somehow)?

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

Reply 68 of 69, by superfury

User metadata
Rank l33t
Rank
l33t

Even with all those recent improvements, the Windows 95 rendering is still having incorrect text display somehow? It's printing gibberish 'text'? (All text is in a random pixellated font) Only when running notepad.exe it's actually a bit readable (way too large text at about 1.5 the size it needs to be with empty pixel lines every other scanline it seems)?

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

Reply 69 of 69, by superfury

User metadata
Rank l33t
Rank
l33t

Some good news and bad news. The good news: I managed to get the VDIAG to run with the latest bugfixes (the only exception being what it called "Error power on: VCC").
Also, if accepting the first byte into the multilevel queue (the queue wasn't (partly) filled), it will cause waitstates on the remaining writes to the queue until there is room to put it in the queue (causing 16-bit and 32-bit writes to the queue and queued registers to succeed properly instead of being partly transfers).

Then managed to destroy it once again when making the queued register use a multilevel queue with waitstates when writing more than 1 byte on the same transfer (causing multibyte transfers to be shifted into a multilevel queue instead of a single-level queue).
This also makes Windows 95 render stuff at the wrong positions again 😖 Notably things like large chunks of the task bar and other things.

On VDIAG, it gives lots of errors on almost all the blitting parts. I also see it rendering what looks like horizontal and vertical lines on the screen (it didn't do this before, instead just rendering areas in a certain color, filling the entire screen)? That's the poly line part of the VDIAG program.

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