VOGONS


CGA on VGA emulation in x86EMU?

Topic actions

Reply 100 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:
About those 'black lines' appearing in the images, dumping the vertical timinig (horizontal timing seems fine) gave me this: […]
Show full quote

About those 'black lines' appearing in the images, dumping the vertical timinig (horizontal timing seems fine) gave me this:

0:00:37:49.3.0579: Row #0=+VRETRACEEND+VBLANKEND+VACTIVEDISPLAY

0:00:37:49.3.0857: Row #1=+VACTIVEDISPLAY

0:00:37:49.3.0861: Row #2=+OVERSCAN

0:00:37:49.3.0869: Row #3=+VTOTAL+OVERSCAN+VSYNCRESET

So effectively 2 scanlines active display and 1 scanline overscan? Does the vertical total trigger too late? Shouldn't vertical total trigger on scanline 2 instead of 3? Thus 2 scanlines of active display?

This is the CGA model identification graphic? The first image that appears in 8088MPH final version? Yes, it programs r9=0, r5=0, r6=2 and r4=1 for most of the active area, so it should have two scanlines total, both active.

Reply 101 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've decreased both the vertical total character(CGA register 4) and calculated scanline after that ((register 4 + 1_ times character height plus register 4)) to use vertical total when:
1. The character row is higher or equal to register 4(instead of only when higher).
2. (((Register 4 + 1) x character height)+register 5) is lower or equal to the scanline instead of being lower than the scanline.

This seems to have fixed all black scanline insertions(essentially removing the old Row#2 from the list) in the demo. The only problems currently left in the vertical timing is that (at least) the detection and 1K screens only have half the vertical height they're supposed to have(I only end up with half a screen of content, the other half being blanked for some reason). Also the horizontal timing seems to have a little problem: the patterns on the 3d objects look like horizontal lines instead of dots. Also the comparison part(including the scrolling with the car) and Intel logo seem to have horizontal problems(forming blocks of 8 pixels instead of single pixels in the Intel logo(this might be the same problem messing up the comparison and image with the car etc.)).

Snap 2016-04-11 at 09.30.31.png
Filename
Snap 2016-04-11 at 09.30.31.png
File size
84.51 KiB
Views
821 views
File comment
CGA detection only showing half a screen without black lines(overscan) inserted.
File license
Fair use/fair dealing exception
Snap 2016-04-11 at 09.23.12.png
Filename
Snap 2016-04-11 at 09.23.12.png
File size
208.51 KiB
Views
821 views
File comment
Kefrens now working(with blank frames being inserted).
File license
Fair use/fair dealing exception
Snap 2016-04-11 at 09.26.36.png
Filename
Snap 2016-04-11 at 09.26.36.png
File size
267.85 KiB
Views
821 views
File comment
3d objects showing horizontal lines pattern.
File license
Fair use/fair dealing exception

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

Reply 102 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Here's some pictures taken in CGA using the RGB monitor (to verify outputted data, since only the processing the scanline to NTSC instead of RGB values is affected after this step):

Snap 2016-04-11 at 10.22.27.png
Filename
Snap 2016-04-11 at 10.22.27.png
File size
64 KiB
Views
814 views
File comment
Detection window on a RGB monitor.
File license
Fair use/fair dealing exception
Snap 2016-04-11 at 10.23.45.png
Filename
Snap 2016-04-11 at 10.23.45.png
File size
215.8 KiB
Views
814 views
File comment
Initial logo on a RGB monitor.
File license
Fair use/fair dealing exception

Edit: some more images:

Snap 2016-04-11 at 10.29.55.png
Filename
Snap 2016-04-11 at 10.29.55.png
File size
53.13 KiB
Views
813 views
File comment
Text displayed in the comparison screen.
File license
Fair use/fair dealing exception

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

Reply 103 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

The model identification screen looks ok on the RGBI output, so the composite colour issue you're having is probably due to a horizontal pixel offset (the colour carrier phase repeats every 4 hdots so if your horizontal positioning is off by 1, 2 or 3 hdots the colours will be wrong).

There is something very screwed up with the pixel plotting in 1bpp mode. It looks like the pixels are wider than they are supposed to be and adjacent columns are getting mixed together somehow. Compare with how that looks in DOSBox SVN with composite decoding turned off.

Reply 104 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

This is what my emulation generates when rendering the CGA (set the emulator to use Forced, Fullscreen stretching, Old-style RGB to get a 1:1 screen of CGA RGB output):

Snap 2016-04-11 at 11.05.37.png
Filename
Snap 2016-04-11 at 11.05.37.png
File size
6.1 KiB
Views
811 views
File comment
CGA output as rendered by the CGA-on-VGA renderer.
File license
Fair use/fair dealing exception

So vertical timing is correct, but horizontal timing has errors? It's supposed to be put in monochrome graphics(all color planes enabled), shift interleaved mode off(so just single shift mode on the VGA), MAP13=0(Since it's an interleaved CGA graphics mode).

