• Welcome to Talking Time's third iteration! If you would like to register for an account, or have already registered but have not yet been confirmed, please read the following:

    1. The CAPTCHA key's answer is "Percy"
    2. Once you've completed the registration process please email us from the email you used for registration at percyreghelper@gmail.com and include the username you used for registration

    Once you have completed these steps, Moderation Staff will be able to get your account approved.

MiSTer: the thread of cycle accuracy

Yimothy

Red Plane
(he/him)
I've been playing around some more with the MiSTer, thinking way too hard about SMS resolution. The thing is, the SMS runs at two resolutions: 256x192 and 248x192. In fact it's always running at 256x192, but whenever there's horizontal scrolling the system blacks out the leftmost tile column (8 pixels). MiSTer unfortunately doesn't let you directly control the horizontal scaling by setting a multiple, but you can manipulate it via the custom aspect ratio setting (and setting vertical scaling to integer). The problem is that you can't set a different aspect ratio for 256 and 248 pixel wide resolutions, so you either end up downscaling 256 slightly or upscaling 248 slightly:

GcEaJsl.jpg


This is from Sonic 1, running at 248. In the above image the shadow with the arrow is noticeably wider than the others because of the upscaling of the image to a multiple of 256. In the lower, I've set the aspect ratio to 248:192, so it's been scaled up to a clean multiple of 248 and the shadows are even.

iVSdstZ.jpg


Here's the shop screen of Wonder Boy in Monster Land in extreme close-up. This is 256 pixels wide in the game, and the upper image is pretty even. In the lower, it's been downscaled to a multiple of 248 and the right side of the T is too narrow.

Games go back and forwards between resolutions on the fly, so whichever I choose it'll be scaled incorrectly some of the time. The mega drive core actually has different aspect ratio settings for its 256 and 320 wide modes, so maybe they could do that here too. Or, if the point is to be accurate to the original system:

2zNEHwk.jpg


Just display 248 pixel wide images as 256 pixels with with the left column blacked out. This image is WBiML running on my Mega Drive. The gap on the left is wider in the lower image, because part of it is the left column that the game isn't showing. This would definitely lead to people complaining about the image being off-centre, so maybe it could be an option in the video settings and off by default.

I'm thinking about joining the MiSTer forums to post about this, because I don't think it'll be implemented otherwise and I apparently care way too much about it (edit: I’ve now done this).

I've also done some fiddling with my M30 controller. It was dropping out a lot when I used it on my MiSTer, so I updated the firmware and it's worked just fine since. Updating the firmware was pretty harrowing, though - it failed about ten times before it worked, and the controller was useless after the first fail - the attempt apparently wiped the existing firmware so it just didn't work until I got the new stuff running. I don't think it should make any difference, but all the times that it failed I was copying the new firmware over directly from the .zip file it came in (copying just the relevant file out of the zip, not putting it on there zipped). When I unzipped the file and then copied over it worked first time for both controller and dongle.
 
Last edited:

MCBanjoMike

Sudden chomper
(He/him)
Ha ha, well maybe your passion will be enough to motivate the SMS core designer to update it? I'm sure they don't see a lot of people who are as excited about that console as you are.

Meanwhile, I'm dying to play DoDonPachi on my CRT monitor, but for the time being I can't get it running. Computer monitors typically run at frequencies of 30kHz and up, whereas 240p games on CRT TVs run at 15kHz. The simple solution is to literally double every pixel, which transforms a 240p signal into a 480p signal and doubles its frequency. This works with most MiSTer cores, providing you (me) with a video signal that is almost too clean? Like, I'm running on a CRT monitor, but it's so crisp it practically looks like an LCD - weird problem to have. Sadly, the DoDonPachi core doesn't have support for scandoubling yet, so it's locked at around 15kHz no matter what framerate you play it at (the game natively runs at a non-standard 57.5Hz). Shane Lynch posted screenshots on Twitter showing that he got the scandoubler to work, so I had a look at the core's Github page and, sure enough, there's a pull request titled "Adding scandoubler support" that is waiting to be approved. Wondering when it might be approved, I kept on sleuthing, which led me to the Twitter account of nullobject, the guy who developed the core...and whose DE-10 just broke. So it looks like I might have to keep waiting a while longer. It's too bad, because I'm itching to turn my CRT sideways and play some dang TATE games properly for once in my life.

