VOGONS


Emulating Area5150

Topic actions

Reply 60 of 113, by GloriousCow

User metadata
Rank Member
Rank
Member

Wouldn't your PC be cooler with ... Area 5150 in your web browser?

https://dbalsom.github.io/martypc/web/player. … ?title=area5150

This is a big work in progress - Sound is all jacked up, and the end credits don't work. You will need a FAST pc to run this at full speed...
Still kind of neat it works at all 😁

Last edited by GloriousCow on 2023-07-03, 01:00. Edited 2 times in total.

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

Reply 61 of 113, by superfury

User metadata
Rank l33t++
Rank
l33t++
VileR wrote on 2023-06-20, 18:42:
Been messing around with MartyPC some more and I think I'm getting the hang of things. That will probably merit a little blog p […]
Show full quote

Been messing around with MartyPC some more and I think I'm getting the hang of things. That will probably merit a little blog post of my own... so far I haven't seen this emulator being shouted from the rooftops as much as it should be - I don't do the social media thing so my rooftop isn't tactically positioned, but I might as well get up there.

GloriousCow wrote on 2023-06-11, 19:27:

The memory viewer doesn't currently support MMIO; since the CGA card owns its own memory which is then mapped into the system and the viewer is not aware of that it shows all 0's. That could be addressed with CGA fairly trivially as it doesn't have pages, but there would be a question for say, EGA/VGA - what should I show for those ranges? Other emulators often have a dropdown for MMIO ranges specifically, and I could follow that model.

Yeah, good question. In a debugger running *on* the emulated machine one would expect to see the contents of the bank that's currently paged into the CPU's address space, no different from emulating an EMS card for instance, but here of course there are more options. I was considering the case of debugging some code with say DS or ES pointing to video RAM, where it can be helpful to just set the memory view to e.g. "DS:0000" or "ES:BX" etc., and see what gets read/written as you single-step.

GloriousCow wrote on 2023-06-11, 19:27:

I've also been considering a dedicated video memory viewer, with options to view VRAM as either hex or various graphical interpretations...

Sounds very nice, although a useful graphical rendering may prove to be a bit of a rabbit hole... you'd probably have to consider arbitrary CRTC settings that change how the data is laid out and interpreted, plus the logical layout of VRAM data can bear little resemblance to the final screen layout, especially on EGA/VGA (where offscreen buffers may be used for tiles/sprites and so on).

But speaking of visual representations: I've always liked the realtime memory usage monitor that some emulators have (e.g. Bisqwit's NES emulator), where you get a map of RAM 'blocks' of arbitrary sizes, and can see read/write ops indicated in color as they happen. MartyPC's memory viewer already has the latter part - think more or less the same thing but at a lower granularity, so you can get a bigger picture of what's going on.
Admittedly that's more of a 'nice to have' toy feature, but if you're patching or reverse-engineering an existing program this sort of thing can actually be helpful.

GloriousCow wrote on 2023-06-11, 19:27:
VileR wrote on 2023-06-11, 17:53:

[*]It'd be awesome if all the debug-related views/widgets could be spun off to a separate window. Especially useful on a two-monitor setup; maybe not so much on a single monitor, so perhaps that could be made an optional setting.

I agree that would be useful. I'm not sure how difficult it will be. The windowing library I'm using does in theory support multiple windows, but I don't know if the wgpu stuff will play nice. I've recently refactored my emulator core into a library so i can support multiple front ends, so if my current library stack won't cooperate I can try to find one better suited for that.

More debugging is coming; register and memory editing for sure (the CPU status window is already a bunch of edit controls, just need to send events when you change them). A breakpoint overhaul is definitely needed. Rather than add a million new little debug windows I'm planning on adding a little quake-like console window where you can issue commands. You'll be able to create named breakpoints of various types, and set up profiling between two breakpoints for cycle counts/time between any two breakpoints you have defined.

I'm a simple man - I get a basic text-based UI for a debugger (or something that acts like one) and I'm good. 😀 A drop-down console window sounds pretty convenient if you want to get rid of separate little widgets; maybe something divided into panes instead?

If you could optionally have it appear as a separate window, all the better... either way, UI takes a back seat to features, so I'd be happy with the above additions however they're presented!

GloriousCow wrote on 2023-06-11, 19:27:

I appreciate you checking it out! Don't hold back on the suggestions. If there's even a remote chance I could make it good enough for people to use it for demo development, that would make me very happy.

Well, down the line it'd be awesome to have more flexible output scaling options, but if you're already planning to offload some rendering tasks to GPU shaders and such, those things would be easier to plug in after that.

You also mentioned the option of letting the GPU handle composite rendering, so perhaps something similar could be done with RGBI, in case someone wants to mimic the IBM 5153's palette treatment and pixel blending. 😀