The attributes are set to 0 for color #0 and 7 for all other colors.

All other registers are as set by the CGA initializing:

	getActiveVGA()->registers->GraphicsRegisters.REGISTERS.SETRESETREGISTER.SetReset = 0; //Disable!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.ENABLESETRESETREGISTER.EnableSetReset = 0; //No set/reset used!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.DATAROTATEREGISTER.RotateCount = 0; //No special operation!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.DATAROTATEREGISTER.LogicalOperation = 0; //No special operation!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.COLORCOMPAREREGISTER.ColorCompare = 0; //Disable!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.READMAPSELECTREGISTER.ReadMapSelect = 0; //Disable/Plane 0!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.WriteMode = 0; //Disable!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.ReadMode = 0; //Disable!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.OddEvenMode = 1; //Enable!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.Color256ShiftMode = 0; //Disable!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.MISCGRAPHICSREGISTER.EnableOddEvenMode = 1; //Enable!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.COLORDONTCAREREGISTER.ColorCare |= 0xF; //Care about this only!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.BITMASKREGISTER = 0xFF; //Use all bits supplied by the CPU!
//Sequencer: Fully set!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.RESETREGISTER.AR = 1; //Start the sequencer!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.RESETREGISTER.SR = 1; //Start the sequencer!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.S4 = 0; //CGA display!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.DCR = 0; //CGA display! Single pixels only!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.SLR = 0; //CGA display! Single load rate!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.CLOCKINGMODEREGISTER.DotMode8 = 1; //CGA display! 8 dots/character!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.MAPMASKREGISTER.MemoryPlaneWriteEnable = 3; //Write to planes 0/1 only, since we're emulating CGA!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.ExtendedMemory = 0; //Write to planes 0/1 only, since we're emulating CGA! We're wrapping around 16KB, so only 64K applied(16K with double 4 bytes per index=64K memory).
getActiveVGA()->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.OEDisabled = 0; //Write to planes 0/1 only, since we're emulating CGA!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.Chain4Enable = 0; //Write to planes 0/1 only, since we're emulating CGA!
//CRT Controller: Fully set!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.UNDERLINELOCATIONREGISTER.DW = 0; //CGA normal mode!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.UNDERLINELOCATIONREGISTER.DIV4 = 0; //CGA normal mode!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.LINECOMPAREREGISTER = 0xFF; //Maximum line compare: no split screen!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.OVERFLOWREGISTER.LineCompare8 = 1; //Maximum line compare: no split screen!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.MAXIMUMSCANLINEREGISTER.LineCompare9 = 1; //Maximum line compare: no split screen!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CURSORENDREGISTER.CursorSkew = 0; //Don't use any cursor skewing: we're direct line numbers for the scanline within the character!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.VERTICALRETRACEENDREGISTER.VerticalInterrupt_Disabled = 1; //Disable the VRetrace interrupts!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.SLDIV = 0; //CGA no scanline division!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.DIV2 = 0; //CGA normal mode?
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.SE = 1; //CGA enable CRT rendering HSYNC/VSYNC!
//Memory mapping special: always map like a CGA!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.UseByteMode = 0; //CGA word mode!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.AW = 0; //CGA mapping is done by the renderer mapping CGA!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.MAP14 = 1; //CGA mapping!
//Attribute Controller: Fully set!
VGA_3C0_PAL = 1; //Enable the palette!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.LineGraphicsEnable = 1; //CGA line graphics!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.PixelPanningMode = 0; //CGA pixel panning mode!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.ColorEnable8Bit = 0; //Not using 8-bit colors!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.PaletteBits54Select = 0; //Not using the high Palette bits!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.COLORPLANEENABLEREGISTER.DATA |= 0xF; //CGA: enable all color planes!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.HORIZONTALPIXELPANNINGREGISTER.PixelShiftCount = 0; //Don't shift!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.COLORSELECTREGISTER.ColorSelect54 = 0; //Don't use!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.COLORSELECTREGISTER.ColorSelect76 = 0; //Don't use!
//External registers: Fully set!
getActiveVGA()->registers->ExternalRegisters.MISCOUTPUTREGISTER.IO_AS = (getActiveVGA()->registers->specialCGAflags&1)?1:0; //CGA/MDA address!
getActiveVGA()->registers->ExternalRegisters.MISCOUTPUTREGISTER.RAM_Enable = 1; //CGA!
getActiveVGA()->registers->ExternalRegisters.MISCOUTPUTREGISTER.OE_HighPage = 0; //CGA!
getActiveVGA()->registers->ExternalRegisters.MISCOUTPUTREGISTER.HSyncP = 0; //CGA has positive polarity!
getActiveVGA()->registers->ExternalRegisters.MISCOUTPUTREGISTER.VSyncP = 0; //CGA has positive polarity!
getActiveVGA()->registers->ExternalRegisters.FEATURECONTROLREGISTER.FC0 = 0; //CGA!
getActiveVGA()->registers->ExternalRegisters.FEATURECONTROLREGISTER.FC1 = 1; //CGA!

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

