VOGONS


First post, by GloriousCow

User metadata
Rank Member
Rank
Member

Thought I'd start a new thread for this as it's an interesting discussion that could go on for a while.

The discussion began here: Re: MartyPC

CGA snow is a visual artifact generated by CPU-CGA bus contention in the high-resolution mode of the CGA due to the fixed READY suppression timing of the CGA card not adapting to the HCHAR character clock. Therefore READY is reasserted too soon on bus access in 80-column mode and artifacts appear on the screen in single-row spans of 8 pixels as incorrect bytes are used for glyph and attribute lookup during scanout of a single character gylph row.

Some reading on CGA wait states:
https://www.reenigne.org/blog/the-cga-wait-states/
https://martypc.blogspot.com/2023/05/explorin … ait-states.html

PCRetroTech has an excellent video on the CGA in general but explores CGA snow as well:
https://www.youtube.com/watch?v=IQ2UeIx1qIA
point in video where snow is discussed:
https://youtu.be/IQ2UeIx1qIA?t=2128

Emulating snow exactly, in theory, requires sub-instruction accuracy; consider a single MOVSW instruction from VRAM to VRAM on an 8088 could have 4 bus operations, each with their own set of wait states and potentially resulting in 4 'snowflakes' on screen.

The CGA device must be either ticked to update its clock to the CPU's T3 on each transfer, or some sort of data provided to the CGA on MMIO regarding the bus timings for snow post-calculation. The latter is probably more performant. The former would strictly be more 'accurate', as a program could 'race the beam' with VRAM writes, but of course, would be drawing snow all over while doing so; however, this could be intentional in the case of a theoretical demo that precisely controls the appearance of snow using lockstep.

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 1 of 19, by GloriousCow

User metadata
Rank Member
Rank
Member

My first attempt at emulating CGA snow in MartyPC is only capable for accounting for a single bus transaction per instruction.

Here's a comparison of MartyPC's snow (top) vs a frame capture from an RGB2HDMI device off an original IBM CGA card:

marty_snow02.png
Filename
marty_snow02.png
File size
10.82 KiB
Views
1729 views
File comment
MartyPC snow emulation, 02
File license
Public domain

This is the snow test from the CGA_COMP utility:
https://github.com/MobyGamer/CGACompatibility … GATTEST.PAS#L19

The snow is generated by using MOVSW to do VRAM-VRAM copies after the raster has proceeded past the text at the top of the screen, to leave it unaffected. Given the four total bus transfers, a lot more snow is generated.
I surmise that the character bytes for the displayed text in video memory being copied generate the initial variety of different colors within the snow immediately below; after we proceed past that the snow becomes either white or green. I am not sure where the green comes from.

You can clearly see the effect of wait states here; in that the snow only appears every other HCHAR.

Last edited by GloriousCow on 2023-07-11, 12:25. Edited 1 time in total.

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 2 of 19, by GloriousCow

User metadata
Rank Member
Rank
Member
superfury wrote on 2023-07-11, 08:45:

Well, the waitstates on the CGA memory read/write (from the CPU) is from the point of the T1(start of memory access) until the next match on the CGA rendering (First straight 8 hdots, then waiting for modulo 15 on the pixel counter to become 0 (next lchar). Said counter for that increases every video card clock. It's never reset.
After that lchar (modulo 15)==0 match, the CPU will start the next access to VRAM. During that entire part, the BIU is effectively halted in Tw state, with the buffer (the latch) kept filled because of the VRAM access.

Why T1? The CGA is not even aware the CPU is accessing it on T1. The IOREADY logic on the CGA is triggered by MEMR or MEMW, which don't signal until T2.

superfury wrote on 2023-07-11, 08:45:

Edit: After some more work on the BIU and CGA (to make it properly count the waitstates and keep the BIU in T1 state) it now seems to work properly.

It tries to execute a memory access first. Then if any waitstates occur on the access, the T1 state is kept to try again next time and the access is transformed into a waitstate access instead on the BIU.

superfury wrote on 2023-07-11, 08:45:

since the BIU/CPU isn't halted at that point anymore, it will actually proceed to T2 at that point until the operation finishes.

I'm a little confused by your description of how you operate wait states. Wait states are inserted after T3 if READY is not asserted, until it is. Wait states do not keep the CPU in T1.

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 3 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++
GloriousCow wrote on 2023-07-11, 12:23:
Why T1? The CGA is not even aware the CPU is accessing it on T1. The IOREADY logic on the CGA is triggered by MEMR or MEMW, wh […]
Show full quote
superfury wrote on 2023-07-11, 08:45:

Well, the waitstates on the CGA memory read/write (from the CPU) is from the point of the T1(start of memory access) until the next match on the CGA rendering (First straight 8 hdots, then waiting for modulo 15 on the pixel counter to become 0 (next lchar). Said counter for that increases every video card clock. It's never reset.
After that lchar (modulo 15)==0 match, the CPU will start the next access to VRAM. During that entire part, the BIU is effectively halted in Tw state, with the buffer (the latch) kept filled because of the VRAM access.

Why T1? The CGA is not even aware the CPU is accessing it on T1. The IOREADY logic on the CGA is triggered by MEMR or MEMW, which don't signal until T2.

superfury wrote on 2023-07-11, 08:45:

Edit: After some more work on the BIU and CGA (to make it properly count the waitstates and keep the BIU in T1 state) it now seems to work properly.

It tries to execute a memory access first. Then if any waitstates occur on the access, the T1 state is kept to try again next time and the access is transformed into a waitstate access instead on the BIU.

superfury wrote on 2023-07-11, 08:45:

since the BIU/CPU isn't halted at that point anymore, it will actually proceed to T2 at that point until the operation finishes.

I'm a little confused by your description of how you operate wait states. Wait states are inserted after T3 if READY is not asserted, until it is. Wait states do not keep the CPU in T1.

Noticed that as well when looking on the net.

I've modified the BIU to check for operations to do on T1, then tick until T3, at which point the actual operation (previously T1) is executed, with waitstates until T4 after waitstates (if any). T4 is simply a result cycle resetting to T1 and giving the EU the result on the very next cycle (and telling it it's OK to make new requests). The only issue is that on T3 the BIU doesn't save a status of what T1 was (if it's a request from EU or a prefetch), so if a request happens to be buffered while starting because of a prefetch, the EU request will override the fetch when T3 is reached. That should still be fixed.

And obviously, when implementing that new BIU behaviour I've managed to break the entire CPU...
Getting an INT FFh instruction now 😖
Edit: OK. The source is an INTA cycle.

Last edited by superfury on 2023-07-11, 16:27. Edited 1 time in total.

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

Reply 4 of 19, by GloriousCow

User metadata
Rank Member
Rank
Member
superfury wrote on 2023-07-11, 16:08:

I've modified the BIU to check for operations to do on T1, then tick until T3, at which point the actual operation (previously T1) is executed, with waitstates until T4 after waitstates (if any). T4 is simply a result cycle resetting to T1 and giving the EU the result on the very next cycle (and telling it it's OK to make new requests). The only issue is that on T3 the BIU doesn't save a status of what T1 was (if it's a request from EU or a prefetch), so if a request happens to be buffered while starting because of a prefetch, the EU request will override the fetch when T3 is reached. That should still be fixed.

If i'm reading this right, you're doing the read/write and *then* doing the wait states, where, to be accurate, the CPU executes wait states and then finally does the transfer on the last Tw cycle.

I guess there's a decent enough reason to do it the former way, because it's hard to have a single mmio read/write function that both reports wait states and does the transfer at the same time, because the former has to happen before the latter, so its sort of a chicken/egg scenario. My solution was to have a separate mmio function that just gets wait states from a device on T2, before the transfer. This simulates the CGA card seeing MEMR/MEMW, when it would deassert READY, although I don't directly model the READY line.

This has a performance hit, of course, as now i'm resolving MMIO lookups twice per bus operation...

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 5 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++
GloriousCow wrote on 2023-07-11, 16:25:
If i'm reading this right, you're doing the read/write and *then* doing the wait states, where, to be accurate, the CPU executes […]
Show full quote
superfury wrote on 2023-07-11, 16:08:

I've modified the BIU to check for operations to do on T1, then tick until T3, at which point the actual operation (previously T1) is executed, with waitstates until T4 after waitstates (if any). T4 is simply a result cycle resetting to T1 and giving the EU the result on the very next cycle (and telling it it's OK to make new requests). The only issue is that on T3 the BIU doesn't save a status of what T1 was (if it's a request from EU or a prefetch), so if a request happens to be buffered while starting because of a prefetch, the EU request will override the fetch when T3 is reached. That should still be fixed.