That sounds interesting...
Adjusting the RGBI to RGB values is easy to implement in UniPCemu (it's a simple RGBA lookup table set to EGA RGB colors already).
Perhaps the blurring can be archieved by converting the scanline result to 0.0-1.0 normalized floating point RGB values (3 floats per pixel), then low-pass filtering at some frequency those R, G and B values (one filter for each color channel) and converting the result of each pixel back from normalized to RGB? UniPCemu already has a low-pass RC filter for audio, perhaps that can be used?

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

Reply 62 of 113, by VileR

User metadata
Rank l33t
Rank
l33t

Spotted what looks like a bug with CGA palette handling: sometimes the on-screen rendering doesn't match what the CGA is set to, although the debug tools tell me that the register values are sent and interpreted as expected.

In some Atarisoft games like Gremlins or Moon Patrol, you can hit F8 to swap between "full color" (palette 0) and "partial color" (alternate cyan/red/white, or B&W composite output). In MartyPC this has no visible effect: the register is set, and the video card view correctly interprets the display mode as "Mode5LowResAltPalette", but the screen is always rendered in palette 0 regardless.

The attachment gremlins.png is no longer available

California Games' "CGA MORE-color mode" alternates between two palettes in mid-frame, but the display swaps them around - it's supposed to look like this, but I gt this instead:

The attachment calgames.png is no longer available

You can see when the values are programmed, e.g. in my version 'Footbag' does it at CS:57EA (mid-screen) and CS:5801 (vertical blanking). Again the Video Card View reports the correct display mode in each case, but the rendering is wrong.

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

Reply 63 of 113, by VileR

User metadata
Rank l33t
Rank
l33t
superfury wrote on 2023-06-23, 09:25:

That sounds interesting...
Adjusting the RGBI to RGB values is easy to implement in UniPCemu (it's a simple RGBA lookup table set to EGA RGB colors already).
Perhaps the blurring can be archieved by converting the scanline result to 0.0-1.0 normalized floating point RGB values (3 floats per pixel), then low-pass filtering at some frequency those R, G and B values (one filter for each color channel) and converting the result of each pixel back from normalized to RGB?

That sounds about right, although I don't know about the performance penalty. To get the bandwidth of the filter or the blur amount more or less correct, you could try starting from nothing and nudging it up until hi-res alternating dots look pretty much like a solid color - e.g. character 0xB1 "▒" in 80-column mode, as per the photos. But maybe that should be a tunable option as well?
As far as I could tell, this is one of the few cases where the pixel blending actually should be done in sRGB space, so there's no need to gamma-correct before and after; maybe that would go a little easier on the performance.

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

Reply 64 of 113, by GloriousCow

User metadata
Rank Member
Rank
Member
VileR wrote on 2023-06-23, 09:50:

Spotted what looks like a bug with CGA palette handling: sometimes the on-screen rendering doesn't match what the CGA is set to, although the debug tools tell me that the register values are sent and interpreted as expected.

Thanks - Fixed, will be in the next release. Kind of an awkward order of operations thing. The CGA palettes are stored in an array, and I was actually setting the palette index when the color control register was written based on the current mode byte, but of course, you could also set the cc register and *then* the mode. So now both cc and mode writes will update the palette.

The attachment pal_fix.PNG is no longer available
The attachment pal_fix2.png is no longer available

check the little pink line in the california games screen...that's a debug view of when the register write happens to change the palette.

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

Reply 65 of 113, by GloriousCow

User metadata
Rank Member
Rank
Member
VileR wrote on 2023-06-20, 18:42:

Been messing around with MartyPC some more and I think I'm getting the hang of things. That will probably merit a little blog post of my own... so far I haven't seen this emulator being shouted from the rooftops as much as it should be - I don't do the social media thing so my rooftop isn't tactically positioned, but I might as well get up there.

no pressure 😀

VileR wrote on 2023-06-20, 18:42:

Yeah, good question. In a debugger running *on* the emulated machine one would expect to see the contents of the bank that's currently paged into the CPU's address space, no different from emulating an EMS card for instance, but here of course there are more options. I was considering the case of debugging some code with say DS or ES pointing to video RAM, where it can be helpful to just set the memory view to e.g. "DS:0000" or "ES:BX" etc., and see what gets read/written as you single-step.

I think i'll just add another set of mmio read/write routines that do not have side effects, and route the memory viewer requests through those. Currently the memory viewer relies on a dump() method that the mmio devices don't have, but it would make more sense just to do byte reads through the full bus to populate the window. But they have to be special reads - You don't want to change the latches while viewing VGA memory, after all.

VileR wrote on 2023-06-20, 18:42:

Sounds very nice, although a useful graphical rendering may prove to be a bit of a rabbit hole... you'd probably have to consider arbitrary CRTC settings that change how the data is laid out and interpreted, plus the logical layout of VRAM data can bear little resemblance to the final screen layout, especially on EGA/VGA (where offscreen buffers may be used for tiles/sprites and so on).

I'm thinking something akin to reenigne's CGAArt, but built in. There would be a few knobs and dials to tweak, sure. Even if you can't replicate everything, it would be a cool toy. Reminds me of some hex editors where you can choose to view the data as some sort of bitmap interpretation, in fact, there's no actual reason to limit the "VRAM viewer" to just VRAM, if you think about it...

As far as off-screen stuff, peeking in on what's going on offscreen would be cool! Wouldn't it be neat to see where a game is hiding its sprites?

VileR wrote on 2023-06-20, 18:42:

But speaking of visual representations: I've always liked the realtime memory usage monitor that some emulators have (e.g. Bisqwit's NES emulator), where you get a map of RAM 'blocks' of arbitrary sizes, and can see read/write ops indicated in color as they happen. MartyPC's memory viewer already has the latter part - think more or less the same thing but at a lower granularity, so you can get a bigger picture of what's going on.
Admittedly that's more of a 'nice to have' toy feature, but if you're patching or reverse-engineering an existing program this sort of thing can actually be helpful.

So the memory viewer updates are a bit of a cheat, I confess. They're not based on updates sent on a memory write, but on a diff of what the memory viewer was displaying on the last frame (diffs are suppressed when you scroll) That means if you toggle a memory value to something else and back within the same frame, the memory viewer won't highlight anything as having changed.

There's a major performance consideration here - memory writes need to be very fast for decent performance, and generating a GUI update event for each one that happens would be glacially slow. That said, showing updated regions should be possible - I could have a little vertical image strip to one side of the memory viewer, maybe by the scroll bar, that represented the whole address space. Divide the address space into 4k or 8k blocks by shifting the address to the right on a write, and mark the resulting memory slice as dirty. There would only be 128 or 256 slices this way, so would limit the number of updates that needed to be sent considerably.

VileR wrote on 2023-06-20, 18:42:

You also mentioned the option of letting the GPU handle composite rendering, so perhaps something similar could be done with RGBI, in case someone wants to mimic the IBM 5153's palette treatment and pixel blending. 😀

Certainly seems like a good candidate for a fragment shader. Image processing is not my forte, but I'll tackle it eventually.
That reminds me also, I do have a 'VileR' CGA palette defined; I just need to put in the config option to make it selectable...

Also, I don't know if you've noticed some keyboard issues, but that's also on the agenda for a re-do. I'm using the host's typematic repeat rate, which I think is a bit too fast, so I need to maintain a key state array and generate more period-accurate typematic repeats from an emulated keyboard. In certain games like Pharaoh's Tomb just holding the key down to move in a direction while falling can cause a freeze and an angry beep due to what I assume is the BIOS keyboard buffer being filled. Need to check that on real hardware though, maybe that's just how it was...

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

Reply 66 of 113, by superfury

User metadata
Rank l33t++
Rank
l33t++
VileR wrote on 2023-06-23, 10:30:
superfury wrote on 2023-06-23, 09:25:

That sounds interesting...
Adjusting the RGBI to RGB values is easy to implement in UniPCemu (it's a simple RGBA lookup table set to EGA RGB colors already).
Perhaps the blurring can be archieved by converting the scanline result to 0.0-1.0 normalized floating point RGB values (3 floats per pixel), then low-pass filtering at some frequency those R, G and B values (one filter for each color channel) and converting the result of each pixel back from normalized to RGB?

That sounds about right, although I don't know about the performance penalty. To get the bandwidth of the filter or the blur amount more or less correct, you could try starting from nothing and nudging it up until hi-res alternating dots look pretty much like a solid color - e.g. character 0xB1 "▒" in 80-column mode, as per the photos. But maybe that should be a tunable option as well?
As far as I could tell, this is one of the few cases where the pixel blending actually should be done in sRGB space, so there's no need to gamma-correct before and after; maybe that would go a little easier on the performance.

Interesting enough, the SDL2_gfx image resize function (as well as UniPCemu's adaptation of it, which is just optimizing it using precalcs for horizontal/vertical coordinate buffers of repeatedly used frame sizes) suffers from a moire effect in some cases (like Windows 3.0's boot logo).
Implementing such a filter on the rendering unit instead thus might fix that issue as well?
Although I don't know if it can be easily combined on both axes?

https://bitbucket.org/superfury/commonemufram … u/gpu/gpu_sdl.c
It's resizing where it says "Interpolating zoom" inside zoomSurfaceRGBA. Everything above that are the precalcs of the horizontal and vertical resize coordinates for each relative position of the destination to source image(to be precise: any destination pixel's corresponding top-left corner in the source image).

Edit: Also, when using the audio filters, you'd probably have to filter at a speed that results in every 2 pixels blending? So that means a low-pass filter at the niquist (half) of the amount of pixels?
So say a 320 pixels scanline would have it's input at 320Hz with Niquist at 160Hz? Thus blending every 2 pixels together?
Although effectively it would always be at 320Hz, as 640Hz(Hi-res) are blending, but 320Hz(4 color) isn't? Although it would cause color gradients on 640Hz input even-odd on/off scanlines for every 2 pixels? That would cause something like 33%/100% on every odd/even pixel?

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

Reply 67 of 113, by VileR

User metadata
Rank l33t
Rank
l33t
GloriousCow wrote on 2023-06-23, 13:28:
Thanks - Fixed, will be in the next release. Kind of an awkward order of operations thing. The CGA palettes are stored in an a […]
Show full quote

Thanks - Fixed, will be in the next release. Kind of an awkward order of operations thing. The CGA palettes are stored in an array, and I was actually setting the palette index when the color control register was written based on the current mode byte, but of course, you could also set the cc register and *then* the mode. So now both cc and mode writes will update the palette.

The attachment pal_fix.PNG is no longer available
The attachment pal_fix2.png is no longer available

check the little pink line in the california games screen...that's a debug view of when the register write happens to change the palette.

Nice!
Speaking of the display: would it be possible to improve the centering of the active area within the emulated monitor? As far as I can tell, +HRES modes (80-col text) are shifted far to the right, while -HRES (everything else) is way off to the left:

The attachment centering40c.png is no longer available
The attachment centering80c.png is no longer available

This is with IBM's default CRTC values, which have the same hsync position in both cases (45 lchars = 90 hchars), so both are more or less centered on a standard CGA monitor.

Vertical centering could be tweaked as well... the tail-end of vertical blanking at the top left is normally hidden way behind the monitor's top bezel. 😀

GloriousCow wrote on 2023-06-23, 14:56:

I'm thinking something akin to reenigne's CGAArt, but built in. There would be a few knobs and dials to tweak, sure. Even if you can't replicate everything, it would be a cool toy. Reminds me of some hex editors where you can choose to view the data as some sort of bitmap interpretation, in fact, there's no actual reason to limit the "VRAM viewer" to just VRAM, if you think about it...

As far as off-screen stuff, peeking in on what's going on offscreen would be cool! Wouldn't it be neat to see where a game is hiding its sprites?

Definitely... I meant to say that they could be stored there in any arbitrary layout, so you'd have to know what it is (and be able to tune the viewer accordingly).

FWIW, here's a tool I sometimes use for such things: https://www.romhacking.net/utilities/818/. Crap UI, but feed it a file or a RAM/VRAM dump, and you can usually find a setting that lets you figure out the graphical content; e.g. it doesn't have a "CGA" format, but it does have a packed-pixel 2bpp one that's practically the same, and all you need to is to play with the palette.

GloriousCow wrote on 2023-06-23, 14:56:

So the memory viewer updates are a bit of a cheat, I confess. They're not based on updates sent on a memory write, but on a diff of what the memory viewer was displaying on the last frame (diffs are suppressed when you scroll) That means if you toggle a memory value to something else and back within the same frame, the memory viewer won't highlight anything as having changed.

There's a major performance consideration here - memory writes need to be very fast for decent performance, and generating a GUI update event for each one that happens would be glacially slow. That said, showing updated regions should be possible - I could have a little vertical image strip to one side of the memory viewer, maybe by the scroll bar, that represented the whole address space. Divide the address space into 4k or 8k blocks by shifting the address to the right on a write, and mark the resulting memory slice as dirty. There would only be 128 or 256 slices this way, so would limit the number of updates that needed to be sent considerably.

Yep, that's acceptable for sure - for this use-case there's absolutely no need to catch all changes on every I/O cycle; it's more for getting a rough visual idea of the big picture, so the 'cheat' you mention is not a problem.

For precision monitoring, I'd say a SoftICE-type "breakpoint on memory range" would be the sort of thing to go with (although I'd still expect a performance penalty there).