Reply 105 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've made a bit on progress on the CGA monochrome mode:

Snap 2016-04-11 at 11.23.18.png
Filename
Snap 2016-04-11 at 11.23.18.png
File size
6.13 KiB
Views
810 views
File comment
Improved monochrome mode with small width error.
File license
Fair use/fair dealing exception

I've modified the CGA-on-VGA to change the VRAM addressing a bit when switched to 640x200 mode.

void setCGAMDAMode(byte useGraphics, byte GraphicsMode, byte blink) //Rendering mode set!
{
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.ShiftRegisterInterleaveMode = ((useGraphics && GraphicsMode)?1:0);
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.MISCGRAPHICSREGISTER.AlphaNumericModeDisable = useGraphics;
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.COLORPLANEENABLEREGISTER.DATA |= (useGraphics&&!GraphicsMode)?0x1:0xF; //CGA: enable all color planes!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.AttributeControllerGraphicsEnable = useGraphics; //Text mode!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.MonochromeEmulation = ((!useGraphics) && GraphicsMode); //MDA attributes!
getActiveVGA()->registers->AttributeControllerRegisters.REGISTERS.ATTRIBUTEMODECONTROLREGISTER.BlinkEnable = ((!useGraphics) && blink)?1:0; //Use blink when not using graphics and blink is enabled!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.UNDERLINELOCATIONREGISTER.UnderlineLocation = ((!useGraphics) && GraphicsMode)?0xC:0x1F; //Monochrome emulation applies MDA-compatible underline, simple detection by character height!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.MAP13 = !useGraphics; //Graphics enables CGA graphics MAP13, else text!
if (useGraphics && !GraphicsMode) //Special case? CGA monochrome mode?
{
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.OddEvenMode = 0; //Don't force odd/even mode!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.OEDisabled = 1; //Disable odd/even mode!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.READMAPSELECTREGISTER.ReadMapSelect = 0; //Only read map #0!
}
else //Revert to normal memory mode!
{
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.GRAPHICSMODEREGISTER.OddEvenMode = 1; //Force odd/even mode!
getActiveVGA()->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.OEDisabled = 0; //Disable odd/even mode!
getActiveVGA()->registers->GraphicsRegisters.REGISTERS.READMAPSELECTREGISTER.ReadMapSelect = 0; //Only read map #0!
}
}

