VOGONS


CGA on VGA emulation in x86EMU?

Topic actions

Reply 80 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Looking at what the Turbo XT BIOS does:

	mov	dx, 61h
in al, dx ; Read machine flags
or al, 00110000b ; clear old parity error
out dx, al ; Write them back to reset
and al, 11001111b ; enable parity
out dx, al ; Write back, parity enabled
mov al, 80h ; allow NMI interrupts
out 0A0h, al
mov ax, 0000000000110000b ; Assume monochrome video
mov [ds:10h], ax ; card has been installed
int 10h ; initialize if present
mov ax,0000000000100000b ; Assume color/graphics video
mov [ds:10h], ax ; card has been installed
int 10h ; initialize if present

ifdef IBM_PC ; Read 5150 switch config
mov al, 0CCh
out dx, al ; Reset keyboard
in al, 60h ; Read config switches
mov ah, al
else ; Read 5160 switch config
in al, 62h ; Get memory size (64K bytes)
and al, 00001111b ; in bits 2,3 low nibble
mov ah, al ; Save memory size nibble
mov al, 10101101b
out dx, al
in al, 62h ; Get number of floppies (0-3)
endif
mov cl, 4 ; and init video mode
shl al, cl ; shift in hi nibble
or al, ah
mov ah, 0

mov [ds:10h], ax ; Start building Equipment Flag
and al, 00110000b ; if video card, mode set
jnz @@video_found ; found video interface
mov ax, offset dummy_int ; No hardware, dummy_int becomes
mov [es:40h], ax ; int_10 video service
jmp short @@skip_video

@@video_found:
call video_init ; Setup video

@@skip_video:
mov al, 00001000b ; Read low switches
out dx, al

It seems writes to port 61h somehow affect the values of port 62h to respond with different values giving information about the machine?

Edit: Looking at the ioports.lst of Bochs does indeed reveal something about it:

0061	w	PPI  Programmable Peripheral Interface 8255 (XT only)
system control port
bit 7 = 1 clear keyboard
bit 6 = 0 hold keyboard clock low
bit 5 = 0 I/O check enable
bit 4 = 0 RAM parity check enable
bit 3 = 0 read low switches
bit 2 reserved, often used as turbo switch
bit 1 = 1 speaker data enable
bit 0 = 1 timer 2 gate to speaker enable

It seems bit 3 toggles something to let port 62h return different values (low/high switches)?

Edit: It looks like I was right, although setting up for two floppy disk drives wasn't so simple as I thought:

byte readPPI62()
{
byte result=0;
//Setup PPI62 as defined by System Control Port B!
if (EMULATED_CPU<=CPU_80186) //XT machine?
{
if (SystemControlPortB&8) //Read high switches?
{
if (((getActiveVGA()->registers->specialCGAflags&0x81)==1)) //Pure CGA mode?
{
result |= 2; //First bit set: 80x25 CGA!
}
else if (((getActiveVGA()->registers->specialMDAflags&0x81)==1)) //Pure MDA mode?
{
result |= 3; //Both bits set: 80x25 MDA!
}
else //VGA?
{
//Leave PPI62 at zero for VGA: we're in need of auto detection!
}
result |= 4; //Two floppy drives installed!
}
else //Read low switches?
{
result |= 1; //Two floppy drives installed!
}
}
else
{
return PPI62; //Give the normal value!
}
return result; //Give the switches requested, if any!
}

byte PPI_readIO(word port, byte *result)
{
switch (port) //Special register: System control port B!
{
case 0x61: //System control port B?
*result = SystemControlPortB; //Read the value!
return 1;
break;
case 0x62: //PPI62?
*result = readPPI62(); //Read the value!
return 1;
break;
case 0x63: //PPI63?
*result = PPI63; //Read the value!
return 1;
break;
case 0x92: //System control port A?
*result = SystemControlPortA; //Read the value!
return 1;
break;
default: //unknown port?
break;
}
return 0; //No PPI!
}

