Shop OBEX P1 Docs P2 Docs Learn Events
Atari 2600 Emulator — Parallax Forums

Atari 2600 Emulator

maccamacca Posts: 779
edited 2024-04-16 11:50 in Propeller 2

Hello,

Here is a first version of an Atari 2600 VCS emulator, using my 6502 processor emulator.

Some screenshots:



I have tested few games, some seems to run fine, other have issues with the objects positioning (still a bit off in some cases). It also implements the more simple "F8" 8k ROM bank switching scheme to run games like Asteroids (works with some issues).

There are some things missing, one for all the sound (not implemented at all) and others needs a better implementation (wrapping objects out of the right side for example) and for some reasons I can't get the missiles in Combat to move horizontally.

It runs a 320MHz (more the better, I was running at 350MHz), can run at less if disable the video synchronization, with VGA 640x480@60Hz and simple USB controller support.

There are margins for more optimizations but I'm running out of cog/lut code space and there are a number of things to precalculate to reduce the rendering code to the bare minimum. I need to reduce the code for the 6502 instructions, this will take a lot of time...

As usual, it doesn't include any rom because of copyright, licenses, etc.

Enjoy!

Comments

  • Wuerfel_21Wuerfel_21 Posts: 5,044
    edited 2024-04-02 16:26

    Oh, another one! (if you haven't checked the other thread, I'm doing SNES emulator now because I have zero willpower)

    Good job, works for me. At least good enough to grab the holy grail in Adventure. And what more can one really ask for? (aside from sound)

    I had to switch out to a different controller though. These days I mostly leave that troublesome 8bitdo SN30pro connected to the P2. Your USB code doesn't have the fix to make it work: https://github.com/Wuerfel21/usbnew/commit/84477ca80a42750ec17833d057e4692b1120e200

    (oh, and I can't assemble it with flexspin, it doesn't like your alignment with ORGF - will have to file a bug later) EDIT: did submit a fix

  • RaymanRayman Posts: 14,626

    Yes, Adventure is the one I remember most. Played that a lot, back in the day...

  • Transplanted the 8bitdo fix from usbnew, works fine. There's also a logical error in hpad_translate wherein the X/Y axis check overwrites the hat check. Attached the modified file.

  • maccamacca Posts: 779

    @Wuerfel_21 said:
    I had to switch out to a different controller though. These days I mostly leave that troublesome 8bitdo SN30pro connected to the P2. Your USB code doesn't have the fix to make it work: https://github.com/Wuerfel21/usbnew/commit/84477ca80a42750ec17833d057e4692b1120e200

    I planned to use usbnew for this, but for some reasons it caused noise on the VGA output, so I have used my version without all the new changes.

    Transplanted the 8bitdo fix from usbnew, works fine. There's also a logical error in hpad_translate wherein the X/Y axis check overwrites the hat check. Attached the modified file.

    Thanks.

  • @macca said:
    I planned to use usbnew for this, but for some reasons it caused noise on the VGA output, so I have used my version without all the new changes.

    Well that sounds really strange. What kind of board are you using? I think your version doesn't have 1000Hz polling, that seems like the only thing that would be able to cause more line noise to appear. Is it like a little bit of noise or super terrible?

    What a shame, I really designed the emupad stuff in usbnew to be maximally convenient for this sort of thing.

  • maccamacca Posts: 779

    @Wuerfel_21 said:

    @macca said:
    I planned to use usbnew for this, but for some reasons it caused noise on the VGA output, so I have used my version without all the new changes.

    Well that sounds really strange. What kind of board are you using? I think your version doesn't have 1000Hz polling, that seems like the only thing that would be able to cause more line noise to appear. Is it like a little bit of noise or super terrible?

    I'm still using the old Edge board without PSRAM or SD, withe the P2 breadboard and a lot of wires (maybe some interference is possible).
    It was like an old analog TV set that wasn't tuned correctly to the channel... so maybe good for the kind of emulator :smile:
    Apparently it wasn't affecting the sync signal, only the visible part.

    What a shame, I really designed the emupad stuff in usbnew to be maximally convenient for this sort of thing.

    I'm pretty sure it is something I did either in the Atari emulator or adapting the usbnew source to my compiler (had to convert the preprocessor directives to c-style and found a couple of bugs in the compiler). Also had enough headaches with the rendering code optimizations and wasn't in the mood to find the cause of such weird issue but I'll get back to it later.

  • @macca said:
    I'm still using the old Edge board without PSRAM or SD, withe the P2 breadboard and a lot of wires (maybe some interference is possible).
    It was like an old analog TV set that wasn't tuned correctly to the channel... so maybe good for the kind of emulator :smile:
    Apparently it wasn't affecting the sync signal, only the visible part.

    The authentic Atari experience! 📺

    I did recently notice/fix a problem wherein when you have the port enable pin set to -1, all pins on port B would be driven low due to a severe shortage of the letter S, but that wouldn't cause a problem for VGA DACs I think.

    Also had enough headaches with the rendering code optimizations and wasn't in the mood to find the cause of such weird issue but I'll get back to it later.

    Well, I'm sattled with doing the SNES renderer, imagine the headaches I'm having :) I was thinking that the window system on there (which allows cutting shapes out of layers) is oddly Atari-esque, in that to make any shape other than a vertical bar, the left/right position registers need to be changed per-scanline.

    Relatedly, would you be interested in a convenient retro video driver? I've been thinking that I need to reform the mess that is MegaVGA/NeoVGA/ExVGA (which despite the name also support composite/S-video/YPbPr/HDMI/etc) into a single generic driver that can do everything, while adding in the fruits of the HDMI audio packet research (possibly also S/PDIF as an option alongside analog video) . I think you'd prefer if it didn't need any Spin to start up, right?

  • maccamacca Posts: 779
    edited 2024-04-03 08:21

    @Wuerfel_21 said:
    Relatedly, would you be interested in a convenient retro video driver? I've been thinking that I need to reform the mess that is MegaVGA/NeoVGA/ExVGA (which despite the name also support composite/S-video/YPbPr/HDMI/etc) into a single generic driver that can do everything, while adding in the fruits of the HDMI audio packet research (possibly also S/PDIF as an option alongside analog video) . I think you'd prefer if it didn't need any Spin to start up, right?

    The plan for the Atari emulator was to use Spin to have all the drivers in separated sources, more manageable (everything in a single pasm file is a nightmare to navigate...), so no problem with that.
    I was thinking about implementing a video driver with a configurable framebuffer bitmap and a text-only overlay to display menu, debug informations, etc. I'm not sure but I think you already implemented something like that for your emulators (still haven't the hardware to try them...).

    The Atari TIA renders to a 160x210 (or ~242 for PAL) x 8bit buffer, other emulators have a similar requirements, ZX Spectrum and MSX/Coleco are 256x192 (+ some border). Requires duplicated pixels and rows to fit the VGA resolution (currently 4x horizontal, 2x vertical). I have also implemented a double-buffer for the Atari.

    A simple text overlay, 80x25 (or 30) with VGA colors should be enough for the menu requirements, with trasparency so the underliying bitmap is visible.

    This for VGA output. For composite I was never able to get a decent picture for PAL (NTSC is a bit more good) so I would like to have an RGB output to feed to a SCART/RGB converter for HDMI or directly to a TV that still has SCART input.

    BTW, in the meantime I restored the usbnew driver and guess what, everything works correctly, I can't reproduce the issue anymore. I have USB_ENABLE_OFFSET set to -1 and doesn't seems to cause any problem even with the VGA on pins 48+.

  • Wuerfel_21Wuerfel_21 Posts: 5,044
    edited 2024-04-03 21:23

    @macca said:
    The plan for the Atari emulator was to use Spin to have all the drivers in separated sources, more manageable (everything in a single pasm file is a nightmare to navigate...), so no problem with that.

    Oh yea. What I do is use flexspin's ability to change the base address on the command line to build the spin code into high memory and then I use a FILE include to load it in the big assembly file. So that way I can take advantage of manual memory placement (first 256 bytes for variables, 64K aligned buffers, etc). That still means that all the business logic ends up in a big file, but oh well. VSC can open the same file twice without conflict, so that's often useful to see two parts of the program at once.

    I was thinking about implementing a video driver with a configurable framebuffer bitmap and a text-only overlay to display menu, debug informations, etc. I'm not sure but I think you already implemented something like that for your emulators

    Actually, none of that. My current drivers really just have a 320x2 buffer for scanline rendering. Of course it'd be easy to make it use full frame buffers instead. One of the horrible modified versions I have automatically requests lines from an external framebuffer into the line buffer, which is also pretty useful.

    A simple text overlay, 80x25 (or 30) with VGA colors should be enough for the menu requirements, with trasparency so the underliying bitmap is visible.

    I did originally want to implement a text overlay for MegaYume, but eventually abandoned that idea. The video driver just doesn't have time to do it in every mode I want it to work in (and putting it in the actual render cogs is also a non-option). The main trouble is that when using the TMDS encoder, you can't change XFREQ to scale horizontally. It's always 10 cycles per pixel. The simplest solution to that looks something like

                  rep #3,#320
                  rflong pa
                  andn pa,#$FF
                  xcont hdmi_command,pa
    

    (where hdmi_command is a 2 pixel 32 bit immediate command. The instructions change slightly for 16bpp, LUT etc modes).

    In my HDMI audio proof-of-concept, I found a way to interleave useful work with pixel doubling, but building the audio packet takes up most of the time available (though that was at 252 MHz).

    Anyways, I figured that there wasn't that much of a use anyways. Debugging over serial port is... fine and hard-switching between the menu screen and the game image isn't that big of a deal. My stuff doesn't have any menu other than the file select, anyways. Though for a computer emulator you'd probably need it to swap/flip disk images on the fly. Or if you wanted save states, cheats, etc.

    (still haven't the hardware to try them...).

    >
    Oh, those RAM Edges do run a pretty penny. I can't complain, Parallax hardware spontaneously materializes in my mailbox sometimes and that's how I got mine.

    The Atari TIA renders to a 160x210 (or ~242 for PAL) x 8bit buffer, other emulators have a similar requirements, ZX Spectrum and MSX/Coleco are 256x192 (+ some border). Requires duplicated pixels and rows to fit the VGA resolution (currently 4x horizontal, 2x vertical). I have also implemented a double-buffer for the Atari.

    My current crop of driver supports 320 and 256 wide modes in 240p or 480i (the driver can blank out some lines at the top and bottom to get down to 224p etc). It can then multiply vertically by 2x/3x/4x for VGA output. For a new driver I was planning 256/320/512/640 width support, but I guess adding 128/160 on top is easy enough. Also border colors that aren't always black.

    Support for PAL/50Hz might need some head-scratching.

    Though there's a sortof major headache about resolutions, borders, aspect ratios and screen sizes buried here. So a TMS9918 has a 256-wide screen using a 5.37 MHz dot clock, right? In something like an MSX emulator, it'd be depicted as surrounded by a colored border of some thickness. An NES has a 256-wide screen using 5.37 MHz dot clock, right? But that one is usually depicted without a border. And that's empirically what it looks like on the average TV, the picture cuts into overscan:

    (not using an actual NES here, but close enough to illustrate the point. Also my TV is not average because I recalibrated the geometry as good as I could get it, etc etc)

    So how does one depict such a 256-wide mode? What a mystery ~

    The brainrot goes further though: So the Megadrive has two possible horizontal resolutions: 256-wide 5.37MHz (matching the above) and 320-wide 6.71MHz. These are the same width. We normally consider the pixels in 320x224 mode to be 1:1 squares (so when we scale to VGA 640x480, we simply scale 2x and put borders on it). What does that make the pixels in 256x224 mode then? 5:4. But if you look online, the NES pixels are normally considered 8:7, how does that happen? The Megadrive 320 pixels are actually slightly skinny if you're pedantic: 32:35. And (22/35)*(5/4) does result in 8/7. Meanwhile the NeoGeo's 320 pixels are actually clocked 6.04 MHz, which is closer to being theoretically square, but makes the left and right edges go far into overscan to the point where many games put nothing and/or garbage in the left and right 8 pixels. Of course over in reality, what is square really depends on how dried up the TV's capacitors are.

    For lowres analog outputs, I've been trying to match the original timings as close as possible, which is really the thing to do. For VGA (and HDMI of course) you run into the problem that LCD monitors expect to get exactly 640 pixels and will sample them with no attempt at low-pass filtering. So for anything 320-wide, you really want to scale it exactly 2x, which will make the pixels ostensibly square, but it's not a big problem. But what to do about the 256-wide modes? For VGA I can do a fractional scale using XFREQ, which results in unevenly sampled pixels on LCD. So this is where using a higher output resolution is useful: the pixels are sampled often enough to reduce the artifacts. At 1280x960 they disappear entirely since 1280 is the LCM of 320 and 256. But at that point, we're still stretching it out too much (5:4) to make 256 the same width as 320. But I think that's the least obnoxious option(?)

    For HDMI it gets worse because XFREQ doesn't work. So 256-wide modes will necessarily be too narrow and not match 320-wide modes. However, if one only needs the 256-wide modes, I think the tendency of HDMI displays to always stretch the signal to 16:9 can be abused to fix the aspect ratio by adding just the right amount of border pixels. Would end up with something like a 744*480 active area. That stands to be tested yet.

    This for VGA output. For composite I was never able to get a decent picture for PAL (NTSC is a bit more good) so I would like to have an RGB output to feed to a SCART/RGB converter for HDMI or directly to a TV that still has SCART input.

    NTSC/PAL composite can't be good because there's a bit of a design oopsie in the P2. The DACs only go to 1V. But a composite signal can go a little bit higher (usually seen with bright yellow). So you get to pick your poison between yellows turning blue (8 bit overflow), too dark picture (though some displays have AGC and will be fine - what I do) or shallow sync pulses (will look normal on many displays, but ones employing aforementioned AGC will go apeshit - this is what Chip's NTSC example does)

    Maybe I should try if switching the DAC type makes it better. That'd have the wrong impedance, but might fix the level issue. EDIT: Just tried using the 124Ω DAC and that really makes it much better! Why didn't I try this before?

    Other than that, I spent quite a bit of time getting the NTSC signal just right. The PAL is also good, but I use the same 60Hz timing as NTSC, so the color carrier doesn't line up nicely and there's crazy dot-crawl (unless using S-Video). That's just how 60Hz PAL always is though, Wii/PS2/etc also have it. Though they have luma trap filters.

    Lowres RGB I'm actually still missing code for, though it'd really be trivial. I actually have loads of SCART equipment, but no breakout to connect the P2 to. I do have a YPbPr to SCART converter box though and I've just been using that with the P2, lol.

    BTW, in the meantime I restored the usbnew driver and guess what, everything works correctly, I can't reproduce the issue anymore. I have USB_ENABLE_OFFSET set to -1 and doesn't seems to cause any problem even with the VGA on pins 48+.

    That's good to hear. If you're using the latest version the enable pin issue has been fixed for good.

    Also, sorry for the huge post, I got carried away.

  • TonyB_TonyB_ Posts: 2,178
    edited 2024-04-04 18:34

    @Wuerfel_21 said:
    Maybe I should try if switching the DAC type makes it better. That'd have the wrong impedance, but might fix the level issue. EDIT: Just tried using the 124Ω DAC and that really makes it much better! Why didn't I try this before?

    I calculate 1.25V max across 75Ω load for DAC mode 123.75Ω, 3.3V or 1.0V for DAC value $CC. Not tried it yet for video but seems a useful mode.

  • @TonyB_ said:
    I calculate 1.25V max across 75Ω load for DAC mode 123.75Ω, 3.3V or 1.0V for DAC value $CC. Not tried it yet for video but seems a useful mode.

    Checks out, I think white level ends up at $C7, which is still slightly below 1V, but it looks close enough to properly white.

  • roglohrogloh Posts: 5,783
    edited 2024-04-04 23:49

    @Wuerfel_21 said:

    @TonyB_ said:
    I calculate 1.25V max across 75Ω load for DAC mode 123.75Ω, 3.3V or 1.0V for DAC value $CC. Not tried it yet for video but seems a useful mode.

    Checks out, I think white level ends up at $C7, which is still slightly below 1V, but it looks close enough to properly white.

    @Wuerfel_21 do you see any reflections or other interference effects with the higher level 123.75 ohm DAC with mismatched impedance. I sort of wonder if that is the preferable solution overall in general if you don't.

    Given most of this is just one time configuration related perhaps we could allow a selection of options for people to choose to best suit their equipment as not all solutions will look the same for everyone:
    1) extended DAC voltage range using 123.75 ohm output impedance instead of 75 ohms - may possibly reflect with long cables etc but gives good brightness/colour levels and is a closer match to the optimal levels (though still not perfect)
    2) reduced sync tips (for non-AGC monitors) - increases DAC dynamic range allotted to for luma levels but is very non-standard and may over-saturate on some monitors
    3) reduced overall scale (for AGC monitors which restore it) but sync is properly in scale with peak video levels - downside is reduced DAC dynamic range of possible brightnesses/colours with more of the DAC used for sync. Could look dim/anemic on some monitors.

  • To connect P2 or other systems on the test bench to my big TV I have ~5 meters (guesstimated) of the nastiest RCA cable imaginable + some amount of adapters and switch boxes.

    Is perfectly fine (NeoYume running The Last Blade in PAL60 composite with 124Ω DAC):

    Then again, you probably need at least 50 meters for it to even start mattering (just based on propagation time).

  • maccamacca Posts: 779

    Updated the emulator code in the first post.

    Some improvements in the video renderer, among others, now sprite objects correctly wraps around the right edge, this will make games like frogger and megamania work correctly.
    Implemented the audio driver, may still need some improvements (some sounds doesn't seems exactly like the Stella version) but overall seems to work fairly good.
    I have removed all the illegal/undocumented opcodes to make some room in cog and lut space, none of the games I tried uses them... good.

    The GitHub repository have the Spin version with usbnew (there renamed to simply USB.spin2) and a text mode debugger option, just in case you want to debug your Atari games.
    Unfortunately, I think it can be compiled only with Spin Tools IDE (but not with the last release since I found a couple of bugs...).

    Now I'm short on clock cycles, I need to improve the missiles rendering but I fear that anything I do will take too much time for 320MHz clock.

  • Sound! It's really loud though with headphones plugged in directly. I had to cut the amplitudes down to 1/4th.

    @macca said:
    The GitHub repository have the Spin version with usbnew (there renamed to simply USB.spin2) and a text mode debugger option, just in case you want to debug your Atari games.
    Unfortunately, I think it can be compiled only with Spin Tools IDE (but not with the last release since I found a couple of bugs...).

    Btw, you don't need to have a padmap_builtin.dat if all the rules in there are just 1 2 3 4 5 6 7 8 9 10, since that's what it does by default if no rule is found. The point of that is when you have a controller you know the correct map for and that map is not necessarily what you'd generally set it up as (i.e. what you'd put into a wildcard rule on your SD card). For example, SEGA-style 6-button controllers don't really fit into the usual 4-button gamepad scheme, so the C/Z buttons end up in unusual spots. On the other hand, MegaYume's default setup tries its best to map the 3/6 button layout onto a standard 4 button pad. Add those two together and you get a really confusing button map. Builtin rules solve such a conundrum in an idiot-proof manner. Of course if you don't have SD card support, you can just chuck whatever rules in there in lieu of being able to parse the global map file.

  • maccamacca Posts: 779

    @Wuerfel_21 said:
    Sound! It's really loud though with headphones plugged in directly. I had to cut the amplitudes down to 1/4th.

    Ah... just copied the settings from the AY-3-8912 emulator, only two channels in the Atari, maybe that's why is so loud...

    Btw, you don't need to have a padmap_builtin.dat if all the rules in there are just 1 2 3 4 5 6 7 8 9 10, since that's what it does by default if no rule is found. The point of that is when you have a controller you know the correct map for and that map is not necessarily what you'd generally set it up as (i.e. what you'd put into a wildcard rule on your SD card). For example, SEGA-style 6-button controllers don't really fit into the usual 4-button gamepad scheme, so the C/Z buttons end up in unusual spots. On the other hand, MegaYume's default setup tries its best to map the 3/6 button layout onto a standard 4 button pad. Add those two together and you get a really confusing button map. Builtin rules solve such a conundrum in an idiot-proof manner. Of course if you don't have SD card support, you can just chuck whatever rules in there in lieu of being able to parse the global map file.

    Yes, I need to learn it a bit more... however, I was a bit confused because I'm using a PS3 controller and for some reasons it wasn't mapping any button (only the direction hat/axis) without the entry in padmap_builtin.dat A generic HID controller (NES replica) works, so maybe there is a glitch in the PS3 decoder?

  • Wuerfel_21Wuerfel_21 Posts: 5,044
    edited 2024-04-11 19:31

    Hmm, that shouldn't make a difference. The default mapping is just some rule-shaped data that follows the actual rule buffer immediately. So when it checked all of the rules without a match, the pointer inherently ends up there. The rule check happens regardless of controller type.

    I don't have a PS3 controller, though I do have one that (somehow???) triggers the PS3 code path and that works fine. Though I just noticed the analog data for L2/R2 isn't there, but that isn't relevant to that. (EDIT: v1.1.6 now has analog triggers for PS3)

  • maccamacca Posts: 779

    @Wuerfel_21 said:
    Hmm, that shouldn't make a difference. The default mapping is just some rule-shaped data that follows the actual rule buffer immediately. So when it checked all of the rules without a match, the pointer inherently ends up there. The rule check happens regardless of controller type.

    Aha... got it!

    The row

    byte 0[@emupad_rule_buffer + EMUPAD_MAX_RULES*_EMUPAD_RULE_SIZE - $]
    

    generates more bytes than expected in my compiler, so the default rule ended being all zeros, replacing $ with @$ fixed it.

    Now I need to check what PNut generates in this case.

  • Yea, I was thinking something like that, though I was put off by the statement that the generic NES controller works. Was that after adding rules? Maybe it happens to use the same ID as one of the other pads?

  • maccamacca Posts: 779

    @Wuerfel_21 said:
    Yea, I was thinking something like that, though I was put off by the statement that the generic NES controller works. Was that after adding rules? Maybe it happens to use the same ID as one of the other pads?

    Sorry, that confused me too... I think I added a rule for the NES and tought that the PS3 doesn't need one because the buttons are at a known position, wasn't thinking about the need for a default rule in all cases (wrongly tought that PS3 skipped the default rule...).

  • maccamacca Posts: 779
    edited 2024-04-16 12:11

    Updated the first post with a number of fixes.

    Finally I got the object position algorithm (or crazyness, depending on the point of view...) working correctly, thanks to javatari.js.
    All games I have tested works correctly, including Combat, Poleposition (highly depending on the correct object position) and Asteroids (forgot to add the extra cycle when jumps cross a page boundary).
    There are still a couple of glitches: Poleposition show a straight line across the screen for a frame or two (don't know why), Phoenix has an "enhacements" were it is easies to defeat the final "monster ship" because the shield update relies on the extra delay required by TIA to update the playfield (can't implement without a proper delay queue, which is as of now impossible to implement).

    The spin version now have a cartridge selection menu (no filesystem, just all in memory):

    Displayed as on overlay on the game screen:

    The overlay is just a second 640x240 bitmap mixed with the game screen, nothing fancy or high-tech. Using the CGA fonts with double lines to "simulate" an 8x16 font resulting in a 80x30 characters display.

    I'll soon release an update to Spin Tools IDE so it can be complied with that. Was waiting for the PNut interpreter update to add structures and other things, but looks it will take more than expected.

    I think I can call this done, the emulation is good enough to run several games.

  • RaymanRayman Posts: 14,626

    Nice. I see one can buy 2600 controllers for $15. Looks like has a DB9 interface?

  • maccamacca Posts: 779

    @Rayman said:
    Nice. I see one can buy 2600 controllers for $15. Looks like has a DB9 interface?

    I think there is also an USB version but can't find it.
    Anyway, support for the original controllers is not implemented but is very easy since it is just a parallel interface (4 bits for direction + 1 bit for fire button).

Sign In or Register to comment.