Now the outputted text is readable, but still a bit too small.

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

Reply 106 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

How does this screen look if you don't force CGA but instead let your emulator emulate a VGA card (which itself is emulating CGA as a normal VGA would)? If it looks right in that configuration, you know it's a problem with how you're emulating CGA. If it looks the same, you know it's a problem with how you're emulating VGA.

For VGA's BIOS mode 6, my tables are showing that the map mask register has a value of 1, not 3. Also the "Odd/even memory access mode" should be disabled. There may be others as well - I don't know how your naming of the VGA registers corresponds to the one I'm familiar with.

Reply 107 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

The naming of the registers is the same as the FreeVGA documentation (except the Input Status 1 register's undefined bits, which are defined on the CGA).

I've switched my emulator to VGA mode. In that mode all CGA-specific stuff (colors, CRT etc) go wrong, but the text is correct and readable. I've made a dump of VGA registers and am now checking it out...

Edit: These are the dumped registers of the VGA at that time:

Filename
vga_registerdump_8088MPHcomparisontext.zip
File size
19.4 KiB
Downloads
43 downloads
File comment
VGA register dump of 8088 MPH comparing hardware on a VGA.
File license
Fair use/fair dealing exception

Just compared the dumps itself. The CGA doesn't use the high memory (Extended Memory bit 1 of the Sequencer Mode Control register). I'll try to force it to 1...

Edit: This doesn't change anything about the output. The only difference left are the CRTC registers itself(which should be correct afaik) and the memory wrapping applied to the CGA memory.

Edit: Disabling the memory wrapping applied to CGA memory(actually this only disables the high memory planes 2&3 for reading and wraps around 4K on MDA mode) didn't have any effect. So there's probably a problem with the CRTC registers needing different contents (besides attribute colors being 7 on a CGA instead of VGA's F).

Edit: It seems it actually enables byte mode on the VGA. This makes the horizontal timing correct somewhat, but odd/even scanlines and character positions now overlap strangely. Text gets printed over itself(odd/even lines) and the text appearing appears to be interlaced with black lines.

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

Reply 108 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

Ah, that makes sense. Remember that when you're using byte mode you have to double the values in the VGA's horizontal registers CRTC registers (this is why, e.g. Horizontal Display Enable End is 0x4f for mode 6 and 0x27 for mode 4).

This brings up something that you might have trouble with emulating CGA with VGA: what if you're in a word mode (i.e. 2bpp) and the CGA CRTC horizontal registers are programmed with odd numbers (e.g. horizontal displayed = 0x27 for a 312x200x4 mode)? I'm not sure offhand if the sprite/scrolling/vectorballs parts of 8088MPH use such a mode or not, but even if they don't a future demo might.

Another thing that's different between mode 4 and mode 6 is the Address Wrap Select bit (called "Display Address Unit 2 Remap" in https://botb.club/~edlinfan/textfiles/faqsys/video/vga.txt which was my only VGA reference back in the day) of the CRTC Mode Control Register, which is set to 0 for BIOS mode 6 and 1 for BIOS mode 4 by the IBM BIOS. I'm not sure if that makes any difference or not for this case.

Reply 109 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've managed to get the byte mode working. There's only four problems now(2 solved by a simple fix clearing plane 0 odd addresses and dividing horizontal CRT timing by 2(double width being rendered normally) when rendering pixels in byte mode):
1. Junk data shows up instead of black screens at the demo after the mode has been entered due to extended VRAM being used. I added a little VRAM plane 0 odd offset clearing to fix that.
2. Besides the 1K color modes only showing half of their vertical display, the parts using the 1K color mode (sprites, comparision, IBM logo rotating) only show half of their horizontal display(40 column display, but their vertical timings seem to be correct)? This has been fixed.
3. The faces before the credits only show half vertically and the first face is at the end wrapping around to the start of the faces.

Edit: I've fixed the sprites, comparision and IBM logo horizontal timing by applying horizontal division by 2 when using byte mode(only used with monochrome graphics):

word get_display_CGAMDA_x(VGA_Type *VGA, word x)
{
word result=0;
word column=x; //Unpatched x value!
if (!x) result |= VGA_SIGNAL_HRETRACEEND; //Horizontal retrace&blank is finished now!
column >>= 3; //Divide by 8 to get the character clock!

if (VGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.UseByteMode) //Byte mode seems to affect timings?
{
column >>= 1; //Half the horizontal timing!
x >>= 1; //Half the horizontal timing!
}

if (column>(VGA->registers->CGARegistersMasked[0])) //Past total specified?
{
result |= VGA_SIGNAL_HTOTAL; //End of display: start the next frame!
result |= VGA_SIGNAL_HSYNCRESET; //Reset HSync!
}
if (CGA_is_hsync(VGA,x)) //Horizontal sync?
{
result |= VGA_SIGNAL_HRETRACESTART; //Start horizontal sync!
}
else if (x && CGA_is_hsync(VGA,x-1)) //Previous was hsync?
{
result |= VGA_SIGNAL_HRETRACEEND; //End horizontal sync!
}
if (column<VGA->registers->CGARegistersMasked[1]) //Are we displayed?
{
result |= VGA_HACTIVEDISPLAY; //Horizontal displayed!
}
else
{
result |= VGA_OVERSCAN; //We're overscan by default!
}
return result; //Give the signal!
}

This seems to fix the horizontal timings to become twice as wide and view the whole 640x200 screen.

So the only problems that are currently left are the "dots are my favour's, unless they're saviours" part showing stripes(is this supposed to be horizontal stripes(though more oval, being 8 pixels in length and 1 pixel in height)) instead of round dots. Also it's in color instead of b/w.

The second problem that's still left is that the 1K screens only show half a screen vertically(100 pixels?).

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

Reply 110 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

So the only problems that are currently left are the "dots are my favour's, unless they're saviours" part showing stripes(is this supposed to be horizontal stripes(though more oval, being 8 pixels in length and 1 pixel in height)) instead of round dots. Also it's in color instead of b/w.

It's supposed to be in colour. Youtube's transcoding messes this up.

superfury wrote:

The second problem that's still left is that the 1K screens only show half a screen vertically(100 pixels?).

I wonder if this could be a status register problem. This effect works by polling the status register to figure out which scanline it's on. If the display enable bit changes four times per scanline instead of two then it'll run out of scanlines twice as fast as it's supposed to. This would also cause the image to be "squashed" vertically. If the bottom half if the image is missing then that's not the problem, and you've got some state within the VGA emulation that's determining whether to blank the screen or not.

Reply 111 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

The problem with the heads is still present. I've also changed the VGA calcultions to ignore offset register updates during CGA/MDA compatibility mode(preventing the offset register from overwriting the CGA horizontal display's value used instead).

This is the current 'offset register' processing for the CGA(The VGA just takes the offset register and shifts it left by 2):

			cgarowsize = (word)VGA->registers->CGARegistersMasked[1]; //We're the value of the displayed characters!
if (VGA->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.UseByteMode) //Word mode? Multiply it by 2!
{
cgarowsize <<= 1; //Convert from byte to word mode!
}
VGA->precalcs.rowsize = cgarowsize; //Apply the new row size!

This seems to work.

There are now thus five problems left with the demo:
- The command prompt after the credits is one row too high, being hidden behind the last line of the credits.
- The faces before the credits only show half (vertically) and the leftmost head's left half is on the right side of the image, at about the middle of the shiny blue/green glasses.
- The 1K images still only display 50%. The other half is black(looks like it's blanking for some reason).
- The Kefrens Bar effect is having lots of black screens with flashes of displayed raster bars as it should be showing all the time. Is the display enabled bit (bit 3 of the CGA Mode Control) being set to 0?
- The part of the credits from the point of "Viler Graphics multi-color hacking", then the third row after the "multi-color hacking" row just has four characters at positions ~2-3, the location of the first arrow, the location of the "M" of Multi-color and at the position of the "-" of Multi-color just has "_" at those places, all about 1 character long. After that is empty text (spaces, NULL characters or blanking of some kind?). The text just scrolls off the screen until only an empty display is left. Eventually the row before the row that says "coda greets: spring!" it starts again. The command prompt hiding behind the last row of 8088 MPH.
- The 16/256 colors part is constantly flashing, just like the Kefrens Bar effect(probably the same cause).
- The 3d objects still show lines instead of dots with dithering.

Currently bit 0 is 1 when retracing (either horizontal or vertical) and bit 3 when retracing vertically.

	VGA->registers->ExternalRegisters.INPUTSTATUS1REGISTER.VRetrace = vretrace; //Vertical retrace?

register byte isretrace;
isretrace = hretrace;
isretrace |= vretrace; //We're retracing?

//Retracing disables output!
VGA->registers->ExternalRegisters.INPUTSTATUS1REGISTER.DisplayDisabled = retracing = isretrace; //Vertical or horizontal retrace?

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

Reply 112 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

The problem with the heads is still present. I've also changed the VGA calcultions to ignore offset register updates during CGA/MDA compatibility mode(preventing the offset register from overwriting the CGA horizontal display's value used instead).

I don't think there's any code in 8088MPH that would change the value of the offset register...

superfury wrote:

- The command prompt after the credits is one row too high, being hidden behind the last line of the credits.

That could be a DOS and/or BIOS problem. At the end of the demo, all the CGA registers should be set up as for normal 40x25 text.

superfury wrote:

- The faces before the credits only show half (vertically) and the leftmost head's left half is on the right side of the image, at about the middle of the shiny blue/green glasses.

Not sure what's going on there. Are other 80-column text modes correct horizontally now?

superfury wrote:

- The Kefrens Bar effect is having lots of black screens with flashes of displayed raster bars as it should be showing all the time. Is the display enabled bit (bit 3 of the CGA Mode Control) being set to 0?

No. Timing issues could cause this, though.

superfury wrote:

- The part of the credits from the point of "Viler Graphics multi-color hacking", then the third row after the "multi-color hacking" row just has four characters at positions ~2-3, the location of the first arrow, the location of the "M" of Multi-color and at the position of the "-" of Multi-color just has "_" at those places, all about 1 character long. After that is empty text (spaces, NULL characters or blanking of some kind?). The text just scrolls off the screen until only an empty display is left. Eventually the row before the row that says "coda greets: spring!" it starts again.

This sounds like a problem with the RAM mirroring or CRTC wrapping. The 16kB of CGA RAM is visible at 0xb8000-0xbbfff and 0xbc000-0xbffff, and only the low 13 bits of the CRTC memory address lines are used, so if the CRTC goes past character 0x1fff (memory address 0xbbffe) then it wraps back around to character 0 (memory address 0xb8000).

superfury wrote:

- The 16/256 colors part is constantly flashing, just like the Kefrens Bar effect(probably the same cause).

Unlikely - this is a "set and forget" mode, no CRTC registers change after it starts.

superfury wrote:

- The 3d objects still show lines instead of dots with dithering.

How does it look on the RGBI output?

superfury wrote:

Currently bit 0 is 1 when retracing (either horizontal or vertical) and bit 3 when retracing vertically.

This isn't quite right. Bit 3 is 1 for vsync (the CRTC vsync, so 16 scanlines not 3), but bit 0 is "display disabled" so it is 0 whenever the raster beam is not over the active image area (i.e. it's 0 everywhere in horizontal/vertical overscan/retrace, not just retrace).