Show last 40 lines
byte PPI_writeIO(word port, byte value)
{
switch (port)
{
case 0x61: //System control port B?
SystemControlPortB = (value&0x7F); //Set the port, highest bit isn't ours!
return 1;
break;
case 0x62: //PPI62?
//PPI62 = value; //Set the value!
return 1;
break;
case 0x63: //PPI63?
PPI63 = value; //Set the value!
return 1;
break;
case 0x92: //System control port A?
MMU_setA20(1,value&2); //Fast A20!
if (value&1) //Fast reset?
{
doneCPU();
resetCPU(); //Reset the CPU!
}
SystemControlPortA = (value&(~1)); //Set the port!
return 1;
break;
default: //unknown port?
break;
}
return 0; //No PPI!
}

void initPPI()
{
SystemControlPortB = 0x7F; //Reset system control port B!
PPI63 = 0x00; //Set the default switches!

register_PORTIN(&PPI_readIO);
register_PORTOUT(&PPI_writeIO);
}

Bits 0-1 of the high switches seem to select the video adapter installed (according to the ioports.lst's values).
Bit 0 of the low switches sets 1 floppy disk when set without bit 2 of the high switches.
If bit 0 of the low switches and bit 2 of the high switches are both set, it sets 2 floppy disks it seems.
Any other combination seems to set no floppy disks at all it seems.

Anyone can confirm this or add information to this?

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

Reply 81 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I'm now trying to run Ultima II on the CGA adapter to test odd/even memory plane generation. I notice that both there and in CheckIt Diagnostics the output is quite blocky, like the odd or even scanlines are duplicated.

This is the active display displaying each line twice (it's in linear memory mode, so the lines follow each other, register 08h is 02h).

Anyone knows what the Blink rate settings are with the CGA?
Setting the rate to 0 means constant On according to the manual(https://github.com/achernya/iap-6.828-website … /vgadoc/CGA.TXT says blink rate).
Setting the rate to 1 means constant Off according to the manual.
Settings the rate to 2 means each 16 frames on->off or off->on? CGA.TXT says blink rate (8 frames on, 8 frames off? Or is it 16 frames on, 16 frames off(VGA compatible values), as the manual says?)?
Setting the rate to 3 means each 32 frames on->off or off->on? CGA.TXT says half blink rate(16 frames on, 16 frames off? Or is it 8 frames on, 8 frames off?)

The manual just says every 16(2) or 32(3) frames it toggles the blink in it's reversed state(0->1 or 1->0)? Dosbox seems to use the 8 blink speed? How many frames do need to be skipped every of those 4 CGA cursor blink settings? Does 0 even blink? 1 seems to be off. Does 2 blink every 16 or 8 frames? Does 3 blink every 32 or 16 frames?

Edit: I currently use 8 for mode 0(Also VGA cursor speed), mode1=disabled, mode 2=16 frames(Text blink, mode 3=32 frames.

Also, I've fixed the 4-color border: it was clearing the border with 4-color mode. It now sets it to 0 for monochrome/composite graphics(640x200 resolution) and palette register color (lower 5 bits) for border&attribute 0. This fixes 8088 MPH's border&background during the Kefrens Bars. Although the border is shifted up one line comparing to output due to the CRT increasing the line at htotal(Thus starting the new line at every active display start, shifting the active display one line down in comparison with the overscan, but for the left border only).

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

Reply 82 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

For some reason I notice that the overscan actually is shifted one line up at the left and right borders. It increases the rendering buffer scanline every time the horizontal total is reached. Anyone? Stuff like the Kefrens Bars and the CGA Compatibility tester's "horizontal retrace test" both suffer from this. The right border is OK, but the left border is actually always shifting up one pixels it seems (it's also vibrating a bit)?

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

Reply 83 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Anyone knows why my CGA and CGA-on-VGA compatibility mode (Essentially VGA switching to CGA mode when the display is enabled through the CGA Mode Control Register bit 3. Also the CGA CRTC is then enabled by setting the VGA Vertical Retrace (or Total?) Protect bit on(which usually protects CRTC registers 0-7 to become(partially in the case of the overflow register) read-only. Only the split screen bit is then writable on the VGA. The CGA CRTC mode remaps all CRTC registers to CGA registers and disables CGA/VGA registers when enabled).

I think there might be a bug with the CGA register?

OPTINLINE void VGA_Sequencer_updateRow(VGA_Type *VGA, SEQ_DATA *Sequencer)
{
register word row;
register uint_32 charystart;
row = Sequencer->Scanline; //Default: our normal scanline!
if (row>VGA->precalcs.topwindowstart) //Splitscreen operations?
{
row -= VGA->precalcs.topwindowstart; //This starts after the row specified, at row #0!
--row; //We start at row #0, not row #1(1 after topwindowstart).
}
row >>= VGA->precalcs.scandoubling; //Apply Scan Doubling on the row scan counter: we take effect on content (double scanning)!
Sequencer->rowscancounter = row; //Set the current row scan counter!

byte oddCGAmemory; //High CGA memory to apply?
oddCGAmemory = 0; //Default: normal sequential lines!
if (CGAMDAEMULATION_RENDER(VGA)) //CGA mode?
{
switch (VGA->registers->CGARegisters[8]&3) //What CGA row mode?
{
case 0:
case 2: //Normal mode?
//No special effect! We just increase in low memory linearly!
break;
//Odd/even memory modes?
case 1: //Even scanlines divide by 2, Odd scanlines equal to the even ones, but higher memory(0,0,1,1,2,2,3,3 as E,O,E,O,E,O)!
oddCGAmemory = Sequencer->Scanline&1; //High when odd rows!
row >>= 1; //Divide by 2(half the rate)!
break;
case 3: //Even scanlines are even numbers, Odd scanlines are odd numbers (0,1,2,3,4,5,6,7 as E,O,E,O,E,O)
oddCGAmemory = Sequencer->Scanline&1; //High when odd rows!
break;
}
}

row >>= VGA->precalcs.CRTCModeControlRegister_SLDIV; //Apply scanline division to the current row timing!
row <<= 1; //We're always a multiple of 2 by index into charrowstatus!

//Row now is an index into charrowstatus
word *currowstatus = &VGA->CRTC.charrowstatus[row]; //Current row status!
Sequencer->chary = row = *currowstatus++; //First is chary (effective character/graphics row)!
Sequencer->charinner_y = *currowstatus; //Second is charinner_y!

charystart = getVRAMScanlineStart(VGA, row); //Calculate row start!
if (oddCGAmemory) //Odd CGA memory field?
{
charystart += getVRAMScanlineStart(VGA,VGA->registers->CGARegistersMasked[6]); //Apply the odd scanline source!
}
charystart += Sequencer->startmap; //Calculate the start of the map while we're at it: it's faster this way!
charystart += Sequencer->bytepanning; //Apply byte panning!
Sequencer->charystart = charystart; //What row to start with our pixels!

//Some attribute controller special 8-bit mode support!
Sequencer->active_nibblerate = 0; //Reset pixel load rate status & nibble load rate status for odd sized screens.
Sequencer->extrastatus = &VGA->CRTC.extrahorizontalstatus[0]; //Start our extra status at the beginning of the row!

VGA_loadcharacterplanes(VGA, Sequencer, 0); //Initialise the character planes for usage!
}

The scan doubling and SLDIV should be disabled(0), since it's in CGA mode.

Strangely enough, Ultima II programs it in mode 2? This would mean the same as mode 0: linear scanline addresses. But the video mode itself is an odd/even(CGA Mode 1) when on a VGA and according to mode 4/5/6h graphics layout? Anyone knows about this? Why is it using a linear mode with 2 lines per pixel(doublescanned by setting the character height register to 01h) instead of 1 line per pixel with mode 1h according to graphics RAM documentations(as I think the CGA should be programmed in modes 4/5/6 according to the docs: 1 line per pixel, interleaved scanlines double scanned according to the Moterola 6845 chip documentation)?

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

Reply 84 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

I think you're confusing the CRTC interlace mode bits with the CGA memory layout. Normal CGA modes are non-interlaced from the CRTC's perspective (neither interlace-sync nor interlace-sync-and-video). The row counter in the MC6845 is 7 bits wide but we want to generate 262 scanlines. Hence we have to program it for 2 scanlines per row or more, or we'll run out of rows long before vsync. That means we need to use the RA0 (row address 0 - i.e. the low bit of the scanline address within the row) output line from the CRTC to distinguish between even and odd scanlines (within the progressive frame - the odd scanlines I'm talking about here are not in a separate field). We need to look at different CGA VRAM addresses when RA0=1 than when RA0=0, and the way the CGA's designers chose to do that (for better or for worse) is to use it to select between 8kB regions. Hence (in graphics modes) the even scanlines are at 0xb8000-0xb9fff and the odd scanlines are at 0xba000-0xbbfff. The CGA's memory interlacing and the CRTC's interlace modes are totally separate things - the latter has twice the vertical spatial frequency for a start. CGA memory interlacing alternates with a frequency of 100 times over the normal vertical active area, and CRTC interlacing would (if it worked) alternate fields 200 times over the normal vertical active area (400 interlaced scanlines total over the course of a 30Hz frame).

Reply 85 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

So the bit0 of the scanline counter should be used when the interlace register isn't 0 or 2 to add vertical display end lines to the current address is correct? But what do I have to do with modes 1/3? What's the effect of those(looking at VGA processing)? It's 2 in both text and CGA 4-color modes. Text modes aren't interlaced, but the graphics mode is, although the register says it isn't? Do I need to force interlacing when in graphics mode? What do values 1&3 do exactly? What's the difference(when patching to VGA register values)?

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

Reply 86 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie

The CRTC interlace mode register (R8) has no equivalent in VGA because the VGA CRTC does not support interlaced sync. The effect of mode 1 is to add an extra scanline every other field, and to start/end the CRTC vsync pulse half a scanline later every other field (though the CGA delays the vsync pulse from the CGA until the next hsync pulse, so you don't actually get an interlaced display from a CGA card even with R8=1). The effect of mode 3 is the same as mode 1 except that the CRTC counts up two scanlines instead of 1 and generates twice as many character rows as it's programmed for. There is no published CGA software that uses R8=1 or R8=3 so you probably don't want to worry about the effect of R8 at all - you have no software to test it with.

Again you are saying that the graphics mode is interlaced and are confusing CGA memory interlacing with CRTC interlacing. The graphics modes have memory interlacing - when bit 1 of CGA port 0x3d8 is set, the equivalent bit in VGA's emulation of CGA is bit 0 of CRTC Mode Control register 0x17 being cleared ("Emulate CGA interlacing" in "Display Address 13 Remap Row 0"). That essentially causes RA0 instead of MA13 to select between the two 8kB regions.

Reply 87 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've seemed to fix the mode by removing the given even/odd adressing and applying MAP13=0 with graphics modes and MAP13=1 with text modes. That fixes normal text and graphics modes within cga_comp(except the composite tests, while still display the problems with black lines). 8088MPH still has the same display errors for some reason with the 320x200 line modes (both the 4-color Intel logo and picture with the car) doubling the lines instead of low/high memory?

Edit: It seems to have something to do with the 640x200 color composite mode? Is the VRAM interpreted differently in that mode? Or is it a normal 640x200 mode? Vertically it's probably correct(normal 640x200 mode)? Horizontally it's partly correct: The middle is still the middle, but any text comes out garbled?

The attachment Snap 2016-04-07 at 10.11.05.png is no longer available

Stuff using the normal mode 4/5h show up correct now(Ultima II shows no errors).

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

Reply 88 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

Edit: It seems to have something to do with the 640x200 color composite mode? Is the VRAM interpreted differently in that mode?

Composite isn't a mode, it's an output. The CGA card will display on both the composite and RGBI outputs at the same time. The +BW mode bit (bit 2 of port 0x3d8) disables the color carrier and color burst on the composite output if set, and also forces 2bpp graphics modes to use the (3, 4, 7) palette instead of the (2, 4, 6) or (3, 5, 7) palettes. It has no effect on VRAM layout.

Reply 89 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Then do you know why all those composite modes (see last screen capture. Also applies to the intro screen with the car(and all related screens, like the new vs old CGA detection screen) and all CGA Compatibility Tester (also the same new vs old CGA detection screen still showing black lines and horizontally is garbled up like the last screen capture). Vertical output should be correct.

A screen capture of the above while set to RGB mode(showing the raw source pixels better):

The attachment Snap 2016-04-07 at 11.58.03.png is no longer available

Also the information says something about that if the text is wrong, the fault might be that the BIOS isn't fully CGA compatible(font-wise)?

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

Reply 90 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've removed the odd/even code in the sequencer for the CGA, perform MAP13 on CGA depending on graphics mode(0) or text mode(1), improved clocks to full accuracy(using divisions instead of numbers, the only one missing is the VGA 28MHz clock, which is still the old number(probably rounded)), added a CGA aspect ratio option besides the 4:3 aspect ratio(The 376.25:242.5 aspect ratio according to your article at http://www.reenigne.org/blog/what-is-the-cga- … -ratio-exactly/ ). I've also changed the row scan counter source to become the charinner_y of the current character (the current scanline rendering within the character, so in the CGA this is the range of 0-7, 0-1 or 0-0 depending on the character height set(8 pixels, 2 pixels(graphics normally, or 8088MPH text mode 1K color image afaik) or single lines(is this even used? Setting the maximum scanline register to 0 on a CGA? Since all graphics modes are 200 lines using 2-line graphics with odd/even mode? Theoretically 100-line modes can be archieved by both text and graphics mode(vertical total 100 is within the CGA range)?))).

I've also changed the CRT emulation to perform increase in scanline in the buffer and on the screen during horizontal retrace? Is this correct? (Originally during horizontal total, but the monitor won't know about it since there's no horizontal reset/total line(internal to the video card), thus it's probably using the retrace lines?)

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

Reply 91 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

improved clocks to full accuracy(using divisions instead of numbers, the only one missing is the VGA 28MHz clock, which is still the old number(probably rounded))

I think the exact values for 14.318MHz, 25.175MHz and 28.322MHz are 15.75/1.1, 25.2/1.001 and 28.35/1.001 respectively (the VGA pixel clocks are 160/91 and 180/91 times the CGA pixel clock). This gives a VGA frame rate of 60Hz/1.001, matching the field rate of standard (not CGA) NTSC.

superfury wrote:

added a CGA aspect ratio option besides the 4:3 aspect ratio(The 376.25:242.5 aspect ratio according to your article at http://www.reenigne.org/blog/what-is-the-cga- … -ratio-exactly/ )

That's a strange choice - the 376.25 is the low end of a range (the high end is 379.83). That also measures the full 4:3 NTSC active area in units of CGA pixels - it's not a screen aspect ratio in itself.

A better choice might be to allow a CGA pixel aspect ratio of 6:7 as well as 5:6. That's what you get if you take the standard "square pixels" NTSC sample rate of 13.5MHz/1.1 and force the pixels you'd get from that to be exactly square - see the discussion at http://www.vcfed.org/forum/showthread.php?518 … 153-CGA-monitor for more details.

superfury wrote:

single lines(is this even used? Setting the maximum scanline register to 0 on a CGA? Since all graphics modes are 200 lines using 2-line graphics with odd/even mode?

It's used in some 8088MPH effects, but you can't do "set and forget" modes with standard sync pulses that way - you need to change CRTC register values multiple times per frame.

superfury wrote:

Theoretically 100-line modes can be archieved by both text and graphics mode(vertical total 100 is within the CGA range)?))).

The "vertical total adjust" register only goes up to 31. You need to generate 262 scanlines but with R9=0 the largest number of scanlines you can do in a "set and forget" mode would be 128*1+31 = 159.

superfury wrote:

I've also changed the CRT emulation to perform increase in scanline in the buffer and on the screen during horizontal retrace? Is this correct? (Originally during horizontal total, but the monitor won't know about it since there's no horizontal reset/total line(internal to the video card), thus it's probably using the retrace lines?)

I'm not sure what difference it would make. Indeed the monitor doesn't know when the CRTC reaches horizontal total - it only knows about the video data and sync pulses.

Reply 92 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

I've changed the timing according to your information. I've changed the horizontal timing of the CGA aspect mode to use 379.83 pixels of width.

Although some screens are only half shown now (the 1K screens) for some reason. The left border seems to be shifted up one pixel compared to the rest of the screen during the Kefrens effect. Also the screen is blinking black/image very fast, but a bit better than earlier(maybe because of better accurate timing?). Although there seems to be some kind of 'tearing' in those images (black scanlines)?

There's now also some kind of black dots/lines on the 3d objects (The donut etc.) that weren't there before I made those timings more accurate. Pausing the emulator reveals that those dot patterns (as they're shown in the final version on the new CGA hardware) are currently displayed as horizontal lines instead.

One thing that has become better (and changed once again) is the colors on the screen during the demo (at least during those 3d objects, there's different colors now).

Also, about the difference increasing the emulated CGA/VGA buffer scanline at the horizontal retrace, together with the CRTC rendering line number, will have effect on anything from after the retrace ends up to the point of active display. In this case it's the overscan area. It maybe seen when looking at the Kefrens effect(as it continuously modifies the background color each scanline). If it isn't handling that during horizontal retrace (when done with the right side of the screen), a bit of overscan(inactive display essentially, unless blanked) follows horizontal retrace before horizontal total is reached and the software refreshes the color upon each horizontal retrace (I think 8088 MPH might actually be doing this, or trying to do it in time(assuming 100% accurate timing(or close) on the 8088 is implemented)?) then it will draw the next scanline's color(which is assumed after retracing horizontally is finished) on the left of the older scanline. After that htotal is reached and active display starts with the normal content and new background color. After horizontal display ends and overscan starts, the overscan will have the new color. Then this whole thing repeats again. This will happen for every scanline rendered(assuming the overscan is changed on horizontal retrace every scanline).

So you'll get the following overscan colors (assuming the overscan border/background color is increased by 1 every scanline. The numbers are the color index, A is active display, assuming only one character row of 8 pixels height displayed with the color used wrapping around 3 bits (values 0-7 used as color indexes)):

11111AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA00000
22222AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA11111
33333AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA22222
44444AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA33333
55555AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA44444
66666AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA55555
77777AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA66666
00000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA77777

This is assuming a timing of:
1. Some Active display at 0(truncated)
2. 5 pixels overscan to get a border on the right
3. Some retrace period
4. 5 pixels overscan to get a border on the left
5. Horizontal total

The above shows the problem with increasing the framebuffer on horizontal total: horizotnal retrace moves the beam down, but the buffer output isn't moved to the next line until horizontal total(and thus, active display) is reached. When the program increases the color index each line, that's what you'll see.

If increasing the buffer line happens on retrace(moving the CRT to the start of the next line), the left and right borders should be on the same row.

So whether it's increased on retrace or on horizontal total makes a big difference (this is probably what's happening in my emulator with the Kefrens Bars?). This also happens during the bars used in the Horizontal retrace test of CGA Compatiblilty Tester.

Also, the vertical retrace tests currently reports my CGA to use an averaged display and refresh cycle of 16769usecs. It's supposed to be 16689usecs according to what it says. Although no refresh or memory access slowdown is emulated. Pixel clock is emulated though, along with all other hardware timing (only CPU timing(limited to 8 cycles/instruction) and hardware access delays(CGA delays accessing VRAM and I/O ports) aren't emulated). It looks like the left side of the effect is shaking vertically, like water heating up. This is probably because the timing expects certain timing of the CGA, but the CGA rendering timings are constant, while the CPU isn't(since each instruction takes the same time). Although this won't happen if the CPU uses the PIT for timing(which has a constant rate).

Running the compatiblity tester's row reprogramming looks like the monitor emulation constantly loses sync(as far as I can see).

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

Reply 93 of 187, by reenigne

User metadata
Rank Oldbie
Rank
Oldbie
superfury wrote:

I think 8088 MPH might actually be doing this, or trying to do it in time(assuming 100% accurate timing(or close) on the 8088 is implemented)?

Yes, if the timing is correct the palette register will be changed at exactly the same position on each scanline, and (in the final version) the place it changes should be neatly hidden in the part of the overscan that is hidden behind the bezel.

superfury wrote:

So whether it's increased on retrace or on horizontal total makes a big difference

The palette register change takes effect immediately, not on retrace or horizontal total.

superfury wrote:

Although this won't happen if the CPU uses the PIT for timing(which has a constant rate).

Unfortunately interrupts have a lot of overhead, so I didn't use them for timing of the Kefrens effect.

Reply 94 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

This is what I get using the Compatibility tester losing sync afaik:
https://www.youtube.com/watch?v=XLnkqFQvfjQ

I meant the moment the palette register is reloaded affecting what line it's drawn on. If it's reloaded before htotal(but after hretrace makes it change the value), the overscan left on the left side of old line(which was rendering before retrace) will have the new color drawn. Then the new line renders the active display until overscan, which is also draws that new color until retrace is hit again. Thus the shift mentioned in my previous post(see image with numbers and Active display). If it's done on retrace instead of totaling(increasing the source scanline(VRAM location effectively) together with the destination(CRT)) this won't happen, as the new data will render on the new row instead of the old row (until totalling).

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

Reply 95 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Also two things going wrong right now: 1K screens only show half screen of content. The other half(bottom half) is black for some reason. And there's still the problem by what seems to be the sprite (compiler?) parts with the man on the car scanlines being offset to the right(every line moves right a bit. They seem to move from the top left(first scanline) to the center right(the image being tilted about 315 degrees instead of being straight as an effect. Did you do something strange in that mode with vertical timing(row size it seems) that's different? It looks like the offset register is set too high?

Also I didn't implement the color composite mode yet. Does this part use that? Although I think the NTSC conversion already handles that?

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

Reply 96 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

Does the color composite mode add different memory addressing or decoding? Like 1-bit(640x200) and 2-bit(320x200) pixel decoding? Or does it only affect the NTSC converter?

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

Reply 97 of 187, by Scali

User metadata
Rank l33t
Rank
l33t
reenigne wrote:

The palette register change takes effect immediately, not on retrace or horizontal total.

Indeed. Sadly I have yet to see a PC emulator that supports this. They all cheap out and perform rendering only once per scanline (or sometimes even once per frame). People may actually start to think that this is really how the hardware works.

http://scalibq.wordpress.com/just-keeping-it- … ro-programming/

Reply 98 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

In x86EMU the palette register DOES take effect immediately once it's written to. In the case of overscan it's only the case that it needs to be rendering overscan to render that color. It's simply rendering on the virtual CRT just like an actual monitor(using the VGA or CGA/MDA timings specified by the software).
Changing the palette in the middle of a scanline will of course only affect the pixels the virtual beam(located at VGA->CRTC.x and VGA->CRTC.y) hasn't drawn yet, just like a real monitor. The monitor beam just moves at the speed of the given clock(~25M, ~28M, ~14M or ~7M movements per second, depending on the device(VGA or CGA/MDA) and pixel clock used(Determined by the CGA mode control register bit 0 or VGA Misc Output Register's Clock Select).

So essentially, x86EMU performs timing with pixel accuracy. Although it will move in small blocks or single pixels depending on the time elapsed between CPU instructions(so 1 cycle of 1us will make the VGA render/move 1us in scanline time, depending on the clock used for the device(25/28/14/7MHz).

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

Reply 99 of 187, by superfury

User metadata
Rank l33t++
Rank
l33t++

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?

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