Update to v099r13 release.
byuu says:
Changelog:
- GB core code cleanup completed
- GBA core code cleanup completed
- some more cleanup on missed processor/arm functions/variables
- fixed FC loading icarus bug
- "Load ROM File" icarus functionality restored
- minor code unification efforts all around (not perfect yet)
- MMIO->IO
- mmio.cpp->io.cpp
- read,write->readIO,writeIO
It's been a very long work in progress ... starting all the way back with
v094r09, but the major part of the higan code cleanup is now completed! Of
course, it's very important to note that this is only for the basic style:
- under_score functions and variables are now camelCase
- return-type function-name() are now auto function-name() -> return-type
- Natural<T>/Integer<T> replace (u)intT_n types where possible
- signed/unsigned are now int/uint
- most of the x==true,x==false tests changed to x,!x
A lot of spot improvements to consistency, simplicity and quality have
gone in along the way, of course. But we'll probably never fully finishing
beautifying every last line of code in the entire codebase. Still,
this is a really great start. Going forward, WIP diffs should start
being smaller and of higher quality once again.
I know the joke is, "until my coding style changes again", but ... this
was way too stressful, way too time consuming, and way too risky. I'm
too old and tired now for extreme upheavel like this again. The only
major change I'm slowly mulling over would be renaming the using
Natural<T>/Integer<T> = (u)intT; shorthand to something that isn't as
easily confused with the (u)int_t types ... but we'll see. I'll definitely
continue to change small things all the time, but for the larger picture,
I need to just accept the style I have and live with it.
2016-06-29 11:10:28 +00:00
|
|
|
auto ICD2::readIO(uint24 addr, uint8 data) -> uint8 {
|
2015-12-14 09:41:06 +00:00
|
|
|
addr &= 0x40ffff;
|
2011-01-08 09:58:41 +00:00
|
|
|
|
|
|
|
//LY counter
|
|
|
|
if(addr == 0x6000) {
|
2016-02-16 09:27:55 +00:00
|
|
|
uint y = min((uint8)143, GameBoy::ppu.status.ly);
|
2016-06-17 13:03:54 +00:00
|
|
|
return (y & ~7) | writeBank;
|
2011-01-08 09:58:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//command ready port
|
|
|
|
if(addr == 0x6002) {
|
2016-06-17 13:03:54 +00:00
|
|
|
data = packetSize > 0;
|
2011-01-08 09:58:41 +00:00
|
|
|
if(data) {
|
2015-11-14 00:52:51 +00:00
|
|
|
for(auto n : range(16)) r7000[n] = packet[0][n];
|
2016-06-17 13:03:54 +00:00
|
|
|
packetSize--;
|
|
|
|
for(auto n : range(packetSize)) packet[n] = packet[n + 1];
|
2011-01-08 09:58:41 +00:00
|
|
|
}
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
//ICD2 revision
|
|
|
|
if(addr == 0x600f) {
|
|
|
|
return 0x21;
|
|
|
|
}
|
|
|
|
|
|
|
|
//command port
|
2015-12-14 09:41:06 +00:00
|
|
|
if((addr & 0x40fff0) == 0x7000) {
|
2011-01-08 09:58:41 +00:00
|
|
|
return r7000[addr & 15];
|
|
|
|
}
|
|
|
|
|
|
|
|
//VRAM port
|
|
|
|
if(addr == 0x7800) {
|
2016-06-17 13:03:54 +00:00
|
|
|
data = output[readBank * 512 + readAddress];
|
|
|
|
readAddress = (readAddress + 1) & 511;
|
2011-01-08 09:58:41 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0x00;
|
|
|
|
}
|
|
|
|
|
Update to v099r13 release.
byuu says:
Changelog:
- GB core code cleanup completed
- GBA core code cleanup completed
- some more cleanup on missed processor/arm functions/variables
- fixed FC loading icarus bug
- "Load ROM File" icarus functionality restored
- minor code unification efforts all around (not perfect yet)
- MMIO->IO
- mmio.cpp->io.cpp
- read,write->readIO,writeIO
It's been a very long work in progress ... starting all the way back with
v094r09, but the major part of the higan code cleanup is now completed! Of
course, it's very important to note that this is only for the basic style:
- under_score functions and variables are now camelCase
- return-type function-name() are now auto function-name() -> return-type
- Natural<T>/Integer<T> replace (u)intT_n types where possible
- signed/unsigned are now int/uint
- most of the x==true,x==false tests changed to x,!x
A lot of spot improvements to consistency, simplicity and quality have
gone in along the way, of course. But we'll probably never fully finishing
beautifying every last line of code in the entire codebase. Still,
this is a really great start. Going forward, WIP diffs should start
being smaller and of higher quality once again.
I know the joke is, "until my coding style changes again", but ... this
was way too stressful, way too time consuming, and way too risky. I'm
too old and tired now for extreme upheavel like this again. The only
major change I'm slowly mulling over would be renaming the using
Natural<T>/Integer<T> = (u)intT; shorthand to something that isn't as
easily confused with the (u)int_t types ... but we'll see. I'll definitely
continue to change small things all the time, but for the larger picture,
I need to just accept the style I have and live with it.
2016-06-29 11:10:28 +00:00
|
|
|
auto ICD2::writeIO(uint24 addr, uint8 data) -> void {
|
2011-01-08 09:58:41 +00:00
|
|
|
addr &= 0xffff;
|
|
|
|
|
2011-05-08 13:46:37 +00:00
|
|
|
//VRAM port
|
|
|
|
if(addr == 0x6001) {
|
2016-06-17 13:03:54 +00:00
|
|
|
readBank = data & 3;
|
|
|
|
readAddress = 0;
|
2011-05-08 13:46:37 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-01-08 09:58:41 +00:00
|
|
|
//control port
|
|
|
|
//d7: 0 = halt, 1 = reset
|
|
|
|
//d5,d4: 0 = 1-player, 1 = 2-player, 2 = 4-player, 3 = ???
|
|
|
|
//d1,d0: 0 = frequency divider (clock rate adjust)
|
|
|
|
if(addr == 0x6003) {
|
|
|
|
if((r6003 & 0x80) == 0x00 && (data & 0x80) == 0x80) {
|
Update to v102r04 release.
byuu says:
Changelog:
- Super Game Boy support is functional once again
- new GameBoy::SuperGameBoyInterface class
- system.(dmg,cgb,sgb) is now Model::(Super)GameBoy(Color) ala the PC
Engine
- merged WonderSwanInterface, WonderSwanColorInterface shared
functions to WonderSwan::Interface
- merged GameBoyInterface, GameBoyColorInterface shared functions to
GameBoy::Interface
- Interface::unload() now calls Interface::save() for Master System,
Game Gear, Mega Drive, PC Engine, SuperGrafx
- PCE: emulated PCE-CD backup RAM; stored per-game as save.ram (2KiB
file)
- this means you can now save your progress in games like Neutopia
- the PCE-CD I/O registers like BRAM write protect are not
emulated yet
- PCE: IRQ sources now hold the IRQ line state, instead of the CPU
holding it
- this fixes most SuperGrafx games, which were fighting over the
VDC IRQ line previously
- PCE: CPU I/O $14xx should return the pending IRQ bits even if IRQs
are disabled
- PCE: VCE and the VDCs now synchronize to each other; fixes pixel
widths in all games
- PCE: greatly increased the accuracy of the VPC priority selection
code (windows may be buggy still)
- HuC6280: PLA, PLX, PLY should set Z, N flags; fixes many game bugs
[Jonas Quinn]
The big thing I wanted to do was enslave the VDC(s) to the VCE. But
unfortunately, I forgot about the asynchronous DMA channels that each
VDC supports, so this isn't going to be possible I'm afraid.
In the most demanding case, Daimakaimura in-game, we're looking at 85fps
on my Xeon E3 1276v3. So ... not great, and we don't even have sound
connected yet.
We are going to have to profile and optimize this code once sound
emulation and save states are in.
Basically, think of it like this: the VCE, VDC0, and VDC1 all have the
same overhead, scheduling wise (which is the bulk of the performance
loss) as the dot-renderer for the SNES core. So it's like there's three
bsnes-accuracy PPU threads running just for video.
-----
Oh, just a fair warning ... the hooks for the SGB are a work in
progress.
If anyone is working on higan or a fork and want to do something similar
to it, don't use it as a template, at least not yet.
Right now, higan looks like this:
- Emulator::Video handles the platform→videoRefresh calls
- Emulator::Audio handles the platform→audioSample calls
- each core hard-codes the platform→inputPoll, inputRumble calls
- each core hard-codes calls to path, open, load to process files
- dipSettings and notify are specialty hacks, neither are even hooked
up right now to anything
With the SGB, it's an emulation core inside an emulation core, so
ideally you want to hook all of those functions. Emulator::Video and
Emulator::Audio aren't really abstractions over that, as the GB core
calls them and we have to special case not calling them in SGB mode.
The path, open, load can be implemented without hooks, thanks to the UI
only using one instance of Emulator::Platform for all cores. All we have
to do is override the folder path ID for the "Game Boy.sys" folder, so
that it picks "Super Game Boy.sfc/" and loads its boot ROM instead.
That's just a simple argument to GameBoy::System::load() and we're done.
dipSettings, notify and inputRumble don't matter. But we do also have to
hook inputPoll as well.
The nice idea would be for SuperFamicom::ICD2 to inherit from
Emulator::Platform and provide the desired functions that we need to
overload. After that, we'd just need the GB core to keep an abstraction
over the global Emulator::platform\* handle, to select between the UI
version and the SFC::ICD2 version.
However ... that doesn't work because of Emulator::Video and
Emulator::Audio. They would also have to gain an abstraction over
Emulator::platform\*, and even worse ... you'd have to constantly swap
between the two so that the SFC core uses the UI, and the GB core uses
the ICD2.
And so, for right now, I'm checking Model::SuperGameBoy() -> bool
everywhere, and choosing between the UI and ICD2 targets that way. And
as such, the ICD2 doesn't really need Emulator::Platform inheritance,
although it certainly could do that and just use the functions it needs.
But the SGB is even weirder, because we need additional new signals
beyond just Emulator::Platform, like joypWrite(), etc.
I'd also like to work on the Emulator::Stream for the SGB core. I don't
see why we can't have the GB core create its own stream, and let the
ICD2 just use that instead. We just have to be careful about the ICD2's
CPU soft reset function, to make sure the GB core's Stream object
remains valid. What I think that needs is a way to release an
Emulator::Stream individually, rather than calling
Emulator::Audio::reset() to do it. They are shared\_pointer objects, so
I think if I added a destructor function to remove it from
Emulator::Audio::streams, then that should work.
2017-01-26 01:06:06 +00:00
|
|
|
reset();
|
2011-01-08 09:58:41 +00:00
|
|
|
}
|
2017-06-30 04:17:23 +00:00
|
|
|
auto frequency = system.cpuFrequency();
|
2011-01-08 09:58:41 +00:00
|
|
|
switch(data & 3) {
|
Update to v100r14 release.
byuu says:
(Windows: compile with -fpermissive to silence an annoying error. I'll
fix it in the next WIP.)
I completely replaced the time management system in higan and overhauled
the scheduler.
Before, processor threads would have "int64 clock"; and there would
be a 1:1 relationship between two threads. When thread A ran for X
cycles, it'd subtract X * B.Frequency from clock; and when thread B ran
for Y cycles, it'd add Y * A.Frequency from clock. This worked well
and allowed perfect precision; but it doesn't work when you have more
complicated relationships: eg the 68K can sync to the Z80 and PSG; the
Z80 to the 68K and PSG; so the PSG needs two counters.
The new system instead uses a "uint64 clock" variable that represents
time in attoseconds. Every time the scheduler exits, it subtracts
the smallest clock count from all threads, to prevent an overflow
scenario. The only real downside is that rounding errors mean that
roughly every 20 minutes, we have a rounding error of one clock cycle
(one 20,000,000th of a second.) However, this only applies to systems
with multiple oscillators, like the SNES. And when you're in that
situation ... there's no such thing as a perfect oscillator anyway. A
real SNES will be thousands of times less out of spec than 1hz per 20
minutes.
The advantages are pretty immense. First, we obviously can now support
more complex relationships between threads. Second, we can build a
much more abstracted scheduler. All of libco is now abstracted away
completely, which may permit a state-machine / coroutine version of
Thread in the future. We've basically gone from this:
auto SMP::step(uint clocks) -> void {
clock += clocks * (uint64)cpu.frequency;
dsp.clock -= clocks;
if(dsp.clock < 0 && !scheduler.synchronizing()) co_switch(dsp.thread);
if(clock >= 0 && !scheduler.synchronizing()) co_switch(cpu.thread);
}
To this:
auto SMP::step(uint clocks) -> void {
Thread::step(clocks);
synchronize(dsp);
synchronize(cpu);
}
As you can see, we don't have to do multiple clock adjustments anymore.
This is a huge win for the SNES CPU that had to update the SMP, DSP, all
peripherals and all coprocessors. Likewise, we don't have to synchronize
all coprocessors when one runs, now we can just synchronize the active
one to the CPU.
Third, when changing the frequencies of threads (think SGB speed setting
modes, GBC double-speed mode, etc), it no longer causes the "int64
clock" value to be erroneous.
Fourth, this results in a fairly decent speedup, mostly across the
board. Aside from the GBA being mostly a wash (for unknown reasons),
it's about an 8% - 12% speedup in every other emulation core.
Now, all of this said ... this was an unbelievably massive change, so
... you know what that means >_> If anyone can help test all types of
SNES coprocessors, and some other system games, it'd be appreciated.
----
Lastly, we have a bitchin' new about screen. It unfortunately adds
~200KiB onto the binary size, because the PNG->C++ header file
transformation doesn't compress very well, and I want to keep the
original resource files in with the higan archive. I might try some
things to work around this file size increase in the future, but for now
... yeah, slightly larger archive sizes, sorry.
The logo's a bit busted on Windows (the Label control's background
transparency and alignment settings aren't working), but works well on
GTK. I'll have to fix Windows before the next official release. For now,
look on my Twitter feed if you want to see what it's supposed to look
like.
----
EDIT: forgot about ICD2::Enter. It's doing some weird inverse
run-to-save thing that I need to implement support for somehow. So, save
states on the SGB core probably won't work with this WIP.
2016-07-30 03:56:12 +00:00
|
|
|
case 0: setFrequency(frequency / 4); break; //fast (glitchy, even on real hardware)
|
|
|
|
case 1: setFrequency(frequency / 5); break; //normal
|
|
|
|
case 2: setFrequency(frequency / 7); break; //slow
|
|
|
|
case 3: setFrequency(frequency / 9); break; //very slow
|
2011-01-08 09:58:41 +00:00
|
|
|
}
|
|
|
|
r6003 = data;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(addr == 0x6004) { r6004 = data; return; } //joypad 1
|
|
|
|
if(addr == 0x6005) { r6005 = data; return; } //joypad 2
|
|
|
|
if(addr == 0x6006) { r6006 = data; return; } //joypad 3
|
|
|
|
if(addr == 0x6007) { r6007 = data; return; } //joypad 4
|
|
|
|
}
|