Reply 113 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

My emulation currently applies the offset to be wrapped around 0x3FFF(CGA) or 0xFFF(MDA). This should wrap it around 16K. Although logically thinking 256K=FFFF; 128K=3FFF, 64K=1FFF, 32K=FFF, 16K=3FF. Of course thinking in VGA memory mapping. But the farthest I can go is 0x3FFF(x4 planes). Any smaller (0x1FFF) and the Turbo XT BIOS will report an error #4(probably checking VRAM).

The empty text still happens during the credits.

The bits of the input status register #1 are adjusted to what you said. The problem still happens.

Snap 2016-04-11 at 19.25.08.png
Filename
Snap 2016-04-11 at 19.25.08.png
File size
14.28 KiB
Views
760 views
File comment
The RGB output of the 3d objects.
File license
Fair use/fair dealing exception

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

Reply 114 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

The empty text still happens during the credits.

What do the contents of CGA RAM look like at this point? If you set the start address such that it wraps around before the end of the screen, what address in CGA RAM does it read from after the wrap?

superfury wrote:

The bits of the input status register #1 are adjusted to what you said. The problem still happens.

Well, it was a long shot...

superfury wrote:
Snap 2016-04-11 at 19.25.08.png

This looks plausible. It gives me an idea about what's causing the stripes and otherwise incorrect colours on that screen, though. In 2bpp mode, are you doubling the pixels horizontally before feeding them to the CGA composite output stage and NTSC decoder? If not, you should be. The composite output code requires pixels at a rate corresponding to the pixel rate in 640x200 mode (i.e. 14.318MHz).