I recognize that this is a very specific issue that is relevant to an extremely small number of people, but I found it interesting to see how the development was going in real time. Overall, I've been super happy with my IO board and CRT monitor combo. It makes streaming really easy, since I can feed the HDMI out to my capture card and still play lag-free on the CRT monitor. I'm not entirely sure how the image quality compares to a fancy PVM, but for the $30 I paid for the screen I think I'm doing pretty well.
 

Yimothy

Red Plane
(he/him)
(cross-posted from the Mister forums)

Well, it turns out this was pretty simple. Delete line 135 in /rtl/video.vhd, which starts horizontal lines from pixel 9 when masking is turn on:

Code:
134        hbl_end <= conv_std_logic_vector(500,9) when border = '1' and gg = '0'
135                else conv_std_logic_vector(008,9) when (border xor gg) = '0' and mask_column = '1'  --this one
136                else conv_std_logic_vector(000,9) when (border xor gg) = '0'
137                else conv_std_logic_vector(048,9);

And:

TqchPa2.png


We've got the blanked out left column visible! This then gives a consistent 256 pixel wide image, so the scaling isn't messed up by changing from 248 to 256. It is also, I believe, more accurate to how original hardware displayed. Wonder Boy in Monster Land actually took advantage of this:

bKRMNxK.png


Above is the title screen as it appears in the current version of the SMS core. The image is slightly off-centre to the left.

fpYoz3D.png


Here's the same thing with the line above deleted. The left column is displayed (in the background colour), so the image is more even. Why they didn't just use 256 mode for the title screen like in the shops I don't know.

22OeDuc.png


Not every game seems to have been as careful with it as WBiML. This is Sonic 1 without the left column. Add it in:

R8mjxUv.png


And you get a column of blue. I think this is accurate to original hardware, but it doesn't actually look great in my opinion. But there's no distortion from uneven scaling if you turn on vertical integer and set the aspect ratio for horizontal integer.

Next step would be to make it optional. I think I have that mostly figured out: add a line to SMS.sv in the CONF_STR section:

Code:
    "P1OS,Show masked left column,Yes,No;",

And instead of deleting the line in video.vhd, add a variable for showing the masked column or not, and change line 135 to

Code:
    else conv_std_logic_vector(008,9) when (border xor gg) = '0' and mask_column = '1' and showmask = '0'