GloriousCow wrote on 2023-06-23, 14:56:

Certainly seems like a good candidate for a fragment shader. Image processing is not my forte, but I'll tackle it eventually.
That reminds me also, I do have a 'VileR' CGA palette defined; I just need to put in the config option to make it selectable...

Funny, I call it the 'Holden palette' since I based it on Hugo Holden's data... I suppose "5153" ("-revised"?) is as good a name as any. 😀

Also, I don't know if you've noticed some keyboard issues, but that's also on the agenda for a re-do. I'm using the host's typematic repeat rate, which I think is a bit too fast, so I need to maintain a key state array and generate more period-accurate typematic repeats from an emulated keyboard. In certain games like Pharaoh's Tomb just holding the key down to move in a direction while falling can cause a freeze and an angry beep due to what I assume is the BIOS keyboard buffer being filled. Need to check that on real hardware though, maybe that's just how it was...

Now that you mention it, I did notice that holding shift while typing isn't always registered. Haven't noticed it in a game yet, but then games that don't bypass the BIOS keyboard routines are mostly asking for trouble anyway.

Last edited by VileR on 2023-06-30, 16:39. Edited 1 time in total.

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

Reply 68 of 113, by VileR

User metadata
Rank l33t
Rank
l33t
superfury wrote on 2023-06-23, 21:55:
Interesting enough, the SDL2_gfx image resize function (as well as UniPCemu's adaptation of it, which is just optimizing it usin […]
Show full quote

Interesting enough, the SDL2_gfx image resize function (as well as UniPCemu's adaptation of it, which is just optimizing it using precalcs for horizontal/vertical coordinate buffers of repeatedly used frame sizes) suffers from a moire effect in some cases (like Windows 3.0's boot logo).
Implementing such a filter on the rendering unit instead thus might fix that issue as well?
Although I don't know if it can be easily combined on both axes?

https://bitbucket.org/superfury/commonemufram … u/gpu/gpu_sdl.c
It's resizing where it says "Interpolating zoom" inside zoomSurfaceRGBA. Everything above that are the precalcs of the horizontal and vertical resize coordinates for each relative position of the destination to source image(to be precise: any destination pixel's corresponding top-left corner in the source image).