Reply 115 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

In 2bpp mode the pixels are single. They're not doubled horizontally nor vertically. But if I enable pixel doubling there, won't that render the whole NTSC conversion useless? And what about 40x25 text mode? Does that need to be doubled too?
Also do I need to force the CGA to run at 14MHz? When at 40x25 or 320x200, does the pixel rate need to be halved, like I found on Dosbox?

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

Reply 116 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

In 2bpp mode the pixels are single. They're not doubled horizontally nor vertically. But if I enable pixel doubling there, won't that render the whole NTSC conversion useless?

Why would it? The NTSC conversion requires pixels at 14.318MHz. In 2bpp mode, the pixel rate (i.e. 1/320 of the normal active width) is 7.16MHz, so the pixels require doubling before conversion. Think about it this way: in 1bpp and 2bpp mode, the image is still the same physical width on the monitor and the raster beam sweeps at the same speed so the pixel rate must be inversely proportional to the pixel width.

superfury wrote:

And what about 40x25 text mode? Does that need to be doubled too?

Yes, if it isn't already.

superfury wrote:

Also do I need to force the CGA to run at 14MHz?

What do you mean by "force the CGA to run at 14MHz"? Some parts of the CGA always run at 14.318MHz, some always at 7.16MHz, some always at 3.58MHz, some always at 1.79MHz, some always at 895kHz, some at either 14.318MHz or 7.16MHz depending on mode and some at either 1.79MHz or 895kHz depending on mode.