If i'm reading this right, you're doing the read/write and *then* doing the wait states, where, to be accurate, the CPU executes wait states and then finally does the transfer on the last Tw cycle.

I guess there's a decent enough reason to do it the former way, because it's hard to have a single mmio read/write function that both reports wait states and does the transfer at the same time, because the former has to happen before the latter, so its sort of a chicken/egg scenario. My solution was to have a separate mmio function that just gets wait states from a device on T2, before the transfer. This simulates the CGA card seeing MEMR/MEMW, when it would deassert READY, although I don't directly model the READY line.

This has a performance hit, of course, as now i'm resolving MMIO lookups twice per bus operation...

I'll look into that later.

Just managed to fix the booting of the Generic Super PC/Turbo XT BIOS again.
The culprit was indeed the buffer of the second INTA cycle (first INTA cycle on AT systems and newer atm). That buffer was getting cleared (set to all ones) when it was read once. And since the request is now made twice (once during T1 and once during T3), it was clearing the interrupt vector (set to FFh) during T1 and reading it during T3.
😁

Btw, when the MS-DOS 6.22 window is scrolling (printing the metric cycle count information of 8088 MPH (1517 cycles atm), I see that pattern you mentioned appearing on the screen.

In RGB mode it looks like a on/off pattern each character clock roughly (exactly at character clock boundaries!) with colored pixels, mostly green.

UniPCemu_8088MPH_CGAsnow.png
Filename
UniPCemu_8088MPH_CGAsnow.png
File size
237.7 KiB
Views
1665 views
File comment
8088 MPH CGA snow in 80x25 text mode.
File license
Fair use/fair dealing exception

The 8088MPH intro (the C64 vs IBM(CGA) comparison) shows clear '\\' patterned noise now. Already a lot less than it used to be.

Edit: In general already a LOT of less noise than it used to be.

Although the rolling over the screen at the start looks like it's vaporizing at the top (from the moving part until the top of the screen).

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

Reply 6 of 19, by GloriousCow

User metadata
Rank Member
Rank
Member

Interesting, can you tell where the green attribute is coming from?

but I don't think you should be seeing snow in DOS. both the DOS and BIOS text routines try to avoid it, either by toggling display-enable or whathaveyou.

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 7 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++
GloriousCow wrote on 2023-07-11, 16:58:

Interesting, can you tell where the green attribute is coming from?

but I don't think you should be seeing snow in DOS. both the DOS and BIOS text routines try to avoid it, either by toggling display-enable or whathaveyou.

I did make a screen capture of a part of 8088 MPH again with the latest snow effects:
https://www.dropbox.com/s/n0hpzpplt3w5d3p/Uni … 8-55-28.7z?dl=0

The intro shows snow, but the 1K on an '81 IBM CGA doesn't?

Dots are my favours shows an interesting one when drawing at the start, looking kind of like an S pattern from top to bottom.

Dots are my favours shows kind of like 10 vertical bars of noise dots from left to right in even spaces, with those dots looking like they're rolling down slowly.

Filename
1699-Dots are my favours.png
File size
5.73 KiB
Downloads
No downloads
File comment
Dots are my favours.
File license
Fair use/fair dealing exception

Delorean on about one story high (in the background building) above the deloran and about half that below filled with noise.

IBM logo has a matrix-ish pattern, also only every other character clock it seems for all rows, filling the entire screen?

16 colors vs 256 colors multiplied the noise. It's 3 bars at the left side now.
Also the first scan line goes about 1/4 from left to right?

1700_UniPCemu_8088MPH_close your eyes for this.png
Filename
1700_UniPCemu_8088MPH_close your eyes for this.png
File size
13.72 KiB
Views
1633 views
File comment
Close your eyes for this.
File license
Fair use/fair dealing exception

Flower girl doesn't display anything weird.

Kefrens improved by a lot! It's almost entirely correctly displaying now:
https://www.dropbox.com/s/aznsycev92svf9v/Uni … 9-14-39.7z?dl=0
Just a few more character clocks it's shifting to the previous scanline now. Vertical timings seems stable and timed correctly (looking at the lines on the screen always staying at the same height together, with probably the first part of the next or previous scanline at the righthand side of the screen (I guess about 8 character clocks or so?)! It's about 35 pixels I think?

1703_UniPCemu_8088MPH_KefrensAlmostThere.png
Filename
1703_UniPCemu_8088MPH_KefrensAlmostThere.png
File size
30.28 KiB
Views
1626 views
File comment
Kefrens bars almost there screen capture.
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 8 of 19, by VileR

User metadata
Rank l33t
Rank
l33t

Parts like the intro, the dot starfield, the Delorean, and the IBM vectorballs should have absolutely no snow, since they're not running in 80-column (+HRES) mode.

[ WEB ] - [ BLOG ] - [ TUBE ] - [ CODE ]

Reply 9 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++
VileR wrote on 2023-07-11, 18:17:

Parts like the intro, the dot starfield, the Delorean, and the IBM vectorballs should have absolutely no snow, since they're not running in 80-column (+HRES) mode.

OK. So I've just modified the CGA to not apply snow (the buffer being filled being ignored when +HRES isn't set) in low-res text mode and graphics modes.