Edit: Also, when using the audio filters, you'd probably have to filter at a speed that results in every 2 pixels blending? So that means a low-pass filter at the niquist (half) of the amount of pixels?
So say a 320 pixels scanline would have it's input at 320Hz with Niquist at 160Hz? Thus blending every 2 pixels together?
Although effectively it would always be at 320Hz, as 640Hz(Hi-res) are blending, but 320Hz(4 color) isn't? Although it would cause color gradients on 640Hz input even-odd on/off scanlines for every 2 pixels? That would cause something like 33%/100% on every odd/even pixel?

CGA's pixel clock is 14.31818MHz for one, so the frequencies are much higher than that (and it's not a given that audio filters could be easily adapted to those rates).
Either way, there are really two separate things here... simulating the characteristics of some particular CRT's electronics is one thing, improving interpolation for image resizing is another. True, applying a low-pass filter before scaling can reduce moire artifacts, but that really depends on the sizes and scaling factors (it's also lossy by definition, so you'd have to oversample by quite a bit first).

It'd be better to avoid whatever is causing the artifacts in the first place, which is likely a lack of gamma correction before/after resizing (source 1, source 2). If you take one of those checkerboard-dithered images (which is what the Win3.0 splash screen does), and scale it by some non-integer factor without gamma correction, you're in for a whole lot of moire.