superfury wrote:

When at 40x25 or 320x200, does the pixel rate need to be halved, like I found on Dosbox?

In these modes the "pixels" (i.e. 1/8 of a character period) are at 7.16MHz. So they're double the width of the pixels in 80-column text mode (and double the width of the pixels that are required by the composite output and NTSC decoding stages).

Reply 117 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've modified the CGA to always render seperate pixels (double pixels taking 2 clocks) and normal pixels at the IBM PC clock (~14MHz). The 320x200(2bpp) and 40x25 modes now use double pixels(by using the dot clock rate set to 1). They also double the horizontal width specified by the CRTC registers (converting the 320x200 window to 640x200 display, since the double pixels(See VGA Dot Clock Rate register) only have effect on the pixels in active display).

This fixes most horizontal timing (except the faces). The colors are now correct everywhere. The only problem left is the faces image and that all 1K modes display only half the vertical display area(the bottom half being black).

About the half screen being blanked, I notice during the flower girl image that it fades in with only the top half of the screen, but when it fades out suddenly the whole display becomes visible during the "drip" effect used for fading out the image to continue the next part of the demo. This might be a hint what's the cause?

Actually, the flower girl is the image shown at https://trixter.oldskool.org/2015/04/07/8088- … your-emulators/ . Only the top half of that image is visible (the non-dripped scanlines), the bottom half being black. When that drip effect starts (the last effect on that image), the bottom becomes visible as well(not black anymore). Perhaps it's got something to do with the CGA start address register becoming too high halfway somehow?

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

Reply 118 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