Only problem is, I cannot for the life of me figure out how to get information from CONF_STR into video.vhd to set the variable. It appears this is too basic to bother explaining in the documentation (or I can't find the explanation). I'm a nurse, not a programmer, so it's beyond me. Little help?

The other thing would be to have three options: not include the left column at all (current behaviour), include it drawn in the background colour (as in my screenshots above), or include it but always black it out (less accurate but I think would look better in most cases - in non-full screen aspect ratios it would just disappear into the existing black border).
 
Last edited:
Only problem is, I cannot for the life of me figure out how to get information from CONF_STR into video.vhd to set the variable. It appears this is too basic to bother explaining in the documentation (or I can't find the explanation). I'm a nurse, not a programmer, so it's beyond me. Little help?

The other thing would be to have three options: not include the left column at all (current behaviour), include it drawn in the background colour (as in my screenshots above), or include it but always black it out (less accurate but I think would look better in most cases - in non-full screen aspect ratios it would just disappear into the existing black border).

Seems like you've done most of the legwork already. I would hope if you opened an issue on the GitHub it would get addressed. If your up for it you could even open up a Pull Request for the SMS Core and submit your changes and see if they get picked up.
 

Yimothy

Red Plane
(he/him)
I’d like to do a pull request, but first I’d have to figure out the implementation, right? I guess I’ve got it solved from my point of view since I just want the masked column to be included, but if I could just figure out how to access the configuration data I’d be able set menu options to turn it on and off.

Also I don’t have a GitHub account and I find the interface really confusing.
 
Also I don’t have a GitHub account and I find the interface really confusing.
I've got an account, I could post an issue and link to your thread on the MisterFPGA boards. At the very least if I create the issue the repository owner should get notified. Should I go ahead and do that? Considering the effort you put in I would hate for it to get overlooked.
 

Yimothy

Red Plane
(he/him)
Thanks for the offer and I may still take you up on it, but for now I think I have an idea of what I need to do in the code and I’m enjoying trying to figure it out.
 

Yimothy

Red Plane
(he/him)
I think it’s fair to say I’ve gotten into it. My latest build of the SMS core has a menu option to include or cut the masked left column, so things are progressing well. It also doesn’t actually mask the column, so you can see it being used to process the right side of the screen, which I did to check that the part of the code which I thought did the masking was actually doing the masking. I kind of don’t understand why it works, though - it looks like it should only apply to graphics modes 1-3, but it’s worked for me in mode 4 (which almost all SMS games run in).

It takes my computer about 20 minutes to build the core, which makes changing a line and seeing what happens pretty slow. All going well I can now expand my menu option to either show the background colour during masking, black out the column, or cut it.

I fired up Sonic 1 SMS on my nomad, and it was a reminder that on original hardware there’s actually a border of background colour on all sides in the overscan. I guess it would be more accurate to include that, but I’m not sure I can be bothered (or know how to do it). I’m also not sure the mister is doing the aspect ratio correctly. 256x192 is a 4:3 ratio, so the mister puts out square pixels, but on a crt I’m pretty sure there were always borders above and below so the aspect ratio of the play area was actually a bit wider. Again, can I be bothered?
 

Yimothy

Red Plane
(he/him)
Alright, I think I’ve done it! It’s midnight where I live, so I’ve left the computer compiling what I hope is my final version of the source and I’m heading to bed, so I won’t know for sure until tomorrow if I’ve ironed out the bugs, but I’ve added a menu option, “Masked left column:” with choices “BG”, “Black”, and “Cut”. Not very intuitive, but you don’t get a lot of characters to work with. BG (default) gives a left column in the background colour, Black makes it black, and Cut cuts it out so that the MiSTer generates a 248 pixel wide image instead of 256 (i.e., current behaviour). My previous compile had this working, but I had the two bits where the choice is stored in the wrong order, so BG did what cut should have and vice versa. The two bits are processed separately, one setting the column to black or background and the other leaving it in or cutting it out. I also set it so the menu option is greyed out if the already present border option is set, since that already drew the masked column along with bigger borders on each edge. And I added a tweak so that the black option is ignored if the borders are on, since in my last build this led to a twelve pixel background colour column, then an eight pixel black column, then the actual game image.

Great Scott, Yimothy. What you're doing is seriously impressive.


Thanks, but I reckon this would have been about ten minutes work for someone who knew what they were doing. I just looked at the source code for things that seemed like they might change what I wanted to change and tried changing them. Hopefully I haven’t inserted any bugs or done this in too stupid of a way. I’ll post my code once I’ve seen that it’s actually working (and I have some time). Then I guess I’ll have to learn how to make a pull request.
 

RT-55J

space hero for hire
(He/Him + RT/artee)
not gonna lie, just going ahead and successfully tweaking a MiSTer core like that is a serious flex (especially if you don't know VHDL). mad props to you.
 

Yimothy

Red Plane
(he/him)
OK, so as I said, I've done what I set out to do (along with some mission creep) with the SMS core. My personal build now has a menu item, "Masked left column", with the following options:

"BG", short for background, which uses the background/overscan colour when the left column is masked:

fAPrP9C.png


This is how it's handled on original hardware, and the default in my version.

"Black", which uses black to mask the left column:

8vdhJlh.png


This is not accurate to original hardware, but makes sense on MiSTer where the rest of the overscan area is blacked out unless you have the "Border" option turned on. This maintains the 256 pixel width of the game image.

And "Cut", which cuts off the left eight pixels when the left column is masked:

tTh0fES.png


The difference between this and "Black" is subtle but significant: the image produced here is 248 pixels wide instead of 256. That means that scaling set up for 256 width will be distorted when this is set. Since many SMS games turn left column masking on and off depending on what's happening in-game, even if you change your aspect ratio to match the 248 width you'll wind up with distortions when 256 pixel images are scaled for that AR. The advantage of this setting is that it only includes the active area of the screen, I guess. It's the current behaviour of the official SMS core.

My new menu option becomes inaccessible when the "Border" option is turned on:

4vl7mKA.png


Because showing the borders already includes the masked column shown in background colour, my new menu item is redundant when they're on. But wait, I hear you say, why is that last image 239 pixels tall? Surely that should be a multiple of 8?

yXMPvUO.png


Well spotted, my observant friend. I also tweaked the overscan area a little - I added one more pixel row to the bottom of the image to make it 240 high, as in the image above. I could be completely wrong about this, but I believe the theoretical limit of SMS vertical resolution is 240 pixels, so this seemed more appropriate. Also 239 is a prime number, so if I want to fiddle with custom aspect ratios for border on mode (which I do), I won't be able to simplify them very well. 240 is very divisible, so I'll be able to have smaller numbers in my mister.ini. The horizontal overscan is kind of odd-seeming as well - twelve pixels on the left (20 if the column is masked) and 14 on the right - but the benefit of tweaking that is less obvious to me and I found the code that sets the sizes very confusing and I'm trying not to break anything, so I left it alone.

Anyways, here's how I did it. Bear in mind, I figured all this out by reading the code, trying stuff out, and looking up what I could find information on. I haven't made a serious effort at programming since 2001. What I'm saying is, if my code is sloppy or inefficient, or my explanations of why what I've done works is completely wrong, that's why.

OK, first up: some changes to SMS.sv. I added the following below line 180:

Code:
"D5P1OST,Masked left column,BG,Black,Cut;",

This is the menu option. D5 disables it when the fifth bit in the menumask is set, P1 nests it in the audio/video options submenu, OST makes it an option modifying bits S and T (28 and 29) in the CONF_STR, and the rest is the title and options. Next, change line 268 from

Code:
    .status_menumask({~gun_en,~raw_serial,gg,~gg_avail,~bk_ena}),

to

Code:
    .status_menumask({status[13],~gun_en,~raw_serial,gg,~gg_avail,~bk_ena}),

This sets the menumask's fifth bit to reflect whether the border is on or not. I need this so I can disable my menu option when the border is on. This is not strictly necessary, since my changes are ignored anyway when the border is on. OK, now for line 498:

Code:
494    .x(x),
495    .y(y),
496    .color(color),
497    .mask_column(mask_column),
498    .black_column(status[28] && ~status[13]),

black_column here is new. This is how I convey the request to use black instead of the background colour to mask the left column. status[28] gets the state of bit 28 of the CONF_STR, which is set by my menu option. If BG is selected, it will be zero. If Black is selected, it's one. If Cut is selected, it doesn't matter because the column won't be shown (but it'll be zero). status[13] is the border option. The tilde inverts the result. So basically black_column is positive if Black is selected in the menu and Border is not. The reason I check on the border here is that an earlier build did this:

2D0pDZk.png


when the border was on. Undesirable. Anyway, I'll get in to how the mask colour is set a bit later, for now there's one more change in SMS.sv, at line 639:

Code:
632  video video
633  (
634      .clk(clk_sys),
635      .ce_pix(ce_pix),
636      .pal(pal),
637      .gg(gg),
638      .border(status[13] & ~gg),
639      .mask_column(mask_column),
640      .cut_mask(status[29]),

cut_mask is the new item here. It reads bit 29 of the CONF_STR, which is 0 when BG or Black is set, and 1 when Cut is set. Putting this here sends that information to video.vhd, which is the part of the code that determines which parts of the screen are included in the image MiSTer produces. That's the last change to SMS.sv, so let's take a look at what I've done to video.vhd:

First off, I added a line at line 14:

Code:
6  entity video is
7      Port (

...

14       cut_mask:    in    std_logic;

This is within the port section of the definition of entity video. So cut_mask takes the value specified in the .cut_mask line I put in to SMS.sv. "in" is for input, meaning it reads but cannot write the information. I think I know what std_logic is about, but not well enough to explain it. Mainly I just copied it because that's what all the other lines in this port section had. Anyway, the code in video.sys now has access to a variable called cut_mask that's set to 1 if the user wants to cut off the left side of the screen and 0 if they'd rather obscure it. Next, I changed line 135 from

Code:
134    hbl_end <= conv_std_logic_vector(500,9) when border = '1' and gg = '0'
135            else conv_std_logic_vector(008,9) when (border xor gg) = '0' and mask_column = '1'
136            else conv_std_logic_vector(000,9) when (border xor gg) = '0'

to

Code:
134    hbl_end <= conv_std_logic_vector(500,9) when border = '1' and gg = '0'
135            else conv_std_logic_vector(008,9) when (border xor gg) = '0' and mask_column = '1' and cut_mask = '1'
136            else conv_std_logic_vector(000,9) when (border xor gg) = '0'

By putting "and cut_mask = '1'" at the end, it checks whether that variable is set before implementing this. And what is it implementing? Well, here goes: hbl_end is the point in each row where it stops ignoring the pixels and starts writing them to the image. So line 135 is saying, if the border is off, the system isn't in game gear mode, the column is supposed to be masked, and the user has requested the masked bit be cut off, ignore the first eight pixels. Line 136 is saying if the border is off, it's not game gear, and either the mask is off or the user has asked to include it, then don't ignore the first eight pixels.

Note that the first line is saying that if the border is on and it's not a game gear, start reading pixels from number 500. This confused the heck out of me for a while, but each horizontal row goes up to 511, so when the border is on the overscan is actually read from the end of the previous line before it wraps back to zero. Sort of. The vertical count increments at horizontal count 487, so the end of the previous line is actually the start of the current one. Or something. The horizontal count also skips from 295 to 466. I'm not really sure why, and it doesn't matter for this.

Anyway, the above code either includes or cuts off the left column when it's masked, depending on menu setting. That's what I initially set out to do. The other thing I did in video.vhd was to change line 120:

Code:
            else conv_std_logic_vector(215,9) when border = '1' and gg = '0'

to

Code:
            else conv_std_logic_vector(216,9) when border = '1' and gg = '0'

This is setting vbl_st to 216 instead of 215. vbl_st is the setting that determines when the MiSTer starts ignoring rows of pixels. So by increasing it one I added an extra row to the bottom of the image when border = '1'. This is how I got my bordered screen's vertical resolution up to 240 instead of 239. 216 is 24 higher than the SMS's active vertical resolution of 192.

OK, so that's the mask cutoff and the extra row of pixels. How about the colour of the mask? Well, that was a little more complicated. If you remember back in SMS.sv I had a line ".black_column(status[28] && ~status[13]),"? This was under system, so it passed the result of that (should the masked column be black yes/no?) to system.vhd. So at the start of that file I added

Code:
        black_column:        in STD_LOGIC;

As line 58, just under where mask_column is. I stuck it next to that already-extant variable because they seemed like an appropriate pair. This gets the information from the menu into system.vhd. But system.vhd doesn't do the masking. Further down in the file is "vdp_inst: entity work.vdp", and under that there's a port section. In there at line 247, just under mask_column again, I added

Code:
        black_column => black_column,

which I think takes the information in system.vhd and passes it to vdp.vhd (vdp being video display processor). So then I open vdp.vhd and insert the same two lines at lines 28 and 141 respectively, taking the information and passing it on to vdp_main.vhd (which is where this will actually be done). In vdp_main.vhd I add "black_column: in STD_LOGIC;" as line 29. That gets the information in. Now, how exactly vdp_main.vhd does its thing is still a bit of a mystery to me. It sets a bunch of variables like cram_a and cram_d (I assume the address and data of the cram being worked on). Then there's the out_color and the vram. Which of these does what? I spent a while looking at it and the various if else statements relating to the mode of the SMS and so on, and then I noticed down the bottom:

Code:
    color <= cram_D when smode_M4='1' else 
            "000000000000" when out_color="0000" else 
            "000000000000" when out_color="0001" else

And the list of colours to set went on for all the values of out_color. Could it be that I just needed to ignore all the preceeding stuff and set color to black when the mask was on and set to be black? Let's try it out:

Code:
color <= "000000000000" when black_column='1' and mask_column0='1' and x>0 and x<9 else
            cram_D when smode_M4='1' else 
            "000000000000" when out_color="0000" else

So here I've set it to make the colour black ("000000000000") if the mask is on, the colour is set to black, and the pixel currently under consideration is part of the leftmost column. I was worried this would screw up the image under the mask, which is required for processing of horizontal scrolling, but it doesn't seem to have. So far as I can tell, everything is working as intended.

Man, that's a lot of post for what would have been a very rudimentary programming job if I'd had any idea what I was doing. Hope my explanation makes sense.
 

ShakeWell

Slam Master
(he, etc.)
Jotego posted a Lens clip on Patreon (kinda like a story on Instagram, if you're unfamiliar) showing the CPS2 core booting up with Super Puzzle Fighter! Missing graphical elements, clearly a work in progress, but IT BOOTS.
 

Sarge

hardcore retro gamin'
Definitely impressive. I used his CPS 1.5 core the other night with Cadillacs & Dinosaurs, and other than some occasional glitching in the backgrounds (don't know if that's how real hardware was), it worked great.
 

Yimothy

Red Plane
(he/him)
I've created a fork and pull request on github for my tweak to the SMS core. Hopefully it'll get accepted!

Also, I just remembered this post:

The MiSTer is probably a more sensible option with its broader range of system supports and greater flexibility in terms of setup, but I can just see myself spending hours and hours fiddling with the settings and very little time actually playing games on the thing.

Yeah, I know myself.
 

Sarge

hardcore retro gamin'
I'm really enjoying having the I/O board. I was originally running on a VGA CRT, which decided to kick the bucket, but I've been on my Trinitron lately and boy does it look fantastic. SNES looks amazing - super vibrant colors and really crisp, geometry/alignment issues with this set notwithstanding.
 
I've created a fork and pull request on github for my tweak to the SMS core. Hopefully it'll get accepted!

If you haven't seen it already, your pull request was accepted by sorgelig, the head MiSTer developer, and merged into the main branch.

Congrats! I know people say that sorgelig can be a bit gruff and picky about changes so that's awesome he pulled yours in with no fuss whatsoever. I think your excellent documentation of the issue and fix you developed have a lot to do with that.

I imagine it'll be distributed in the next release in a day or two.
 

Yimothy

Red Plane
(he/him)
Yeah, I got an email to say it was merged. I’m feeling pretty pleased, I gotta say. Not sure if I should have also included a compiled binary, but as you say I’m sure it’ll get added some time soon.

I didn’t directly interact with sorgelig beyond sending the pull request and it being accepted, but the impression I get is that he doesn’t want to be hassled by people asking for stuff. I don’t want to be a hassle, so I did it myself. I just hope I didn’t break anything. I’m sure when it does get distributed there’ll be complaints about the new blank column on the left and the picture being shifted to the right.
 

Phantoon

I cuss you bad
Wow, I think all of us in this thread are tinkerers by nature, but you're now the Tinkerer King. This project is amazing for preservation, so the closer to real hardware the better.
 

Sarge

hardcore retro gamin'
Seriously, thank you for putting all this work in. The project is better for folks like you! :)
 
Top