For mimicking the bandwidth of the 5153's tube amplifiers the, 'lossiness' is actually intended, and so is the uncorrected gamma... A different kettle of fish, but we're probably going off-topic here?

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

Reply 69 of 113, by GloriousCow

User metadata
Rank Member
Rank
Member
VileR wrote on 2023-06-25, 18:28:

Speaking of the display: would it be possible to improve the centering of the active area within the emulated monitor? As far as I can tell, +HRES modes (80-col text) are shifted far to the right, while -HRES (everything else) is way off to the left:

I was actually considering starting a new thread on this to ask for advice. The version of MartyPC you're using returns the raster to the left side of the screen at the end of hblank. So it's not just the HorizontalSyncPosition that matters, but SyncWidth as well. You are correct in that the HorizontalSyncPosition is effectively the same in 80 column and 45 column mode, but SyncWidth is programmed as 10 in both modes so in 40 column mode the SyncWidth is effectively twice as wide. I already decided that waiting for end of hblank was probably incorrect.

In the current version of MartyPC I have adopted a fixed 'monitor hsync' width, so that the beam returns to the left side of the screen after a fixed period after HorizontalSyncPosition is reached, regardless of the programmed SyncWidth. In 40 column mode this means that part of the hblank then is drawn on the left side of the screen, pushing the image over to the right... This is a bit of an improvement in some ways, for example if you sit at the dos prompt and do mode 40 / mode 80 back and forth, the C: prompt stays in the same position on the screen. However the downside is now everything is too far to the right except for a few effects in Area 5150 that are perfectly centered like the intro sequence, which means just chopping more off the left side of the display aperture can't be the easy solution.

