Jump to content
IGNORED

Emulator test suite?


webdeck

Recommended Posts

I've been learning a lot about various edge cases from threads here, and I am wondering if anyone has already compiled a good set of tests to put an emulator through.  Right now I've just been trying different carts, but that's not a very methodical approach. :)

  • Like 1
Link to comment
Share on other sites

For me, the acid test has been the MEGADEMO which hits so many edge cases - VDP timing, modes, sprite handling, etc. 

 

Additional VDP stress testers are Pole Position (timing is tight - sometimes the game will glitch/freeze while the starting banner scrolls across the screen) and Popeye where the sea-hag throws bottles and will leave visible graphical artifacts on screen if you don't have the VDP prefetch just right.  Skyway needs the 5th sprite stuff to work properly. @Asmusr has a demo of 48 sprites on a screen (birds going left-to-right-to-left) that is really worth trying but I forget the name.

 

For SAMS, I use the AMSTEST4 and @jedimatt42's Expanded Memory Test - as well as Dungeons of Asgard (needs 128K SAMS) and Realms of Antiquity (well worth the $20 and despite saying 1MB SAMS, it works fine on 512K SAMS).

 

For bank switching, the Dragon's Lair Demo at 8MB is solid - though really anything that hits the banks works (Donkey Kong is a simple C/D game with just one bank but it hits HARD in terms of numerous switches).

 

Some other isolated cases...

 

Slymoids is one of the few carts utilizing the CPU IDLE handling - my emulator froze on that one for some time.

 

Eric in Monsterland requires that you scan and latch sprite collisions more than once per frame.

 

Miner 2049er requires that the 5S sprite number act like a counter when not latched (or collision detection won’t work). 

 

