ColecoVision Emulator
macca
Posts: 780
Hello,
I have started to write a ColecoVision console emulator for the P2.
It uses my TMS9918 emulator, with the Z80 and SN76489 emulators made by @Wuerfel_21 and a PS/2 keyboard driver to emulate a single controller.
It is still has some bugs and very few games works without problems (some don't even go beyond the startup screen) but almost all games I have tested so fare are working. If someone wants to help...
Here is a short video of the emulator running H.E.R.O. https://youtu.be/le7NrrUQLC0.
Attached the source code. As usual with these emulators, I think the ROMs can't be included, so you need to add the BIOS and the cartridge ROMs to make it work.
Hope you enjoy!
Comments
Wow, there's another one! And it uses my crusty Z80 core!
Will have to hack this up later for USB keyboard.
Some notes from a cursory glance:
- Source code is horrible to navigate, please do the thing where the line starting a new section contains a comment describing it. Though it is somewhat of a PropTool-specific thing (though I just asked these to be displayed in the VSC extension, for I realized that the file outline is useless for CON/DAT-only files)
- You don't stop the game code from writing over its ROM - that may explain some of the issues. Relatedly, I don't think that the entire memory space is filled with unique ROM/RAM - you need to mirror the unused space, usually (not familiar with ColecoVision memory map though)
- You set the sample rate for SNECog too low - the enormous sample rate that's set by default is there for a reason. It makes it sound not-terrible. Note that any rate is okay with this one, it doesn't need to be related to 44.1kHz.
Illustrating the navigation issue, your code in summary view:
For comparsion, megayume_lower.spin2:
@macca Nice work!
I was wondering why there are comments near the section keywords, as it is not my usual style. I never used that feature, and actually I'm using my own editor with its own outline view. It will be a good addition however, will think about it.
Yes it is one of the (many) things I need to look at. The memory map is very simple: 8k bios rom at 0000-1FFF, 1k ram at 6000-7FFF (mirrored 8 times) and from 8000 onward the cartridge rom, not sure if cartridges less thank 32k are mirrored. 2000-5FFF is for the expansion port but I think it is used by the Adam expansion only. See here for an overview CV-Tech.txt
I need to reorganize the code a bit to implement the additional checks because it starts to fill the cog space.
I'll set it back to the original value, but from my point of view it doesn't make much difference.
Small cartridges should probably be mirrored, yes.
And yes, the Z80 cog is perpetually short on space (though I'd have assumed ripping out the ROM access code to free up way more than ever needed) . Relatedly, I'm not entirely sure that the block I/O instructions work as intended (since the megadrive's Z80 doesn't have any port IO connected). They also happen to be part of a terrible tangle of code, so, uh, good luck.
Ideally you'd set it to something that is CLKFREQ/(256*N), because then you can use the PWM dithered DAC mode (not that that is terribly important for a square wave chip, but posterity!)
Mirroring the ram partially fixed a game (Pitfall) but still hangs, other games still doesn't work. Mirroring the cartridge doesn't seems to have any effect.
I found a test cartridge that hangs at the sound test (outputs a note and hangs) and managed to produce a disassembly listing.
If the listing is correct, there are two things to check, first OTIR is used to send block of data to the sound chip, and the BIT instructions are used to check the frame blanking. OTIR seems to work, at least one time because it produces a note. Are the BIT/SET/RES instructions tested working ?
I think I'll write a test suite for the instructions...
All the instructions are tested, for there is a test suite I ran. But the block I/O, I think the undocumented flags aren't entirely right and a test program obviously can't check that the values being transferred are actually right.
Ok, good. So far the source only contains LDIR and OTIR instructions, not flags are checked so I'm not worried about that.
LDIR is used to write a ram test pattern and since the subsequent check doesn't fail I guess the data are transfered correctly, same with OTIR otherwise the sound won't bee working.
Need to dig deeper.
Are some extended instructions not implemented ? The source I'm looking at doesn't seem to use undocumented instructions.
All the undocumented instructions are there, no problem.
If you log instructions with DEBUG you may be able to see it going off the rails in real-time. Though this is arguably easier with the 68000, since that ususally runs into one of its many trap/error conditions very quickly when it goes ham.
Well, it turned out that is the vsync interrupt logic not working correctly, or the video registers update... don't know. Sometimes it stops triggering the interrupts and the game freezes. The weird thing is that the interrupt enable flag in the vdp register is reset for no apparent reasons. Maybe a wild write somewhere...
Well, maybe your PSG write code is having an issue? Looks fine to me though (not sure if it actually does the right stuff, but it doesn't write memory). Though you're returning with plain RET instead of RET WCZ. You should do the latter in all memory handlers, but I'm not sure if the Z80 core actually relies on this.
Speaking of,
you can do that in one op with GETNIB.
Also, in your read/write handlers, you do
zerox pa,#16
, which a) i'm not sure is actually needed (but it obviously doesn't hurt) b) is wrong, it should bezerox pa,#15
to limit to 16 bits c) you could dogetword pa,zk_ea,#0
insteadOf course if was the other flag, the vsync flag in the status byte that doesn't work as expected and needs investigation.
For now I'm ignoring it and generate an interrupt if enabled, I don't like it because it is not how it is supposed to work, but at least it enables almost all games.
There are still some quirks, the Final Test cartrige doesn't read the numeric keypad (but they works for other games), and Super Cobra seems it doesn't read the fire buttons (but are working with other games). Oh well..
Source updated.
Yep, just checked, you absolutely do need to use RET WCZ in all memory handlers, for otherwise, things like INC (HL) will subtly break. I/O port handlers I think are fine without, but IMO should restore flags, too, for consistency. So I guess you're fine on that front.
Yes, the Alpha2 source on the first post should have all ret wcz fixed.
Alpha 3 added to first post.
I have fixed the controller read issue I had with the Final Test cartridge and Super Cobra, now both detects the buttons correctly.
Changed how video interrupts are generated and handled, now seems to work as expected (or at least it doesn't randomly freeze the game).
Fixed some issues with the sprite handling due to a behaviour with 16x16 sprites that doesn't seems to be documented explicitly (there is a note on the datasheet but I can't see a specific description).
There are still some drawing issues with Pitfall (this game is driving me crazy!), with sprites appearing at random positions, tiles not well drawing, etc.
With Pitfall II Lost Caverns the character always "dies" when entering the third screen, I fear there is some issue with the Z80 emulator, maybe some instructions don't set the flags correctly.
Bump 'N' Jump doesn't go beyond the player / level selection.
Other games seems to work correctly so far.
I'm fairly certain the flags are correct (including undocumented flags), unless the instruction test missed something. There is some oddity with the XY flags for SCF/CCF, but that's unlikely to come up and differs between Z80 variants. The instruction test thinks the Z80 emulator is a NEC Z80, but I'm not sure it actually matches the behaviour of that particular variant. And as said, undocumented flags for block I/O are incorrect, despite best effort)
For what it's worth, I am not aware of any games that have Z80 issues on MegaYume (even modern homebrew with tricky sound drivers).
Except maybe Thunder Force IV, which has a weird tempo issue seemingly related to 68000 load (i.e. goes really slow during boss fights), but IDK where that's coming from (it's certainly not the Z80 being actually halted using BUSREQ, I tested for that. And the music timing is supposed to be determined by the YM2612's timers and those seem to work as intended, too)
And of course you are right!
Pitfall II uses the sprite collision flag and the status read code wasn't clearing it. AFAIK, this is the only game using the collision flag I tested so far.
At this point the lesson should be clear: never doubt Ada's code!
Thanks and sorry for the noise!
Source updated.
Ah, the good ol' collision flag. MegaYume doesn't even implement it (>.>) (remember, the SEGA VDP is a distant relative of the TMS9918, but I guess by 1989 the art of the hitbox had been discovered)
And no, you shall doubt my code, but doubt your own first.
New Alpha 5 source update.
The vsync interrupt was causing the Pitfall random draws, I have changed how interrupts are handled by the Z80 emulation (should be more similar to how the real Z80 detects them) and now seems fixed but still there are some issues that shows as temporary slowdowns with some games, I think that some interrupts are missing or are detected one frame later.
Also changed how the sprites are drawn, this allows to disable the 4 sprites per scanline limit that some emulators define as "disable sprite flicker".
All games I have tested are working, including Bump 'N' Jump (not sure what fixed this...) so I think we are near completion.
Best regards,
Marco
New Beta 1 source update.
Made some cleanup and added semaphores for critical shared hub locations, mainly the TMS9918 status and interrupt generation. I still see some stuttering in Donkey Kong, not sure about the cause, tried to monitor the interrupt routine running time and looks good (triggers at vsync and ends well before the frame complete) despite my logic analyzer is not very good. Probably it is something else.
Also added PAL and NTSC video drivers, selectable by changing the VIDEO constant value.
So far I haven't found any critical bug, all games are working, so the source is promoted as beta 1.
Best regards,
Marco
Package updated with some minor fixes and a version with an initial support for USB keyboards.
If @Wuerfel_21 is interested, I have stripped down the USB driver removing mouse support and reduced to the bare minimum needed for PASM-only use.
Hope to not have disrupted anything in the process.
Seems to work great. You even do the correct thing and scan the entire 6 keys instead of stopping at a zero (which was a bug in the original keyboard handling code, which I see you just threw out entirely).
USB Gamepad Implementation split to new thread here : https://forums.parallax.com/discussion/174541/usb-gamepad-implementation