The proper thing to do would be to emulate a monitor as a separate layer in the rendering stack, so that the card is scanning out as the CRTC is producing hblank and vblank status bits, but the monitor is actually deciding when to do hblank and vblank using its own 'circuitry'. This would have some interesting effects like you could probably lose vhold and start rolling the screen if you didn't produce 262 scanlines, which at the moment the emulator handles somewhat unrealistically well.

I'm not an electronics guru so basically what I need is a description of 'monitor logic'. Clearly the process of a monitor performing an hsync or vsync does not take up the entire hblank and vblank time that the CRTC specifies, the question is just what are the exact timings. It would be helpful to have an actual CGA monitor to test with, but I currently don't.

Regarding seeing too much of the screen, you're right. The current display aperture is based on the widest extent of the 'full screen' effects in Area5150, specifically the gradient effect right after the 'lets really push the boundaries' effect which is 768 pixels wide. On real hardware, some of those beautiful pixels are almost certainly beneath the display bezel. I agree that its a bit awkward to show so much dead space for the 99% of the time you're not running Area5150 specifically. If we're talking about having CRT shaders, though, it probably makes sense to pass the whole display field to the shader and let the shader crop what it needs to.

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

Reply 70 of 113, by Scali

User metadata
Rank l33t
Rank
l33t
GloriousCow wrote on 2023-06-25, 19:28:

I'm not an electronics guru so basically what I need is a description of 'monitor logic'. Clearly the process of a monitor performing an hsync or vsync does not take up the entire hblank and vblank time that the CRTC specifies, the question is just what are the exact timings. It would be helpful to have an actual CGA monitor to test with, but I currently don't.

The not-so-technical answer is that there really isn't any 'logic' as it's all analog.
That is, every CRT has some controls to stretch and center the image both horizontally and vertically. On some, these are set at the factory, and hidden inside the monitor, only to be adjusted by a servicing professional.
On others, they are exposed at the front and/or the back, and the user can make adjustments on-the-fly.

So there is no 'one' answer to what you see on the CRT exactly.
I think the best way to address this in emulation is just to emulate these controls: allow the user to choose how many horizontal pixels to hide during the hblank, and let the user center the screen.
Same for vblank: let the user decide how many scanlines to show, and where it is centered.

Because once you get into tweakmodes/SVGA modes, you'll generally find exactly that: whoever wrote the code, will have adjusted the code to look centered on their display with their settings.
There may not be an actual 'right' way to get a screen perfectly centered.

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

Reply 71 of 113, by GloriousCow

User metadata
Rank Member
Rank
Member

I think the key to getting all the various graphics modes properly centered is to pin the hsync start position along with having the virtual monitor hsync after a fixed period, ignoring the programmed sync width.
My video_debug mode generates a 912x262 output frame so you can see all the time spent in hblank (colored blue), and I collected screenshots of all the graphics modes i could find. It looks like this will center everything pretty well:

The attachment screen_alignment02.png is no longer available

The 'bright' area will be the new display aperture by default so everything in the 'dim' area will be hidden.

Here's a rough overlay from a video of Area 5150 running on a 5153 monitor:

The attachment marty_vs_5153.png is no longer available

You can see just how much of the monitor actually chops off from the left and the right sides of the graphics, which implies I could make the display aperture considerably smaller. What I'll probably do is have a user selectable display profile, so that you can see everything if you want under the 'Raw' profile, but it would realistically crop if you selected 'IBM 5153' as your display. Just chopping off a fixed amount of the margins isn't quite right though. Due to the curve of the display bezel, you can see more pixels per scanline in the middle of the screen than on the top and bottom of the display, so this is probably best handled in a shader that can play around with the geometry and crop dynamically.

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

Reply 72 of 113, by Scali

User metadata
Rank l33t
Rank
l33t
GloriousCow wrote on 2023-06-26, 13:54:

You can see just how much of the monitor actually chops off from the left and the right sides of the graphics, which implies I could make the display aperture considerably smaller. What I'll probably do is have a user selectable display profile, so that you can see everything if you want under the 'Raw' profile, but it would realistically crop if you selected 'IBM 5153' as your display.

That's pretty much what the Vice C64 emulator does:
You can set it to 'debug borders', which means it shows the full width of every scanline, as in: every pixel cycle, even the hsync part. This allows you to see things that would be hidden in the border on a real monitor. Which is great for checking exactly where your register updates take effect, when you want to hide them in the border reliably.
Aside from that, it has two other presets: 'normal' and 'full'. Where if I'm not mistaken, 'normal' simulates more or less how much of the border you see on a real CRT, and 'full' tries to display the whole border area, hiding only the hsync/vsync parts.

But since the 6845 CRTC is more flexible than what the C64 offers in terms of video modes and timings, it may be better to have more control over it than just a few presets.
Even so, having a 'raw'/'debug' and a 'normal' mode would be a good starting point I suppose.

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

Reply 73 of 113, by VileR