Any of the MBX games (I tend to use Bigfoot because, well, it's awesome) for the 1K of MBX RAM and odd banking.

 

Lasso will hang if you don't handle the Speech module correctly (at least you need to make it think it exists).

 

Congo Bongo and Buck Rogers in original C/D form require RAM mirrors in >8000 area to work (Congo Bongo won't crash until the 2nd stage).

 

Borzork and Mission Destruct both hit the sound chip with occasional 16-bit writes that caused me some trouble until recently (audio squealing).

 

I tend to prefer the original dumps of the carts rather than anything that has been doctored to run on the FinalGROM. Nothing against the FG - stunning bit of tech... but sometimes in the conversion things get moved/patched and original troublesome spots might not show.
 

I'm sure there are more... I've now forgotten more than I remember on all the troublesome carts.

 

Dave

  • Like 7
Link to comment
Share on other sites

I totally forgot the CPU Test!

You're killing me, @PeteE!

 

I was clean on your CPU test until this version.

 

image.png.bad2f10f5415f7c97a20b2f67b06471f.png

 

To save me some reading... what is the right order? I guess it's the order I'm not doing it... :D

 

 

Edit: found this comment I left for myself in the code:

 

image.thumb.png.5c81c3cf685f41eba8d5e43b04d7505e.png

 

I think we've answered the question about what this will cause :)

  • Like 1
  • Haha 2
Link to comment
Share on other sites

5 hours ago, PeteE said:

Here's my torture test, updated yesterday to catch the post-increment cases recently discussed in the assembly thread:

 

 

cputest.rpk 2.47 kB · 6 downloads cputestc.bin 6.81 kB · 6 downloads

Thank you so much for this!  It found some stupid status flag mistakes for ABS, S, and SRA in my emulator.  I managed to get the MOV *R0+,*R0+ correct.

  • Like 3
Link to comment
Share on other sites

6 hours ago, wavemotion said:

For me, the acid test has been the MEGADEMO which hits so many edge cases - VDP timing, modes, sprite handling, etc. 

 

Additional VDP stress testers are Pole Position (timing is tight - sometimes the game will glitch/freeze while the starting banner scrolls across the screen) and Popeye where the sea-hag throws bottles and will leave visible graphical artifacts on screen if you don't have the VDP prefetch just right.  Skyway needs the 5th sprite stuff to work properly. @Asmusr has a demo of 48 sprites on a screen (birds going left-to-right-to-left) that is really worth trying but I forget the name.

 

For SAMS, I use the AMSTEST4 and @jedimatt42's Expanded Memory Test - as well as Dungeons of Asgard (needs 128K SAMS) and Realms of Antiquity (well worth the $20 and despite saying 1MB SAMS, it works fine on 512K SAMS).

 

For bank switching, the Dragon's Lair Demo at 8MB is solid - though really anything that hits the banks works (Donkey Kong is a simple C/D game with just one bank but it hits HARD in terms of numerous switches).

 

Some other isolated cases...

 

Slymoids is one of the few carts utilizing the CPU IDLE handling - my emulator froze on that one for some time.

 

Eric in Monsterland requires that you scan for collisions more than once per frame.

 

Any of the MBX games (I tend to use Bigfoot because, well, it's awesome) for the 1K of MBX RAM and odd banking.

 

Lasso will hang if you don't handle the Speech module correctly (at least you need to make it think it exists).

 

Congo Bongo and Buck Rogers in original C/D form require RAM mirrors in >8000 area to work (Congo Bongo won't crash until the 2nd stage).

 

Borzork and Mission Destruct both hit the sound chip with occasional 16-bit writes that caused me some trouble until recently (audio squealing).

 

I tend to prefer the original dumps of the carts rather than anything that has been doctored to run on the FinalGROM. Nothing against the FG - stunning bit of tech... but sometimes in the conversion things get moved/patched and original troublesome spots might not show.
 

I'm sure there are more... I've now forgotten more than I remember on all the troublesome carts.

 

Dave

Thanks - I'll need to try all of these out.  I already saw the Popeye issue and now have it fixed thanks to your pointer as to what was causing it.  I'm doing the >8000 mirroring and partial address line decoding, so those should be good.  I haven't gotten around to implementing sound, speech, or SAMS yet.

 

I'm curious about what you mean by "Eric in Monsterland requires that you scan for collisions more than once per frame."  My rendering approach is that I have two back buffers - one for the screen bitmap, and one for the sprite bitmap.  Both bitmaps start out as all transparent pixels.  I render the screen buffer based on the graphics mode and tables.  Then I do a pass on the sprite attributes to mark which sprites exist on which scan lines.  Then I render the sprites by scan line from top to bottom onto the sprite bitmap, starting with the 4th lowest sprite number on that line to the highest number - whenever I see a write to a pixel where there isn't transparency, I set COINC, and the first time I see 5 sprites on a scan line I set the 5th sprite flag and set the 5th sprite number.  If I don't see 5 sprites on any lines in the frame, I set a random 5th sprite number, since I saw the thread on the Miner 2049er bug that looks at the wrong bit for COINC.  Then I blit the screen bitmap onto the background color, and blit the sprite bitmap on top of it.  To cut down on work, I only re-render those buffers if there have been VDP writes to any registers or to any address ranges that matter for whatever screen mode I'm in based on the table ranges.  So what does scanning for collisions more than once per frame mean?

 

I've got what I assume is some sort of timing issue with Parsec - the enemy ships are flying down too low when they first appear and the ones that come from behind are wrapping all the way around off the right and back to the left again when they come out.  I also see the explosion that appears when I hit a ship to be shifted to the left of where the ship was by a good amount.

 

  • Like 2
Link to comment
Share on other sites

1 hour ago, webdeck said:

I'm curious about what you mean by "Eric in Monsterland requires that you scan for collisions more than once per frame.

It sounds like you check for sprite collisions on each scanline - you'll be fine. To gain speed on my emulator for the DS handheld, I was only scanning for collisions of sprites at the end of the line. 99% of all games only scan for collisions at the end of a frame - true also for Coleco and thousands of MSX games. But Eric in Monsterland and the Megademo poll the collision bits during the frame - and specifically EiM will fail to detect collisions most of the time if you don't check and latch more frequently.

 

I'd love to switch to just scanning for collisions as the sprites are laid down - but it might be just a bit too much precious CPU time in my world.

 

No clues on Parsec... didn't run into that in my wayward travels.

Link to comment
Share on other sites

7 minutes ago, wavemotion said:

It sounds like you check for sprite collisions on each scanline - you'll be fine. To gain speed on my emulator for the DS handheld, I was only scanning for collisions of sprites at the end of the line. 99% of all games only scan for collisions at the end of a frame - true also for Coleco and thousands of MSX games. But Eric in Monsterland and the Megademo poll the collision bits during the frame - and specifically EiM will fail to detect collisions most of the time if you don't check more frequently.

 

I'd love to switch to just scanning for collisions as the sprites are laid down - but it might be just a bit too much precious CPU time in my world.

 

No clues on Parsec... didn't run into that in my wayward travels.

I will probably have issues now that I think about it.  I have a separate thread that is doing the rendering every 1/60th of a second, and that thread renders at full speed, so I may need to slow it down to whatever rate the VDP actually renders scan lines at.

  • Like 1
Link to comment
Share on other sites

17 hours ago, webdeck said:

I will probably have issues now that I think about it.  I have a separate thread that is doing the rendering every 1/60th of a second, and that thread renders at full speed, so I may need to slow it down to whatever rate the VDP actually renders scan lines at.

What (most) other emulators do, is to draw one scan line, then run the CPU for the corresponding number of clock cycles, then draw the next scan line, and so on. But if you could get the threads to synchronize, I guess that would be a more realistic, and maybe faster, emulation.

Edited by Asmusr
Link to comment
Share on other sites

1 hour ago, khanivore said:

Is this good?  I'm guessing not ...

image.png.92bfb32c14a8b1141969b2a2d0e2b83c.png

I had some of that very early on in my emulation testing with Pete's CPU test.

He once explained what the columns were... this is what I have in my scratch-pad notes that must have come from Pete himself:

For the first 24 failures, a line is printed containing: the instruction name, the first and second input, the result, the expected result, then the status flags, and finally the expected status flags. The first status flag byte is the result of the instruction after only EQ is set, and the second byte is the result after LGT AGT C OV OP are set. Instructions ending in I have the inputs swapped. Shift instructions ending in zero use the R0 register for the shift amount, otherwise are shifted by 1.

It's failing on Add - your results look good but your status flags were not as-expected. if he's going alphabetically, you've got a hill to climb :D

 

  • Sad 1
Link to comment
Share on other sites

1 hour ago, khanivore said:

Looks like the parity bit - Yeah I never bothered implementing that one

FYI the tester uses an AB instruction to set the flags to a known value before testing each instruction twice:

 

       LI R2,>A000
       AB R2,R2   ; set status LGT AGT C OV P
and
       CLR R2
       AB R2,R2   ; set status EQ

 

After each instruction, the status flags are compared to the expected flags.  By using two sets of flags, we can determine if the instruction only modifies the flags that are intended.

 

Hopefully, once you get the parity check added to the byte-variant instructions, most tests should start passing.

  • Like 4
Link to comment
Share on other sites

7 hours ago, Asmusr said:

What (most) other emulators do, is to draw one scan line, then run the CPU for the corresponding number of clock cycles, then draw the next scan line, and so on. But if you could get the threads to synchronize, I guess that would be a more realistic, and maybe faster, emulation.

Could someone point me to what the proper timing is to use for the VDP drawing?  I've been looking for it, but I can't find it.

Link to comment
Share on other sites

TMS9918 (vdp).pdf

 

Page 3.8 has the timing in pixel clocks and lines, which is what the VDP uses internally. You can find the other timing nearby. Note the "approximately". Real hardware is allowed to be off by 0.1% based on the input clock (page 5-4).

 

The concept of synchronizing VDP to CPU per scanline is probably the best approach for a current emulator, trading off performance for accuracy. The CPU can't really synchronize to the VDP too much tighter than that anyway. Every few scanlines seems to generally work for the DS emulator too, which is fair - it takes the CPU more than a scanline to react to a scanline detection anyway.

 

 

 

  • Like 3
Link to comment
Share on other sites

On 2/22/2024 at 4:04 PM, webdeck said:

I've got what I assume is some sort of timing issue with Parsec - the enemy ships are flying down too low when they first appear and the ones that come from behind are wrapping all the way around off the right and back to the left again when they come out.  I also see the explosion that appears when I hit a ship to be shifted to the left of where the ship was by a good amount.

 

Ok, the explosion appearing too far to the left was a silly early clock bit mistake in sprite rendering (was looking at the wrong bit.)  As for the Parsec timing issues, it seems to be related to instruction timing - I need to check my math on instruction times because it seems I'm running a bit too fast.

  • Like 1
Link to comment
Share on other sites

Yep, instruction timing.  I was trying to be super-accurate by sleeping after every instruction, but the sleep resolution isn't granular enough for that, and despite my trying to compensate, I was running a bit too fast.  Now I'm accumulating the sleep amount after each instruction and only sleeping after it gets large enough to warrant a sleep call (still fine tuning what that number is), and that seems to be working better.

  • Like 1
Link to comment
Share on other sites

Any wake up on a multi user OS is not going to happen at a precise time unfortunately unless you are running on an isolated CPU core.  What I did was create a recurring timerfd and do a blocking read on the socket to synchronise.  At least that averages out at the right rate.  I didn't find any VDP timing issues but when it came to cassette load and save I had to jump through a few hoops.

  • Like 1
Link to comment
Share on other sites

On 2/23/2024 at 6:48 PM, Tursi said:

TMS9918 (vdp).pdf 5.61 MB · 3 downloads

 

Page 3.8 has the timing in pixel clocks and lines, which is what the VDP uses internally. You can find the other timing nearby. Note the "approximately". Real hardware is allowed to be off by 0.1% based on the input clock (page 5-4).

 

The concept of synchronizing VDP to CPU per scanline is probably the best approach for a current emulator, trading off performance for accuracy. The CPU can't really synchronize to the VDP too much tighter than that anyway. Every few scanlines seems to generally work for the DS emulator too, which is fair - it takes the CPU more than a scanline to react to a scanline detection anyway.

 

 

 

Thanks - I missed this manual - I was using a different TMS9918A reference.

  • Like 1
Link to comment
Share on other sites

  • 4 months later...

Okay, so after a time away from this, I picked it back up again.  I re-did the VDP emulation so that it draws by scan line with appropriate timing and gets the edge cases of 5th sprite correct.  The megademo now works properly - huge milestone!  I also got sound working.

 

I gave up on trying to sleep with precision on a modern OS.  I'm just running busy loops, which I hate, but it is way more accurate.

 

I also misinterpreted this sentence in the 9918A docs on how the VDP Interrupt works:

Quote

Note that the status register needs to be read frame by frame in order to clear the interrupt and receive the new interrupt of the next frame.

I thought that meant that if you don't read the status register, it won't generate another interrupt.  Instead, it means that if you don't read the status register, it will keep retriggering the interrupt.  In other words, CRU bit 2 goes to 0 whenever the F status bit is set (thereby triggering an interrupt), and goes to 1 whenever the status register is read (clearing the F status bit.)

 

The megademo runs slower than the videos I see on YouTube of it, so I need to check my instruction timing as I must be off somewhere.  The "Multiplane" part of the demo runs noticeably slower, so something is wrong there.

 

One annoying thing with Swift is the huge performance difference between a debug build and a release build.  Changing the VDP to draw line by line made the debug build unusable now because the VDP emulation can't keep up.  The release build is orders of magnitude faster, but is much harder to debug when something goes wrong.

 

Speaking of something going wrong, I'm going through testing a bunch of different modules.  There are two atarisoft modules I am having issues with.  Moon Partol crashes right after the intro music at the start of the first level.  It crashes at >628C trying to execute an invalid opcode (>0003).  The code right before that is a B *R11, so clearly that's a bad address to branch to.   The code before that did MOV *R11, R3, so it looked like it was pulling data after the BL, but it never updated R11.  I even tried patching it to be MOV *R11+ instead, but then it just crashed a few seconds later in a different spot, so something else is wrong somewhere with the emulator.  I compared the roms from a couple different sources and they are all the same, so it's not a corrupted rom.

 

The other Atari game that gave me issues is Jungle Hunt.  The swinging vines are missing.

 

Has anyone seen either of these problems and can point me in the right direction?

 

Thanks!

Screenshot 2024-07-06 at 4.20.13 PM.png

Link to comment
Share on other sites

14 minutes ago, webdeck said:

Speaking of something going wrong, I'm going through testing a bunch of different modules.  There are two atarisoft modules I am having issues with.  Moon Partol crashes right after the intro music at the start of the first level.  It crashes at >628C trying to execute an invalid opcode (>0003).  The code right before that is a B *R11, so clearly that's a bad address to branch to.   The code before that did MOV *R11, R3, so it looked like it was pulling data after the BL, but it never updated R11.  I even tried patching it to be MOV *R11+ instead, but then it just crashed a few seconds later in a different spot, so something else is wrong somewhere with the emulator.  I compared the roms from a couple different sources and they are all the same, so it's not a corrupted rom.

The debugger in Classic99 logs many invalid opcodes for >0003 @>628C so you should just ignore it like it's a NOP and keep executing.

Link to comment
Share on other sites

30 minutes ago, webdeck said:

I also misinterpreted this sentence in the 9918A docs on how the VDP Interrupt works:

I thought that meant that if you don't read the status register, it won't generate another interrupt.  Instead, it means that if you don't read the status register, it will keep retriggering the interrupt.  In other words, CRU bit 2 goes to 0 whenever the F status bit is set (thereby triggering an interrupt), and goes to 1 whenever the status register is read (clearing the F status bit.)

Yes, the interrupt for the 9900 is a level-based signal, and not an edge-based signal. This is also the reason why you get an interrupt as soon as LIMI 2 is executed: The interrupt line becomes active at some time possibly during LIMI 0, and then, when a LIMI 2 occurs, it triggers the interrupt handling.

 

The 9995 uses latches for incoming interrupts to allow the same technique with non-buffered interrupt sources.

  • Like 3
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...