About the half screen being blanked, I notice during the flower girl image that it fades in with only the top half of the screen, but when it fades out suddenly the whole display becomes visible during the "drip" effect used for fading out the image to continue the next part of the demo. This might be a hint what's the cause?

Indeed it is. I suspect you're not displaying the second 8kB region in text mode. In graphics mode, the second 8kB region is only visible on odd scanlines, but in text modes it works normally - if you set the start address to 0x1000 you'll see the data from address 0xba000 in the top-left corner of the active area.

Reply 119 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

It should have been written though:

OPTINLINE word applyCGAMDAWrap(VGA_Type *VGA, word offset)
{
if (CGAEMULATION_ENABLED(VGA)) //CGA emulation enabled? Quarter the memory installed!
{
offset &= 0x3FFF; //Apply CGA memory!
}
else if (MDAEMULATION_ENABLED(VGA)) //MDA emulation enabled? Quarter the memory installed more!
{
offset &= 0xFFF; //Apply MDA memory!
}
return offset; //Give the calculated offset!
}

//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!
uint_32 fulloffset2;

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

fulloffset2 = applyCGAMDAWrap(VGA,offset); //Apply wrapping according to the device!

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

if (CGAMDAEMULATION_ENABLED(VGA) && (plane&2)) return 0; //High planes on the CGA don't exist!

fulloffset2 = offset; //Default offset to use!
fulloffset2 <<= 2; //We cycle through the offsets!
fulloffset2 |= plane; //The plane goes from low to high, through all indexes!

fulloffset2 &= 0x3FFFF; //Wrap arround memory! Maximum of 256K memory!

if (!VGA->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.ExtendedMemory) fulloffset2 &= 0xFFFF; //Only 64K memory available, so wrap arround it!

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

void writeVRAMplane(VGA_Type *VGA, byte plane, word offset, byte value, byte mode) //Write to a VRAM plane!
{
if (!VGA) return; //Invalid VGA!
if (!VGA->VRAM_size) return; //No size!

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

offset = applyCGAMDAWrap(VGA,offset); //Apply wrapping according to the device!

plane &= 3; //Only 4 planes are available!

register uint_32 fulloffset2;
fulloffset2 = offset; //Load the offset!
fulloffset2 <<= 2; //We cycle through the offsets!
fulloffset2 |= plane; //The plane goes from low to high, through all indexes!
Show last 14 lines

fulloffset2 &= 0x3FFFF; //Wrap arround memory!

if (!VGA->registers->SequencerRegisters.REGISTERS.SEQUENCERMEMORYMODEREGISTER.ExtendedMemory) fulloffset2 &= 0xFFFF; //Only 64K memory available, so wrap arround it!

if (fulloffset2<VGA->VRAM_size) //VRAM valid, simple check?
{
VGA->VRAM[fulloffset2] = value; //Set the data in VRAM!
if (plane==2) //Character RAM updated?
{
VGA_plane2updated(VGA,offset); //Plane 2 has been updated!
}
}
}

This is the direct VRAM access functionality of the VGA/EGA/CGA/MDA adapter in my emulator.

Also, when applying a CGA mode:

	getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.MAP13 = !useGraphics; //Graphics enables CGA graphics MAP13, else text!
getActiveVGA()->registers->CRTControllerRegisters.REGISTERS.CRTCMODECONTROLREGISTER.AW = useGraphics?((GraphicsMode)?1:0):0; //CGA mapping is done by the renderer mapping CGA!

The VRAM retrieval in both graphics and text mode:

	//Now calculate and give the planes to be used!
planesbuffer[0] = readVRAMplane(VGA, 0, loadedlocation, 0x81); //Read plane 0!
planesbuffer[1] = readVRAMplane(VGA, 1, loadedlocation, 0x81); //Read plane 1!
planesbuffer[2] = readVRAMplane(VGA, 2, loadedlocation, 0x81); //Read plane 2!
planesbuffer[3] = readVRAMplane(VGA, 3, loadedlocation, 0x81); //Read plane 3!

The VRAM read and write mode is 0 when accessed by the CPU (this effectively disables address wrap and map13/14 patching, as these are only applied when rendering)

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