User metadata
Rank l33t
Rank
l33t

The general idea is pretty much as Scali put it. It's one reason why the MODE command has those ",r"/",l" parameters to shift the screen horizontally by changing the hsync position, and why quite a few early CGA games also offered such a setting; you could never be quite sure what a particular monitor was set to, and whether it had user-accessible controls to compensate.

You're correct in decoupling the raster's flyback time from the length of the blanking period: the CRTC lets you change that length, at least for hblank, but this doesn't affect the image's positioning. (What it does affect is the width of the black bars you see when the picture rolls, as the H/V hold circuitry tries to lock on to a sync signal of the right frequency... in case you're interested in emulating that as well.)

The blanking itself is only really there to prevent visible beam output during flyback, but the CGA also uses it to time the actual sync pulses it sends out to the monitor. It generates hblank for the entire duration of the CRTC's hsync signal, and the true hsync pulse it sends out (from my notes) starts 4 hchars into the hblank and lasts 8 hchars. Similarly for the vsync pulse, which really starts 1 scanline into the vblank period and lasts for 3 scanlines... I could be wrong about these numbers, but in any case they're always fixed with respect to the start of the blanking period. So putting aside any user-adjustable controls, the image's centering depends only on the h/v sync positions.

As for how long it takes the beam to physically fly back to the left (or the top) of the raster, that's a good question... but the simple answer is that it doesn't really matter for the issue at hand - I mean, it would matter if you wanted to know the absolute maximum width/height that the visible image could theoretically have, but no properly-adjusted CRT would ever show the full thing; the most realistic thing to do would be to assume some fixed number, and render only the smaller fixed-size 'window' into that area, while centering the image based on the H/V sync position values.
I guess it'd make sense to treat IBM's default positions of 90 hchars and 224 scanlines as '100% centered', even if in practice they may be a bit off by some tiny amount.

For curiosity's sake however, I had a look through Hugo Holden's docs again, since I remembered he had some relevant oscilloscope measurements. In this one, he measures the horizontal fly-back time for CGA as 10.48 µs (compared to 6.70 µs for EGA). That works out to ~150 hdots, which makes for a theoretical maximum width of 912-150 = 762 hdots. Although elsewhere he merely says "10 to 11 µs", so perhaps the precise duration isn't quite set in stone.

Regarding seeing too much of the screen, you're right. The current display aperture is based on the widest extent of the 'full screen' effects in Area5150, specifically the gradient effect right after the 'lets really push the boundaries' effect which is 768 pixels wide. On real hardware, some of those beautiful pixels are almost certainly beneath the display bezel. I agree that its a bit awkward to show so much dead space for the 99% of the time you're not running Area5150 specifically. If we're talking about having CRT shaders, though, it probably makes sense to pass the whole display field to the shader and let the shader crop what it needs to.

Note I didn't say that I was seeing too much width in total, only that too much was visible on the left/right since the centering was off. We did go with 768 pixels (96 chars) as the 'no-borders' width, since we assumed it'd give us graphics all the way out to the edges on most/all monitors. As it happens that's just a bit more than the 762 "maximum" above, so I guess we weren't wrong. 😀

The solid-color dead space you get with the default border size personally doesn't bother me. My 5153 shows less than that, but you can find videos of Area 5150 on other CRT monitors that show some more. Maybe it's worth learning from the C64 scene here... the VICE emulator lets you choose between "normal borders" and "full borders" (as well as "debug borders", which shows the full theoretical frame size, including the areas that should be occupied by flyback and blanking). Having some 'presets' like that for the aperture size might be a good idea.

(Edit: missed Scali's last post, which practically says the same thing!)

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

Reply 74 of 113, by VileR

User metadata
Rank l33t
Rank
l33t
GloriousCow wrote on 2023-06-26, 13:54:
I think the key to getting all the various graphics modes properly centered is to pin the hsync start position along with having […]
Show full quote

I think the key to getting all the various graphics modes properly centered is to pin the hsync start position along with having the virtual monitor hsync after a fixed period, ignoring the programmed sync width.
My video_debug mode generates a 912x262 output frame so you can see all the time spent in hblank (colored blue), and I collected screenshots of all the graphics modes i could find. It looks like this will center everything pretty well:

screen_alignment02.png

The 'bright' area will be the new display aperture by default so everything in the 'dim' area will be hidden.

That looks just about right!

I was a bit surprised (in our video captures as well) to see that there's so much horizontal blanking in the -HRES modes, but it does work out to 10 lchars, which is IBM's default. If the bright area becomes the default or 'full borders' setting, and that extra bit of hblank just shows up as a black stripe on the left, it'll probably be "visually" acceptable.

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

Reply 75 of 113, by GloriousCow

User metadata
Rank Member
Rank
Member

Ok, the plan is to have three selectable display profiles for CGA:

Debug (912x262)
Full (768x460)
Cropped / "IBM 5153" (706x446)

The latter is just a rough guess from looking at this video of Area 5150 on a 5153 monitor: https://www.youtube.com/watch?v=BdM5j96tEpE
I'll probably define these profile values in the config so you can create whatever profiles you want if you're not happy with those presets.

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

Reply 76 of 113, by GloriousCow

User metadata
Rank Member
Rank
Member

I updated the web player to the new horizontal centering logic, if you want to check it out.

https://dbalsom.github.io/martypc/web/player. … ?title=area5150

The transition from DOS into the intro effect is much cleaner now.

EDIT: Here's CGA_COMP to play around with too

https://dbalsom.github.io/martypc/web/player. … l?title=cgacomp

Last edited by GloriousCow on 2023-07-03, 01:01. Edited 2 times in total.

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

Reply 77 of 113, by VileR

User metadata
Rank l33t
Rank
l33t

Nice, looking way better now. 😀 Vertically perhaps it could still use a tiny upwards nudge, but that's hard to tell- it might just be that the canvas is slightly cut off at the bottom? (there's an ~8-pixel strip of background that sticks around after I hit 'Run'.)

For what it's worth: in terms of display size, my 5153 as shown in that YouTube video may or may not be typical... you can find quite a few of others that look pretty much like mine (e.g. relevant videos by PCRetroTech and Al's Geek Lab), and others that are a bit different, say https://www.youtube.com/watch?v=auVLqRJCOJ4. OTOH, it's not like IBM ever provided any clue about the 'proper' adjustment, and they probably never gave it as much thought as we have in this thread.

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

