2016-08-17 12:31:22 +00:00
|
|
|
#include <ms/ms.hpp>
|
|
|
|
|
|
|
|
namespace MasterSystem {
|
|
|
|
|
|
|
|
VDP vdp;
|
Update to v101r24 release.
byuu says:
Changelog:
- SMS: extended bus mapping of in/out ports: now decoding them fully
inside ms/bus
- SMS: moved Z80 disassembly code from processor/z80 to ms/cpu
(cosmetic)
- SMS: hooked up non-functional silent PSG sample generation, so I can
cap the framerate at 60fps
- SMS: hooked up the VDP main loop: 684 clocks/scanline, 262
scanlines/frame (no PAL support yet)
- SMS: emulated the VDP Vcounter and Hcounter polling ... hopefully
it's right, as it's very bizarre
- SMS: emulated VDP in/out ports (data read, data write, status read,
control write, register write)
- SMS: decoding and caching all VDP register flags (variable names
will probably change)
- nall: \#undef IN on Windows port (prevent compilation warning on
processor/z80)
Watching Sonic the Hedgehog, I can definitely see some VDP register
writes going through, which is a good sign.
Probably the big thing that's needed before I can get enough into the
VDP to start showing graphics is interrupt support. And interrupts are
never fun to figure out :/
What really sucks on this front is I'm flying blind on the Z80 CPU core.
Without a working VDP, I can't run any Z80 test ROMs to look for CPU
bugs. And the CPU is certainly too buggy still to run said test ROM
anyway. I can't find any SMS emulators with trace logging from reset.
Such logs vastly accelerate tracking down CPU logic bugs, so without
them, it's going to take a lot longer.
2016-12-17 11:31:34 +00:00
|
|
|
#include "io.cpp"
|
2016-12-30 07:24:35 +00:00
|
|
|
#include "background.cpp"
|
|
|
|
#include "sprite.cpp"
|
Update to v102r10 release.
byuu says:
Changelog:
- removed Emulator::Interface::Capabilities¹
- MS: improved the PSG emulation a bit
- MS: added cheat code support
- MS: added save state support²
- MD: emulated the PSG³
¹: there's really no point to it anymore. I intend to add cheat codes
to the GBA core, as well as both cheat codes and save states to the Mega
Drive core. I no longer intend to emulate any new systems, so these
values will always be true. Further, the GUI doesn't respond to these
values to disable those features anymore ever since the hiro rewrite, so
they're double useless.
²: right now, the Z80 core is using a pointer for HL-\>(IX,IY)
overrides. But I can't reliably serialize pointers, so I need to convert
the Z80 core to use an integer here. The save states still appear to
work fine, but there's the potential for an instruction to execute
incorrectly if you're incredibly unlucky, so this needs to be fixed as
soon as possible. Further, I still need a way to serialize
array<T, Size> objects, and I should also add nall::Boolean
serialization support.
³: I don't have a system in place to share identical sound chips. But
this chip is so incredibly simple that it's not really much trouble to
duplicate it. Further, I can strip out the stereo sound support code
from the Game Gear portion, so it's even tinier.
Note that the Mega Drive only just barely uses the PSG. Not at all in
Altered Beast, and only for a tiny part of the BGM music on Sonic 1,
plus his jump sound effect.
2017-02-22 21:25:01 +00:00
|
|
|
#include "serialization.cpp"
|
2016-08-17 12:31:22 +00:00
|
|
|
|
|
|
|
auto VDP::Enter() -> void {
|
|
|
|
while(true) scheduler.synchronize(), vdp.main();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto VDP::main() -> void {
|
2016-12-26 12:09:56 +00:00
|
|
|
if(io.vcounter <= vlines()) {
|
|
|
|
if(io.lcounter-- == 0) {
|
|
|
|
io.lcounter = io.lineCounter;
|
|
|
|
io.intLine = 1;
|
2016-08-19 14:11:26 +00:00
|
|
|
}
|
2016-12-30 07:24:35 +00:00
|
|
|
} else {
|
|
|
|
io.lcounter = io.lineCounter;
|
2016-08-19 14:11:26 +00:00
|
|
|
}
|
2016-12-26 12:09:56 +00:00
|
|
|
|
|
|
|
if(io.vcounter == vlines() + 1) {
|
|
|
|
io.intFrame = 1;
|
|
|
|
}
|
|
|
|
|
2016-12-30 07:24:35 +00:00
|
|
|
background.scanline();
|
|
|
|
sprite.scanline();
|
|
|
|
|
|
|
|
//684 clocks/scanline
|
2017-01-13 01:15:45 +00:00
|
|
|
uint y = io.vcounter;
|
2017-01-13 23:59:38 +00:00
|
|
|
if(y < vlines()) {
|
|
|
|
uint32* screen = buffer + (24 + y) * 256;
|
|
|
|
for(uint x : range(256)) {
|
|
|
|
background.run();
|
|
|
|
sprite.run();
|
|
|
|
step(2);
|
|
|
|
|
2017-08-18 12:48:29 +00:00
|
|
|
uint12 color = palette(16 | io.backdropColor);
|
|
|
|
if(!io.leftClip || x >= 8) {
|
|
|
|
if(background.output.priority || !sprite.output.color) {
|
|
|
|
color = palette(background.output.palette << 4 | background.output.color);
|
|
|
|
} else if(sprite.output.color) {
|
|
|
|
color = palette(16 | sprite.output.color);
|
|
|
|
}
|
2017-01-13 23:59:38 +00:00
|
|
|
}
|
|
|
|
if(!io.displayEnable) color = 0;
|
|
|
|
*screen++ = color;
|
2016-12-30 07:24:35 +00:00
|
|
|
}
|
2017-01-13 23:59:38 +00:00
|
|
|
} else {
|
|
|
|
//Vblank
|
|
|
|
step(512);
|
2016-12-26 12:09:56 +00:00
|
|
|
}
|
2016-12-30 07:24:35 +00:00
|
|
|
step(172);
|
2016-12-26 12:09:56 +00:00
|
|
|
|
|
|
|
if(io.vcounter == 240) scheduler.exit(Scheduler::Event::Frame);
|
2016-08-17 12:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto VDP::step(uint clocks) -> void {
|
2016-12-26 12:09:56 +00:00
|
|
|
while(clocks--) {
|
|
|
|
if(++io.hcounter == 684) {
|
|
|
|
io.hcounter = 0;
|
Update to v102r28 release.
byuu says:
Changelog:
- higan: `Emulator::<Platform::load>()` now returns a struct containing
both a path ID and a string option
- higan: `Emulator::<Platform::load>()` now takes an optional final
argument of string options
- fc: added PAL emulation (finally, only took six years)
- md: added PAL emulation
- md: fixed address parameter to `VDP::Sprite::write()`; fixes missing
sprites in Super Street Fighter II
- md: emulated HIRQ counter; fixes many games
- Super Street Fighter II - status bar
- Altered Beast - status bar
- Sonic the Hedgehog - Labyrinth Zone - water effect
- etc.
- ms: added PAL emulation
- sfc: added the ability to override the default region auto-detection
- sfc: removed "system.region" override setting from `Super Famicom.sys`
- tomoko: added options list to game folder load dialog window
- tomoko: added the ability to specify game folder load options on the
command-line
So, basically ... Sega forced a change with the way region detection
works. You end up with games that can run on multiple regions, and the
content changes accordingly. Bare Knuckle in NTSC-J mode will become
Streets of Rage in NTSC-U mode. Some games can even run in both NTSC and
PAL mode.
In my view, there should be a separate ROM for each region a game was
released in, even if the ROM content were identical. But unfortunately
that's not how things were done by anyone else.
So to support this, the higan load dialog now has a drop-down at the
bottom-right, where you can choose the region to load games from. On the
SNES, it defaults to "Auto", which will pull the region setting from the
manifest, or fall back on NTSC. On the Mega Drive ... unfortunately, I
can't auto-detect the region from the ROM header. $1f0 is supposed to
contain a string like "JUE", but instead you get games like Maui Mallard
that put an "A" there, and other such nonsense. Sega was far more lax
than Nintendo with the ROM header validity. So for now at least, you
have to manually select your region every time you play a Mega Drive
game, thus you have "NTSC-J", "NTSC-U", and "PAL". The same goes for the
Master System for the same reason, but there's only "NTSC" and "PAL"
here. I'm not sure if games have a way to detect domestic vs
international consoles.
And for now ... the Famicom is the same as well, with no auto-detection.
I'd sincerely hope iNES has a header bit for the region, but I didn't
bother with updating icarus to support that yet.
The way to pass these parameters on the command-line is to prefix the
game path with "option:", so for example:
higan "PAL:/path/to/Sonic the Hedgehog (USA, Europe).md"
If you don't provide a prefix, it uses the default (NTSC-J, NTSC, or
Auto.) Obviously, it's not possible to pass parameters with
drag-and-drop, so you will always get the default option in said case.
2017-06-20 12:34:50 +00:00
|
|
|
if(++io.vcounter == (Region::NTSC() ? 262 : 312)) {
|
2016-12-26 12:09:56 +00:00
|
|
|
io.vcounter = 0;
|
|
|
|
}
|
Update to v101r24 release.
byuu says:
Changelog:
- SMS: extended bus mapping of in/out ports: now decoding them fully
inside ms/bus
- SMS: moved Z80 disassembly code from processor/z80 to ms/cpu
(cosmetic)
- SMS: hooked up non-functional silent PSG sample generation, so I can
cap the framerate at 60fps
- SMS: hooked up the VDP main loop: 684 clocks/scanline, 262
scanlines/frame (no PAL support yet)
- SMS: emulated the VDP Vcounter and Hcounter polling ... hopefully
it's right, as it's very bizarre
- SMS: emulated VDP in/out ports (data read, data write, status read,
control write, register write)
- SMS: decoding and caching all VDP register flags (variable names
will probably change)
- nall: \#undef IN on Windows port (prevent compilation warning on
processor/z80)
Watching Sonic the Hedgehog, I can definitely see some VDP register
writes going through, which is a good sign.
Probably the big thing that's needed before I can get enough into the
VDP to start showing graphics is interrupt support. And interrupts are
never fun to figure out :/
What really sucks on this front is I'm flying blind on the Z80 CPU core.
Without a working VDP, I can't run any Z80 test ROMs to look for CPU
bugs. And the CPU is certainly too buggy still to run said test ROM
anyway. I can't find any SMS emulators with trace logging from reset.
Such logs vastly accelerate tracking down CPU logic bugs, so without
them, it's going to take a lot longer.
2016-12-17 11:31:34 +00:00
|
|
|
}
|
|
|
|
|
2016-12-26 12:09:56 +00:00
|
|
|
cpu.setINT((io.lineInterrupts && io.intLine) || (io.frameInterrupts && io.intFrame));
|
|
|
|
Thread::step(1);
|
|
|
|
synchronize(cpu);
|
|
|
|
}
|
2016-08-19 14:11:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto VDP::refresh() -> void {
|
2017-02-21 11:07:33 +00:00
|
|
|
if(Model::MasterSystem()) {
|
2017-01-13 23:59:38 +00:00
|
|
|
//center the video output vertically in the viewport
|
|
|
|
uint32* screen = buffer;
|
|
|
|
if(vlines() == 224) screen += 16 * 256;
|
|
|
|
if(vlines() == 240) screen += 24 * 256;
|
|
|
|
|
|
|
|
Emulator::video.refresh(screen, 256 * sizeof(uint32), 256, 240);
|
2017-01-13 01:15:45 +00:00
|
|
|
}
|
|
|
|
|
2017-02-21 11:07:33 +00:00
|
|
|
if(Model::GameGear()) {
|
2017-01-13 23:59:38 +00:00
|
|
|
Emulator::video.refresh(buffer + 48 * 256 + 48, 256 * sizeof(uint32), 160, 144);
|
2017-01-13 01:15:45 +00:00
|
|
|
}
|
2016-08-19 14:11:26 +00:00
|
|
|
}
|
|
|
|
|
2016-12-26 12:09:56 +00:00
|
|
|
auto VDP::vlines() -> uint {
|
|
|
|
if(io.lines240) return 240;
|
|
|
|
if(io.lines224) return 224;
|
|
|
|
return 192;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto VDP::vblank() -> bool {
|
|
|
|
return io.vcounter >= vlines();
|
|
|
|
}
|
|
|
|
|
2016-08-19 14:11:26 +00:00
|
|
|
auto VDP::power() -> void {
|
2017-01-13 01:15:45 +00:00
|
|
|
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
|
|
|
|
2017-01-13 23:59:38 +00:00
|
|
|
memory::fill(&buffer, sizeof(buffer));
|
2017-01-13 01:15:45 +00:00
|
|
|
memory::fill(&io, sizeof(IO));
|
|
|
|
|
2016-12-30 07:24:35 +00:00
|
|
|
background.power();
|
|
|
|
sprite.power();
|
2016-08-19 14:11:26 +00:00
|
|
|
}
|
|
|
|
|
2017-01-13 01:15:45 +00:00
|
|
|
auto VDP::palette(uint5 index) -> uint12 {
|
2017-02-21 11:07:33 +00:00
|
|
|
if(Model::MasterSystem()) {
|
2017-01-13 01:15:45 +00:00
|
|
|
return cram[index];
|
|
|
|
}
|
Update to v101r24 release.
byuu says:
Changelog:
- SMS: extended bus mapping of in/out ports: now decoding them fully
inside ms/bus
- SMS: moved Z80 disassembly code from processor/z80 to ms/cpu
(cosmetic)
- SMS: hooked up non-functional silent PSG sample generation, so I can
cap the framerate at 60fps
- SMS: hooked up the VDP main loop: 684 clocks/scanline, 262
scanlines/frame (no PAL support yet)
- SMS: emulated the VDP Vcounter and Hcounter polling ... hopefully
it's right, as it's very bizarre
- SMS: emulated VDP in/out ports (data read, data write, status read,
control write, register write)
- SMS: decoding and caching all VDP register flags (variable names
will probably change)
- nall: \#undef IN on Windows port (prevent compilation warning on
processor/z80)
Watching Sonic the Hedgehog, I can definitely see some VDP register
writes going through, which is a good sign.
Probably the big thing that's needed before I can get enough into the
VDP to start showing graphics is interrupt support. And interrupts are
never fun to figure out :/
What really sucks on this front is I'm flying blind on the Z80 CPU core.
Without a working VDP, I can't run any Z80 test ROMs to look for CPU
bugs. And the CPU is certainly too buggy still to run said test ROM
anyway. I can't find any SMS emulators with trace logging from reset.
Such logs vastly accelerate tracking down CPU logic bugs, so without
them, it's going to take a lot longer.
2016-12-17 11:31:34 +00:00
|
|
|
|
2017-02-21 11:07:33 +00:00
|
|
|
if(Model::GameGear()) {
|
2017-01-13 01:15:45 +00:00
|
|
|
return cram[index * 2 + 0] << 0 | cram[index * 2 + 1] << 8;
|
|
|
|
}
|
2016-12-30 07:24:35 +00:00
|
|
|
|
2017-01-13 01:15:45 +00:00
|
|
|
return 0;
|
2016-08-17 12:31:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|