It will be interesting to see what happens to 8088 MPH now.
The credits are unfortunately still crashing for some weird reason, even though they did run in the past? Could it be some instruction is off since back then? Afaik I just adjusted the timings according to Reenigne's reverse engineered 8088 emulator.

Edit: Disabling that snow buffer in 40 column text mode and non-text modes makes the "mode co40" set screen not show the snow, while still showing the snow in 80 column text mode. Graphics modes are also not affected by it anymore with that fix (although I don't know if the timing is somehow the cause of that?). Since the CGA/MDA like the VGA keeps rendering directly from VRAM, that probably wouldn't be the case otherwise?

8088 MPH says 1514 cycles now when starting the app.

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

Reply 10 of 19, by VileR

User metadata
Rank l33t
Rank
l33t

Oh, missed this:

GloriousCow wrote on 2023-07-11, 12:14:

I surmise that the character bytes for the displayed text in video memory being copied generate the initial variety of different colors within the snow immediately below; after we proceed past that the snow becomes either white or green. I am not sure where the green comes from.

The green shows up when the character byte on the bus gets read as the attribute: that test fills the screen with the sequence "20 0F", i.e. character 20h (space) with attribute 0Fh (white on black). If the 20h shows up when the CGA fetches the odd (attribute) byte, it'll set the color to black on green, and since the space character has no set bits you only get the green background.

I did a couple of quick tests just to make sure that I'm not talking out of my nether region, and it seems to match up. With the byte sequence "02 08" (a dark gray-on-black smiley face "☻"), the "02" generates green-on-black attribute noise:

snow 02 08.jpg
Filename
snow 02 08.jpg
File size
75.6 KiB
Views
1566 views
File license
Public domain

And with "3A 08" (":", dark gray on black) the attribute noise becomes intensified green (A) on cyan (3):

snow 3a 08.jpg
Filename
snow 3a 08.jpg
File size
65.32 KiB
Views
1566 views
File license
Public domain

[ WEB ] - [ BLOG ] - [ TUBE ] - [ CODE ]

Reply 11 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++
VileR wrote on 2023-07-11, 20:25:
Oh, missed this: […]
Show full quote

Oh, missed this:

GloriousCow wrote on 2023-07-11, 12:14:

I surmise that the character bytes for the displayed text in video memory being copied generate the initial variety of different colors within the snow immediately below; after we proceed past that the snow becomes either white or green. I am not sure where the green comes from.

The green shows up when the character byte on the bus gets read as the attribute: that test fills the screen with the sequence "20 0F", i.e. character 20h (space) with attribute 0Fh (white on black). If the 20h shows up when the CGA fetches the odd (attribute) byte, it'll set the color to black on green, and since the space character has no set bits you only get the green background.

I did a couple of quick tests just to make sure that I'm not talking out of my nether region, and it seems to match up. With the byte sequence "02 08" (a dark gray-on-black smiley face "☻"), the "02" generates green-on-black attribute noise:

snow 02 08.jpg

And with "3A 08" (":", dark gray on black) the attribute noise becomes intensified green (A) on cyan (3):

snow 3a 08.jpg

So in VGA terms, basically the value read from plane 1 (the attribute plane) gets replaced with the value that's read from RAM, while the other byte (from plane 0, which is the character byte) gets read normally?

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

Reply 12 of 19, by mdrejhon

User metadata
Rank Newbie
Rank
Newbie
VileR wrote on 2023-07-11, 20:25:

The green shows up when the character byte on the bus gets read as the attribute: that test fills the screen with the sequence "20 0F", i.e. character 20h (space) with attribute 0Fh (white on black). If the 20h shows up when the CGA fetches the odd (attribute) byte, it'll set the color to black on green, and since the space character has no set bits you only get the green background.

TIL! That's fantastic.

Makes sense why green was such a common snow color -- because the space character is one of the most commonly displayed characters -- space is 0x20 in hexadecimal -- "2" is green and "0" is black.

I must've contributed a domino tipover to opening this Pandora Box when I merely asked GloriousCow if MartyPC had CGA snow emulation in that original thread, and suddely it was implemented the same day...

Last edited by mdrejhon on 2023-07-12, 22:45. Edited 1 time in total.

Founder of www.blurbusters.com and www.testufo.com
- Research Portal
- Beam Racing Modern GPUs
- Lagless VSYNC for Emulators

Reply 13 of 19, by VileR

User metadata
Rank l33t
Rank
l33t
superfury wrote on 2023-07-11, 22:37:

So in VGA terms, basically the value read from plane 1 (the attribute plane) gets replaced with the value that's read from RAM, while the other byte (from plane 0, which is the character byte) gets read normally?

On these particular cycles yes, that seems to be what's happening. The alternate case is when it's the other way around (CGA fetches the character value and gets the attribute byte on the bus instead) - when that attribute byte is '0F' it gets you a '☼', as in CGA_COMP. My above tests used '08', which gives '◘'... I think I just used a too-long exposure time, so the dark grey makes it not all that visible, but it's there.

I also tried a couple of variations on that test, using LODSW or STOSW instead of MOVSW (i.e. just copying from VRAM to a register and vice versa). As expected, the characters/attributes visible in the noise remain the same... they just generate different-looking snow patterns.

[ WEB ] - [ BLOG ] - [ TUBE ] - [ CODE ]

Reply 14 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++
VileR wrote on 2023-07-12, 08:11:
superfury wrote on 2023-07-11, 22:37:

So in VGA terms, basically the value read from plane 1 (the attribute plane) gets replaced with the value that's read from RAM, while the other byte (from plane 0, which is the character byte) gets read normally?

On these particular cycles yes, that seems to be what's happening. The alternate case is when it's the other way around (CGA fetches the character value and gets the attribute byte on the bus instead) - when that attribute byte is '0F' it gets you a '☼', as in CGA_COMP. My above tests used '08', which gives '◘'... I think I just used a too-long exposure time, so the dark grey makes it not all that visible, but it's there.

I also tried a couple of variations on that test, using LODSW or STOSW instead of MOVSW (i.e. just copying from VRAM to a register and vice versa). As expected, the characters/attributes visible in the noise remain the same... they just generate different-looking snow patterns.

Does the CGA not fetch character and attribute from both planes in one go like the VGA? Won't that cause timing issues (since 1 clock elapsed between character and attribute)?
Also what about graphic modes? Does it use a shift register?

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

Reply 15 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

On a side note, I've just adjusted the CGA's RGB palette (which is the VGA palette on current releases and a new improved palette by Viler's post on commits until just now) when using the new-style RGB setting to actually use the VGA palette again.
The old-style CGA palette is still the improved color table (with adjusted colors, not the VGA palette). In commits before this last one both old and new style CGA palettes were using the same improved Viler palette. Now with those latest improvements, the old-style CGA palette is the Viler improved one (changed since last release) and the new style CGA palette is instead the VGA palette. So the two options actually affect the RGB conversion in a different way (so the user can choose to render VGA-compatible or CGA-compatible CGA colors).

Also, there's one issue with the way CGA renders text and graphics and when it fetches two seperate bytes from VRAM. With graphics modes, it can be adjusted to become 1 byte loads and rendering, by exploiting the SVGA half-timing mode (which reloads the latches every 4 instead of every 8 pixels, allowing those modes to load 8 bits instead of 16 bits chunks when rendering those). The main issue is that if it's to load text mode in byte chunks, it can't just load the entire required data to render a text mode 8-pixel block in one go, creating an issue with loading the character or attribute byte (whichever is supposed to be loaded on the character clock time of rendering). It will need to load the other byte at another time (probably 1 clock before or perhaps 4 clocks before it?), as both are required to be read from VRAM to render 8 pixels. I can use said half clock mode to load one of those two bytes from VRAM at any other time, but the issue is in three things:
- If loading the missing character(or attribute, whichever is supposed to be loaded first) halfway or at the end of a character clock, both aren't loaded during the first cycle of the CGA when it starts up (first CPU and CGA clock cycle essentially).
- If not having loaded both text-mode bytes at the first clock cycle of a character clock, data required for the shift buffers (if character byte is supposed to be loaded first) or attribute color (if it's loaded first, which according to your findings probably isn't the case (seeing the green color effect being like that)) isn't loaded during the first character clock, thus causing that byte to be cleared for the entire character cell.

There's also the issue of when to load that first byte from VRAM in text modes. Is it loaded at the halfway point (at the 4th clock out of every 8 clocks) in text modes (matching the graphics modes byte loads in 4 color modes (once that's implemented))? Or is it loaded at the end? What about when the CGA receives it's first power and starts it's first character clock (it didn't have any cycle before starting to output to the screen on the first clock)?

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

Reply 16 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

Running 8088 MPH on the latest UniPCemu version again, I see something interesting. Most snow on 8088 MPH is gone now, with the first being at the 256 color part, and just one vertical column (and first scanline of active display it seems), of which the column is the column the first "1" is starting horizontally. That's the column where the noise is now.

In this video (https://www.youtube.com/watch?v=yHXx3orN35Y) it's a few character clocks further to the right, at the vertically longest part of the 1 symbol (think the | part of the 1), while UniPCemu has it at the leftmost clock of the 1 instead.

Also, no more noise during 8088 MPH now (although most modes don't emulate the CGA snow, except the high resolution text modes (mode control register bit 1 set))!

A bit more snow while rendering the faces before the credits, but not after that.
The credits simply display the first frame and then silence and nothing (PC speaker whizzing a bit though).

Edit: Hmmm.. That noise on the 256 colors is probably the difference in the final version of 8088 MPH? UniPCemu's position (it's the final version i'm testing with) matches that, although not just displaying noise on the first few columns but on the entire height of the screen (all on the same horizontal column).

A screen capture made from the recording:

1704_UniPCemu_8088MPH_KefrensAlmostThere_withoutnoise.png
Filename
1704_UniPCemu_8088MPH_KefrensAlmostThere_withoutnoise.png
File size
1.33 MiB
Views
1319 views
File comment
Kefrens effect on UniPCemu's latest commit.
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 17 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++

Thinking about the Kefrens issue, perhaps the first scanline starts it's rendering (on the CPU being earlier than the raster) too soon, then runs in correct lockstep for the remainder of the frame? That would explain why it's vertically correct, except the final constant sets of pixels being the next scanline somehow?

Edit: Moved some cycle accurate issues and questions over to the other thread: UniPCemu 8088 cycle accuracy , since they don't relate to CGA snow directly.

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

Reply 18 of 19, by GloriousCow

User metadata
Rank Member
Rank
Member

It does appear that you're rendering the kefrens bars every other scanline; that's a bit odd. Are you still generating 262 scanlines per frame there?

I can confirm that having a single vertical discontinuity in the background lines indicates you're executing each scanline in the proper time, but something offset the start of the effect

MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc

Reply 19 of 19, by superfury

User metadata
Rank l33t++
Rank
l33t++
GloriousCow wrote on 2023-07-13, 20:59:

It does appear that you're rendering the kefrens bars every other scanline; that's a bit odd. Are you still generating 262 scanlines per frame there?

I can confirm that having a single vertical discontinuity in the background lines indicates you're executing each scanline in the proper time, but something offset the start of the effect

Both captures in the video output buffer (both the one with the 1-character having snow (the 16/256 color one) and the Kefrens (the old capture with snow, which just has had the snow removed) seem to be the same height in the total rendered frame including overscan.

Both seem 246 scanlines high. That's 1:1 unscaled CGA in the screen captures made by UniPCemu (the higher resolution or VGA captures are resizes (the 1080p one is Windows resizing to full screen with aspect ratio from the video, which is recorded at 800x600 I think (resized to that).

Although the fixed 16 vertical retrace lines (which disable the CRTC) aren't rendered. If VTotal is reached during VRetrace scanlines, it's ignored until it's done the remaining 16 HTotal timings. After VRetrace is finished, VTotal will trigger and the scanline counter will reset, starting to render from RAM again (effectively starting scanline&character row counter at row 0) and loading the start address latches at CGA.

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