Reply 78 of 113, by superfury

User metadata
Rank l33t++
Rank
l33t++

I'm testing the demo again with UniPCemu's latest commit.

It seems to lose sync (w/ garbage or out-of-range data displayed on the screen, I see a pink or red line at the right quarter of the screen during those failed frames, the left half being the rendered image from the wobbly effect) every other frame or so during the wobbly text part before the dancing elephant?

Looking at the video renderer, I don't see it rendering ANY overscan being timed/rendered at all when rendering the 3D vector image bouncing up and down the screen? The CGA is supposed to have it in it's precalcs though.
It's supposed to be rendered when:
Character column at CGA register #1's value and higher (outside Horizontal active display).
Character row at CGA register #6's value and higher (outside Vertical active display).

The chaplin part is still recognisable but with the same issues?
https://www.dropbox.com/s/2xu696cobhro430/Uni … 4-05-44.7z?dl=0

The attachment UniPCemu_5150area_chaplinpart_rendering.png is no longer available

The credits might be a bit more stable now?
https://www.dropbox.com/s/bt2dozbp53q14ie/Uni … 4-11-59.7z?dl=0

So a slight improvement with the improved interrupt timings, but not entirely there yet.

Looking at the sun image at the credits, I do see a distinct pattern now, in character clocks off as a binary string, it looks like a
(at CRT coordinates 268,113) 0100 1011 11 repeating twice, followed by 11, that entire sequence (the repeating twice and the two scanlines with 11 displacement) repeating across the entire image? The 1-lines being 18 pixels moved to the right on the scanline (horizontal measures taken at the widest part of the sun image.

The attachment UniPCemu_5150area_sunimagemeasures.png is no longer available

I've marked the start of the area that's measured and one scanline of it (two times 8 pixels) for easier viewing with a 0101 pattern black pixels (and 1010 vertical, starting at the leftmost part of border of the sun).

I think it did indeed improve at the credits, although just a bit?

Edit: Only after running the demo (and the recordings in this post) and checking out the CGA blanking signal I've noticed that the blanking signal detection of ALL video cards supported (so MDA, CGA, VGA as well as all SVGA cards) was having the blanking precalc on the lookup table inversed! So when it was blanking it was calling the non-blanking function and when it wasn't blanking it was calling the blanking function to render pixels!
That's fixed now! 😁

Edit: Some images of the incorrect and correct frames during the scrolling animation:

The attachment UniPCemu_5150area_houses_wrongframe.png is no longer available
The attachment UniPCemu_5150area_houses_correctframe.png is no longer available

That's until the bob/landing on the ground at the end occurs after which the glass ball-animation starts playing.

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

Reply 79 of 113, by GloriousCow

User metadata
Rank Member
Rank
Member
superfury wrote on 2023-06-27, 12:21:

I'm testing the demo again with UniPCemu's latest commit.

It's weird that you have full glyphs showing anywhere during these effects.

The attachment glyphs.PNG is no longer available

If an entire character glyph is drawn that implies that R9 is 7 at some point, which it never should be during these effects.

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