byuu says:
Added VDP sprite rendering. Can't get any games far enough in to see if
it actually works. So in other words, it doesn't work at all and is 100%
completely broken.
Also added 68K exceptions and interrupts. So far only the VDP interrupt
is present. It definitely seems to be firing in commercial games, so
that's promising. But the implementation is almost certainly completely
wrong. There is fuck all of nothing for documentation on how interrupts
actually work. I had to find out the interrupt vector numbers from
reading the comments from the Sonic the Hedgehog disassembly. I have
literally no fucking clue what I0-I2 (3-bit integer priority value in
the status register) is supposed to do. I know that Vblank=6, Hblank=4,
Ext(gamepad)=2. I know that at reset, SR.I=7. I don't know if I'm
supposed to block interrupts when I is >, >=, <, <= to the interrupt
level. I don't know what level CPU exceptions are supposed to be.
Also implemented VDP regular DMA. No idea if it works correctly since
none of the commercial games run far enough to use it. So again, it's
horribly broken for usre.
Also improved VDP fill mode. But I don't understand how it takes
byte-lengths when the bus is 16-bit. The transfer times indicate it's
actually transferring at the same speed as the 68K->VDP copy, strongly
suggesting it's actually doing 16-bit transfers at a time. In which case,
what happens when you set an odd transfer length?
Also, both DMA modes can now target VRAM, VSRAM, CRAM. Supposedly there's
all kinds of weird shit going on when you target VSRAM, CRAM with VDP
fill/copy modes, but whatever. Get to that later.
Also implemented a very lazy preliminary wait mechanism to to stall out
a processor while another processor exerts control over the bus. This
one's going to be a major work in progress. For one, it totally breaks
the model I use to do save states with libco. For another, I don't
know if a 68K->VDP DMA instantly locks the CPU, or if it the CPU could
actually keep running if it was executing out of RAM when it started
the DMA transfer from ROM (eg it's a bus busy stall, not a hard chip
stall.) That'll greatly change how I handle the waiting.
Also, the OSS driver now supports Audio::Latency. Sound should be
even lower latency now. On FreeBSD when set to 0ms, it's absolutely
incredible. Cannot detect latency whatsoever. The Mario jump sound seems
to happen at the very instant I hear my cherry blue keyswitch activate.
byuu says:
I reworked the video sizing code. Ended up wasting five fucking hours
fighting GTK. When you call `gtk_widget_set_size_request`, it doesn't
actually happen then. This is kind of a big deal because when I then go
to draw onto the viewport, the actual viewport child window is still the
old size, so the image gets distorted. It recovers in a frame or so with
emulation, but if we were to put a still image on there, it would stay
distorted.
The first thought is, `while(gtk_events_pending())
gtk_main_iteration_do(false);` right after the `set_size_request`. But
nope, it tells you there's no events pending. So then you think, go
deeper, use `XPending()` instead. Same thing, GTK hasn't actually issued
the command to Xlib yet. So then you think, if the widget is realized,
just call a blocking `gtk_main_iteration`. One call does nothing, two
calls results in a deadlock on the second one ... do it before program
startup, and the main window will never appear. Great.
Oh, and it's not just the viewport. It's also the widget container area
of the windows, as well as the window itself, as well as the fullscreen
mode toggle effect. They all do this.
For the latter three, I couldn't find anything that worked, so I just
added 20ms loops of constantly calling `gtk_main_iteration_do(false)`
after each one of those things. The downside here is toggling the status
bar takes 40ms, so you'll see it and it'll feel a tiny bit sluggish.
But I can't have a 20ms wait on each widget resize, that would be
catastrophic to performance on windows with lots of widgets.
I tried hooking configure-event and size-allocate, but they were very
unreliable. So instead I ended up with a loop that waits up to a maximm
of 20ms that inspects the `widget->allocation.(width,height)` values
directly and waits for them to be what we asked for with
`set_size_request`.
There was some extreme ugliness in GTK with calling
`gtk_main_iteration_do` recursively (`hiro::Widget::setGeometry` is
called recursively), so I had to lock it to only happen on the top level
widgets (the child ones should get resized while waiting on the
top-level ones, so it should be fine in practice), and also only run it
on realized widgets.
Even still, I'm getting ~3 timeouts when opening the settings dialog in
higan, but no other windows. But, this is the best I can do for now.
And the reason for all of this pain? Yeah, updated the video code.
So the Emulator::Interface now has this:
struct VideoSize { uint width, height; }; //or requiem for a tuple
auto videoSize() -> VideoSize;
auto videoSize(uint width, uint height, bool arc) -> VideoSize;
The first function, for now, is just returning the literal surface size.
I may remove this ... one thing I want to allow for is cores that send
different texture sizes based on interlace/hires/overscan/etc settings.
The second function is more interesting. Instead of having the UI trying
to figure out sizing, I figure the emulation cores can do a better job
and we can customize it per-core now. So it gets the window's width and
height, and whether the user asked for aspect correction, and then
computes the best width/height ratio possible. For now they're all just
doing multiples of a 1x scale to the UI 2x,3x,4x modes.
We still need a third function, which will probably be what I repurpose
videoSize() for: to return the 'effective' size for pixel shaders, to
then feed into ruby, to then feed into quark, to then feed into our
shaders. Since shaders use normalized coordinates for pixel fetching,
this should work out just fine. The real texture size will be exposed to
quark shaders as well, of course.
Now for the main window ... it's just hard-coded to be 640x480, 960x720,
1280x960 for now. It works nicely for some cores on some modes, not so
much for others. Work in progress I guess.
I also took the opportunity to draw the about dialog box logo on the
main window. Got a bit fancy and used the old spherical gradient and
impose functionality of nall/image on it. Very minor highlight, nothing
garish. Just something nicer than a solid black window.
If you guys want to mess around with sizes, placements, and gradient
styles/colors/shapes ... feel free. If you come up with something nicer,
do share.
That's what led to all the GTK hell ... the logo wasn't drawing right as
you resized the window. But now it is, though I am not at all happy with
the hacking I had to do.
I also had to improve the video update code as a result of this:
- when you unload a game, it blacks out the screen
- if you are not quitting the emulator, it'll draw the logo; if
you are, it won't
- when you load a game, it black out the logo
These options prevent any unsightliness from resizing the viewport with
image data on it already
I need to redraw the logo when toggling fullscreen with no game loaded
as well for Windows, it seems.
byuu says:
Changelog:
- 68K: fixed bug that affected BSR return address
- VDP: added very preliminary emulation of planes A, B, W (W is
entirely broken though)
- VDP: added command/address stuff so you can write to VRAM, CRAM,
VSRAM
- VDP: added VRAM fill DMA
I would be really surprised if any commercial games showed anything at
all, so I'd probably recommend against wasting your time trying, unless
you're really bored :P
Also, I wanted to add: I am accepting patches\! So if anyone wants to
look over the 68K core for bugs, that would save me untold amounts of
time in the near future :D
byuu says:
Changelog:
- pulled the (u)intN type aliases into higan instead of leaving them
in nall
- added 68K LINEA, LINEF hooks for illegal instructions
- filled the rest of the 68K lambda table with generic instance of
ILLEGAL
- completed the 68K disassembler effective addressing modes
- still unsure whether I should use An to decode absolute
addresses or not
- pro: way easier to read where accesses are taking place
- con: requires An to be valid; so as a disassembler it does a
poor job
- making it optional: too much work; ick
- added I/O decoding for the VDP command-port registers
- added skeleton timing to all five processor cores
- output at 1280x480 (needed for mixed 256/320 widths; and to handle
interlace modes)
The VDP, PSG, Z80, YM2612 are all stepping one clock at a time and
syncing; which is the pathological worst case for libco. But they also
have no logic inside of them. With all the above, I'm averaging around
250fps with just the 68K core actually functional, and the VDP doing a
dumb "draw white pixels" loop. Still way too early to tell how this
emulator is going to perform.
Also, the 320x240 mode of the Genesis means that we don't need an aspect
correction ratio. But we do need to ensure the output window is a
multiple 320x240 so that the scale values work correctly. I was
hard-coding aspect correction to stretch the window an additional \*8/7.
But that won't work anymore so ... the main higan window is now 640x480,
960x720, or 1280x960. Toggling aspect correction only changes the video
width inside the window.
It's a bit jarring ... the window is a lot wider, more black space now
for most modes. But for now, it is what it is.
byuu says:
The 68K core now implements all 88 instructions. It ended up being 111
instructions in my core due to splitting up opcodes with the same name
but different addressing modes or directions (removes conditions at the
expense of more code.)
Technically, I don't have exceptions actually implemented yet, and
RESET/STOP don't do anything but set flags. So there's still more to
go. But ... close enough for statistics time!
The M68K core source code is 124,712 bytes in size. The next largest
core is the ARM7 core at 70,203 bytes in size.
The M68K object size is 942KiB; with the next largest being the V30MZ
core at 173KiB.
There are a total of 19,656 invalid opcodes in the 68000 revision (unless
of course I've made mistakes in my mappings, which is very probably.)
Now the fun part ... figuring out how to fix bugs in this core without
VDP emulation :/
byuu says:
Changelog:
- Emulator: use `(uintmax)-1 >> 1` for the units of time
- MD: implemented 13 new 68K instructions (basically all of the
remaining easy ones); 21 remain
- nall: replaced `(u)intmax_t` (64-bit) with *actual* `(u)intmax` type
(128-bit where available)
- this extends to everything: atoi, string, etc. You can even
print 128-bit variables if you like
22,552 opcodes still don't exist in the 68K map. Looking like quite a
few entries will be blank once I finish.
byuu says:
Changelog:
- added eight more 68K instructions
- split ADD(direction) into two separate ADD functions
I now have 54 out of 88 instructions implemented (thus, 34 remaining.)
The map is missing 25,182 entries out of 65,536. Down from 32,680 for
v101.00
Aside: this version number feels really silly. r10 and r11 surely will
as well ...
byuu says (in the public announcement):
Not a large changelog this time, sorry. This release is mostly to fix
the SA-1 issue, and to get some real-world testing of the new scheduler
model. Most of the work in the past month has gone into writing a 68000
CPU core; yet it's still only about half-way finished.
Changelog (since the previous release):
- fixed SNES SA-1 IRQ regression (fixes Super Mario RPG level-up
screen)
- new scheduler for all emulator cores (precision of 2^-127)
- icarus database adds nine new SNES games
- added Input/Frequency to settings file (allows simulation of
latency)
byuu says (in the WIP forum):
Changelog:
- in 32-bit mode, Thread uses uint64\_t with 2^-63 time units (10^-7
precision in the worst case)
- nearly ten times the precision of an attosecond
- in 64-bit mode, Thread uses uint128\_t with 2^-127 time units
(10^-26 precision in the worst case)
- far more accurate than yoctoseconds; almost closing in on planck
time
Note: a quartz crystal is accurate to 10^-4 or 10^-5. A cesium fountain
atomic clock is accurate to 10^-15. So ... yeah. 2^-63 was perfectly
fine; but there was no speed penalty whatsoever for using uint128\_t in
64-bit mode, so why not?
byuu says:
(Windows users may need to include <sys/time.h> at the top of
nall/chrono.hpp, not sure.)
Unchangelog:
- forgot to add the Scheduler clock=0 fix because I have the memory of
a goldfish
Changelog:
- new icarus database with nine additional games
- hiro(GTK,Qt) won't constantly write its settings.bml file to disk
anymore
- added latency simulator for fun (settings.bml => Input/Latency in
milliseconds)
So the last one ... I wanted to test out nall::chrono, and I was also
thinking that by polling every emulated frame, it's pretty wasteful when
you are using Fast Forward and hitting 200+fps. As I've said before,
calls to ruby::input::poll are not cheap.
So to get around this, I added a limiter so that if you called the
hardware poll function within N milliseconds, it'll return without
doing any actual work. And indeed, that increases my framerate of Zelda
3 uncapped from 133fps to 142fps. Yay. But it's not a "real" speedup,
as it only helps you when you exceed 100% speed (theoretically, you'd
need to crack 300% speed since the game itself will poll at 16ms at 100%
speed, but yet it sped up Zelda 3, so who am I to complain?)
I threw the latency value into the settings file. It should be 16,
but I set it to 5 since that was the lowest before it started negatively
impacting uncapped speeds. You're wasting your time and CPU cycles setting
it lower than 5, but if people like placebo effects it might work. Maybe
I should let it be a signed integer so people can set it to -16 and think
it's actually faster :P (I'm only joking. I took out the 96000hz audio
placebo effect as well. Not really into psychological tricks anymore.)
But yeah seriously, I didn't do this to start this discussion again for
the billionth time. Please don't go there. And please don't tell me this
WIP has higher/lower latency than before. I don't want to hear it.
The only reason I bring it up is for the fun part that is worth
discussing: put up or shut up time on how sensitive you are to
latency! You can set the value above 5 to see how games feel.
I personally can't really tell a difference until about 50. And I can't
be 100% confident it's worse until about 75. But ... when I set it to
150, games become "extra difficult" ... the higher it goes, the worse
it gets :D
For this WIP, I've left no upper limit cap. I'll probably set a cap of
something like 500ms or 1000ms for the official release. Need to balance
user error/trolling with enjoyability. I'll think about it.
[...]
Now, what I worry about is stupid people seeing it and thinking it's an
"added latency" setting, as if anyone would intentionally make things
worse by default. This is a limiter. So if 5ms have passed since the
game last polled, and that will be the case 99.9% of the time in games,
the next poll will happen just in time, immediately when the game polls
the inputs. Thus, a value below 1/<framerate>ms is not only pointless,
if you go too low it will ruin your fast forward max speeds.
I did say I didn't want to resort to placebo tricks, but I also don't
want to spark up public discussion on this again either. So it might
be best to default Input/Latency to 0ms, and internally have a max(5,
latency) wrapper around the value.
byuu wrote:
Aforementioned scheduler changes added. Longer explanation of why here:
http://hastebin.com/raw/toxedenece
Again, we really need to test this as thoroughly as possible for
regressions :/
This is a really major change that affects absolutely everything: all
emulation cores, all coprocessors, etc.
Also added ADDX and SUB to the 68K core, which brings us just barely
above 50% of the instruction encoding space completed.
[Editor's note: The "aformentioned scheduler changes" were described in
a previous forum post:
Unfortunately, 64-bits just wasn't enough precision (we were
getting misalignments ~230 times a second on 21/24MHz clocks), so
I had to move to 128-bit counters. This of course doesn't exist on
32-bit architectures (and probably not on all 64-bit ones either),
so for now ... higan's only going to compile on 64-bit machines
until we figure something out. Maybe we offer a "lower precision"
fallback for machines that lack uint128_t or something. Using the
booth algorithm would be way too slow.
Anyway, the precision is now 2^-96, which is roughly 10^-29. That
puts us far beyond the yoctosecond. Suck it, MAME :P I'm jokingly
referring to it as the byuusecond. The other 32-bits of precision
allows a 1Hz clock to run up to one full second before all clocks
need to be normalized to prevent overflow.
I fixed a serious wobbling issue where I was using clock > other.clock
for synchronization instead of clock >= other.clock; and also another
aliasing issue when two threads share a common frequency, but don't
run in lock-step. The latter I don't even fully understand, but I
did observe it in testing.
nall/serialization.hpp has been extended to support 128-bit integers,
but without explicitly naming them (yay generic code), so nall will
still compile on 32-bit platforms for all other applications.
Speed is basically a wash now. FC's a bit slower, SFC's a bit faster.
The "longer explanation" in the linked hastebin is:
Okay, so the idea is that we can have an arbitrary number of
oscillators. Take the SNES:
- CPU/PPU clock = 21477272.727272hz
- SMP/DSP clock = 24576000hz
- Cartridge DSP1 clock = 8000000hz
- Cartridge MSU1 clock = 44100hz
- Controller Port 1 modem controller clock = 57600hz
- Controller Port 2 barcode battler clock = 115200hz
- Expansion Port exercise bike clock = 192000hz
Is this a pathological case? Of course it is, but it's possible. The
first four do exist in the wild already: see Rockman X2 MSU1
patch. Manifest files with higan let you specify any frequency you
want for any component.
The old trick higan used was to hold an int64 counter for each
thread:thread synchronization, and adjust it like so:
- if thread A steps X clocks; then clock += X * threadB.frequency
- if clock >= 0; switch to threadB
- if thread B steps X clocks; then clock -= X * threadA.frequency
- if clock < 0; switch to threadA
But there are also system configurations where one processor has to
synchronize with more than one other processor. Take the Genesis:
- the 68K has to sync with the Z80 and PSG and YM2612 and VDP
- the Z80 has to sync with the 68K and PSG and YM2612
- the PSG has to sync with the 68K and Z80 and YM2612
Now I could do this by having an int64 clock value for every
association. But these clock values would have to be outside the
individual Thread class objects, and we would have to update every
relationship's clock value. So the 68K would have to update the Z80,
PSG, YM2612 and VDP clocks. That's four expensive 64-bit multiply-adds
per clock step event instead of one.
As such, we have to account for both possibilities. The only way to
do this is with a single time base. We do this like so:
- setup: scalar = timeBase / frequency
- step: clock += scalar * clocks
Once per second, we look at every thread, find the smallest clock
value. Then subtract that value from all threads. This prevents the
clock counters from overflowing.
Unfortunately, these oscillator values are psychotic, unpredictable,
and often times repeating fractions. Even with a timeBase of
1,000,000,000,000,000,000 (one attosecond); we get rounding errors
every ~16,300 synchronizations. Specifically, this happens with a CPU
running at 21477273hz (rounded) and SMP running at 24576000hz. That
may be good enough for most emulators, but ... you know how I am.
Plus, even at the attosecond level, we're really pushing against the
limits of 64-bit integers. Given the reciprocal inverse, a frequency
of 1Hz (which does exist in higan!) would have a scalar that consumes
1/18th of the entire range of a uint64 on every single step. Yes, I
could raise the frequency, and then step by that amount, I know. But
I don't want to have weird gotchas like that in the scheduler core.
Until I increase the accuracy to about 100 times greater than a
yoctosecond, the rounding errors are too great. And since the only
choice above 64-bit values is 128-bit values; we might as well use
all the extra headroom. 2^-96 as a timebase gives me the ability to
have both a 1Hz and 4GHz clock; and run them both for a full second;
before an overflow event would occur.
Another hastebin includes demonstration code:
#include <libco/libco.h>
#include <nall/nall.hpp>
using namespace nall;
//
cothread_t mainThread = nullptr;
const uint iterations = 100'000'000;
const uint cpuFreq = 21477272.727272 + 0.5;
const uint smpFreq = 24576000.000000 + 0.5;
const uint cpuStep = 4;
const uint smpStep = 5;
//
struct ThreadA {
cothread_t handle = nullptr;
uint64 frequency = 0;
int64 clock = 0;
auto create(auto (*entrypoint)() -> void, uint frequency) {
this->handle = co_create(65536, entrypoint);
this->frequency = frequency;
this->clock = 0;
}
};
struct CPUA : ThreadA {
static auto Enter() -> void;
auto main() -> void;
CPUA() { create(&CPUA::Enter, cpuFreq); }
} cpuA;
struct SMPA : ThreadA {
static auto Enter() -> void;
auto main() -> void;
SMPA() { create(&SMPA::Enter, smpFreq); }
} smpA;
uint8 queueA[iterations];
uint offsetA;
cothread_t resumeA = cpuA.handle;
auto EnterA() -> void {
offsetA = 0;
co_switch(resumeA);
}
auto QueueA(uint value) -> void {
queueA[offsetA++] = value;
if(offsetA >= iterations) {
resumeA = co_active();
co_switch(mainThread);
}
}
auto CPUA::Enter() -> void { while(true) cpuA.main(); }
auto CPUA::main() -> void {
QueueA(1);
smpA.clock -= cpuStep * smpA.frequency;
if(smpA.clock < 0) co_switch(smpA.handle);
}
auto SMPA::Enter() -> void { while(true) smpA.main(); }
auto SMPA::main() -> void {
QueueA(2);
smpA.clock += smpStep * cpuA.frequency;
if(smpA.clock >= 0) co_switch(cpuA.handle);
}
//
struct ThreadB {
cothread_t handle = nullptr;
uint128_t scalar = 0;
uint128_t clock = 0;
auto print128(uint128_t value) {
string s;
while(value) {
s.append((char)('0' + value % 10));
value /= 10;
}
s.reverse();
print(s, "\n");
}
//femtosecond (10^15) = 16306
//attosecond (10^18) = 688838
//zeptosecond (10^21) = 13712691
//yoctosecond (10^24) = 13712691 (hitting a dead-end on a rounding error causing a wobble)
//byuusecond? ( 2^96) = (perfect? 79,228 times more precise than a yoctosecond)
auto create(auto (*entrypoint)() -> void, uint128_t frequency) {
this->handle = co_create(65536, entrypoint);
uint128_t unitOfTime = 1;
//for(uint n : range(29)) unitOfTime *= 10;
unitOfTime <<= 96; //2^96 time units ...
this->scalar = unitOfTime / frequency;
print128(this->scalar);
this->clock = 0;
}
auto step(uint128_t clocks) -> void { clock += clocks * scalar; }
auto synchronize(ThreadB& thread) -> void { if(clock >= thread.clock) co_switch(thread.handle); }
};
struct CPUB : ThreadB {
static auto Enter() -> void;
auto main() -> void;
CPUB() { create(&CPUB::Enter, cpuFreq); }
} cpuB;
struct SMPB : ThreadB {
static auto Enter() -> void;
auto main() -> void;
SMPB() { create(&SMPB::Enter, smpFreq); clock = 1; }
} smpB;
auto correct() -> void {
auto minimum = min(cpuB.clock, smpB.clock);
cpuB.clock -= minimum;
smpB.clock -= minimum;
}
uint8 queueB[iterations];
uint offsetB;
cothread_t resumeB = cpuB.handle;
auto EnterB() -> void {
correct();
offsetB = 0;
co_switch(resumeB);
}
auto QueueB(uint value) -> void {
queueB[offsetB++] = value;
if(offsetB >= iterations) {
resumeB = co_active();
co_switch(mainThread);
}
}
auto CPUB::Enter() -> void { while(true) cpuB.main(); }
auto CPUB::main() -> void {
QueueB(1);
step(cpuStep);
synchronize(smpB);
}
auto SMPB::Enter() -> void { while(true) smpB.main(); }
auto SMPB::main() -> void {
QueueB(2);
step(smpStep);
synchronize(cpuB);
}
//
#include <nall/main.hpp>
auto nall::main(string_vector) -> void {
mainThread = co_active();
uint masterCounter = 0;
while(true) {
print(masterCounter++, " ...\n");
auto A = clock();
EnterA();
auto B = clock();
print((double)(B - A) / CLOCKS_PER_SEC, "s\n");
auto C = clock();
EnterB();
auto D = clock();
print((double)(D - C) / CLOCKS_PER_SEC, "s\n");
for(uint n : range(iterations)) {
if(queueA[n] != queueB[n]) return print("fail at ", n, "\n");
}
}
}
...and that's everything.]
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.
byuu says:
All of the above fixes, plus I added all 24 variations on the shift
opcodes, plus SUBQ, plus fixes to the BCC instruction.
I can now run 851,767 instructions into Sonic the Hedgehog before hitting
an unimplemented instruction (SUB).
The 68K core is probably only ~35% complete, and yet it's already within
4KiB of being the largest CPU core, code size wise, in all of higan. Fuck
this chip.
byuu says:
I split the Register class and read/write handlers into DataRegister and
AddressRegister, given that they have different behaviors on byte/word
accesses (data tends to preserve the upper bits; address tends to
sign-extend things.)
I expanded EA to EffectiveAddress. No sense in abbreviating things
to death.
I've now implemented 26 instructions. But the new ones are just all the
stupid from/to ccr/sr instructions.
Ryphecha confirmed that you can't set the undefined bits, so I don't
think the BitField concept is appropriate for the CCR/SR. Instead, I'm
just storing direct flags and have (read,write)(CCR,SR) instead. This
isn't like the 65816 where you have subroutines that push and pop the
flag register. It's much more common to access individual flags. Doesn't
match the consistency angle of the other CPU cores, but ... I think this
is the right thing to for the 68K specifically.
byuu says:
Redesigned the handling of reading/writing registers to be about eight
times faster than the old system. More work may be needed ... it seems
data registers tend to preserve their upper bits upon assignment; whereas
address registers tend to sign-extend values into them. It may make
sense to have DataRegister and AddressRegister classes with separate
read/write handlers. I'd have to hold two Register objects inside the
EffectiveAddress (EA) class if we do that.
Implemented 19 opcodes now (out of somewhere between 60 and 90.) That gets
the first ~530,000 instructions in Sonic the Hedgehog running (though
probably wrong. But we can run a lot thanks to large initialization
loops.)
If I force the core to loop back to the reset vector on an invalid opcode,
I'm getting about 1500fps with a dumb 320x240 blit 60 times a second and
just the 68K running alone (no Z80, PSG, VDP, YM2612.) I don't know if
that's good or not. I guess we'll find out.
I had to stop tonight because the final opcode I execute is an RTS
(return from subroutine) that's branching back to address 0; which is
invalid ... meaning something went terribly wrong and the system crashed.
byuu says:
Another six hours in ...
I have all of the opcodes, memory access functions, disassembler mnemonics
and table building converted over to the new template<uint Size> format.
Certainly, it would be quite easy for this nightmare chip to throw me
another curveball, but so far I can handle:
- MOVE (EA to, EA from) case
- read(from) has to update register index for +/-(aN) mode
- MOVEM (EA from) case
- when using +/-(aN), RA can't actually be updated until the transfer
is completed
- LEA (EA from) case
- doesn't actually perform the final read; just returns the address
to be read from
- ANDI (EA from-and-to) case
- same EA has to be read from and written to
- for -(aN), the read has to come from aN-2, but can't update aN yet;
so that the write also goes to aN-2
- no opcode can ever fetch the extension words more than once
- manually control the order of extension word fetching order for proper
opcode decoding
To do all of that without a whole lot of duplicated code (or really
bloating out every single instruction with red tape), I had to bring
back the "bool valid / uint32 address" variables inside the EA struct =(
If weird exceptions creep in like timing constraints only on certain
opcodes, I can use template flags to the EA read/write functions to
handle that.
byuu says:
Six and a half hours this time ... one new opcode, and all old opcodes
now in a deprecated format. Hooray, progress!
For building the table, I've decided to move from:
for(uint opcode : range(65536)) {
if(match(...)) bind(opNAME, ...);
}
To instead having separate for loops for each supported opcode. This
lets me specialize parts I want with templates.
And to this aim, I'm moving to replace all of the
(read,write)(size, ...) functions with (read,write)<Size>(...) functions.
This will amount to the ~70ish instructions being triplicated ot ~210ish
instructions; but I think this is really important.
When I was getting into flag calculations, a ton of conditionals
were needed to mask sizes to byte/word/long. There was also lots of
conditionals in all the memory access handlers.
The template code is ugly, but we eliminate a huge amount of branch
conditions this way.
byuu says:
Four and a half hours of work and ... zero new opcodes implemented.
This was the best job I could do refining the effective address
computations. Should have all twelve 68000 modes implemented now. Still
have a billion questions about when and how I'm supposed to perform
certain edge case operations, though.
byuu says:
Up to ten 68K instructions out of somewhere between 61 and 88, depending
upon which PDF you look at. Of course, some of them aren't 100% completed
yet, either. Lots of craziness with MOVEM, and BCC has a BSR variant
that needs stack push/pop functions.
This WIP actually took over eight hours to make, going through every
possible permutation on how to design the core itself. The updated design
now builds both the instruction decoder+dispatcher and the disassembler
decoder into the same main loop during M68K's constructor.
The special cases are also really psychotic on this processor, and
I'm afraid of missing something via the fallthrough cases. So instead,
I'm ordering the instructions alphabetically, and including exclusion
cases to ignore binding invalid cases. If I end up remapping an existing
register, then it'll throw a run-time assertion at program startup.
I wanted very much to get rid of struct EA (EffectiveAddress), but
it's too difficult to keep track of the internal effective address
without it. So I split out the size to a separate parameter, since
every opcode only has one size parameter, and otherwise it was getting
duplicated in opcodes that take two EAs, and was also awkward with the
flag testing. It's a bit more typing, but I feel it's more clean this way.
Overall, I'm really worried this is going to be too slow. I don't want
to turn the EA stuff into templates, because that will massively bloat
out compilation times and object sizes, and will also need a special DSL
preprocessor since C++ doesn't have a static for loop. I can definitely
optimize a lot of EA's address/read/write functions away once the core
is completed, but it's never going to hold a candle to a templatized
68K core.
----
Forgot to include the SA-1 regression fix. I always remember immediately
after I upload and archive the WIP. Will try to get that in next time,
I guess.
byuu says:
Alright, I'm definitely going to need to find some people willing to
tolerate my questions on this chip, so I'm going to go ahead and announce
I'm working on this I guess.
This core is way too big for a surprise like the NES and WS cores
were. It'll probably even span multiple v10x releases before it's
even ready.
byuu says:
I now have enough of three instructions implemented to get through the
first four instructions in Sonic the Hedgehog.
But they're far from complete. The very first instruction uses EA
addressing, which is similar to x86's ModRM in terms of how disgustingly
complex it is. And it also accesses Z80 control registers, which obviously
isn't going to do anything yet.
The slow speed was me being stupid again. It's not 7.6MHz per frame,
it's 7.67MHz per second. So yeah, speed is so far acceptable again. But
we'll see how things go as I keep emulating more. The 68K decode is not
pretty at all.
byuu says:
Changelog:
- moved Thread, Scheduler, Cheat functionality into emulator/ for
all cores
- start of actual Mega Drive emulation (two 68K instructions)
I'm going to be rather terse on MD emulation, as it's too early for any
meaningful dialogue here.
byuu says:
Sigh ... I'm really not a good person. I'm inherently selfish.
My responsibility and obligation right now is to work on loki, and
then on the Tengai Makyou Zero translation, and then on improving the
Famicom emulation.
And yet ... it's not what I really want to do. That shouldn't matter;
I should work on my responsibilities first.
Instead, I'm going to be a greedy, self-centered asshole, and work on
what I really want to instead.
I'm really sorry, guys. I'm sure this will make a few people happy,
and probably upset even more people.
I'm also making zero guarantees that this ever gets finished. As always,
I wish I could keep these things secret, so if I fail / give up, I could
just drop it with no shame. But I would have to cut everyone out of the
WIP process completely to make it happen. So, here goes ...
This WIP adds the initial skeleton for Sega Mega Drive / Genesis
emulation. God help us.
(minor note: apparently the new extension for Mega Drive games is .md,
neat. That's what I chose for the folders too. I thought it was .smd,
so that'll be fixed in icarus for the next WIP.)
(aside: this is why I wanted to get v100 out. I didn't want this code in
a skeleton state in v100's source. Nor did I want really broken emulation,
which the first release is sure to be, tarring said release.)
...
So, basically, I've been ruminating on the legacy I want to leave behind
with higan. 3D systems are just plain out. I'm never going to support
them. They're too complex for my abilities, and they would run too slowly
with my design style. I'm not willing to compromise my design ideals. And
I would never want to play a 3D game system at native 240p/480i resolution
... but 1080p+ upscaling is not accurate, so that's a conflict I want
to avoid entirely. It's also never going to emulate computer systems
(X68K, PC-98, FM-Towns, etc) because holy shit that would completely
destroy me. It's also never going emulate arcade machines.
So I think of higan as a collection of 2D emulators for consoles
and handhelds. I've gone over every major 2D gaming system there is,
looking for ones with games I actually care about and enjoy. And I
basically have five of those systems supported already. Looking at the
remaining list, I see only three systems left that I have any interest
in whatsoever: PC-Engine, Master System, Mega Drive. Again, I'm not in
any way committing to emulating any of these, but ... if I had all of
those in higan, I think I'd be content to really, truly, finally stop
writing more emulators for the rest of my life.
And so I decided to tackle the most difficult system first. If I'm
successful, the Z80 core should cover a lot of the work on the SMS. And
the HuC6280 should land somewhere between the NES and SNES in terms of
difficulty ... closer to the NES.
The systems that just don't appeal to me at all, which I will never touch,
include, but are not limited to:
* Atari 2600/5200/7800
* Lynx
* Jaguar
* Vectrex
* Colecovision
* Commodore 64
* Neo-Geo
* Neo-Geo Pocket / Color
* Virtual Boy
* Super A'can
* 32X
* CD-i
* etc, etc, etc.
And really, even if something were mildly interesting in there ... we
have to stop. I can't scale infinitely. I'm already way past my limit,
but I'm doing this anyway. Too many cores bloats everything and kills
quality on everything. I don't want higan to become MESS v2.
I don't know what I'll do about the Famicom Disk System, PC-Engine CD,
and Mega CD. I don't think I'll be able to achieve 60fps emulating the
Mega CD, even if I tried to.
I don't know what's going to happen here with even the Mega Drive. Maybe
I'll get driven crazy with the documentation and quit. Maybe it'll end
up being too complicated and I'll quit. Maybe the emulation will end up
way too slow and I'll give up. Maybe it'll take me seven years to get
any games playable at all. Maybe Steve Snake, AamirM and Mike Pavone
will pool money to hire a hitman to come after me. Who knows.
But this is what I want to do, so ... here goes nothing.
[This version, with the internal version number changed back to "v100",
replaced the original v100 source archive on byuu.org soon after v100's
release, because it fixes important bugs in that version. --Ed]
byuu says:
Changelog:
- fixed default paths for Sufami Turbo slotted games
- moved WonderSwan orientation controls to the port rather than the device
- I do like hex_usr's idea here; but that'll need more consideration;
so this is a temporary fix
- added new debugger interface (see the public topic for more on that)
byuu says:
higan has finally reached v100!
I feel it's important to stress right away that this is not "version
1.00", nor is it a major milestone release. Rather than arbitrary version
numbers, all of my software simply bumps version numbers by one for each
official release. As such, higan v100 is simply higan's 100th release.
That said, the primary focus of this release has been code
clean-ups. These are always somewhat dangerous in that regressions are
possible. We've tested through sixteen WIP revisions, one of which was
open to the public, to try and minimize any regressions. But all the same,
please report any regressions if you discover any.
Changelog (since v099):
FC: render during pixels 1-256 instead of 0-255 [hex_usr]
FC: rewrote controller emulation code
SFC: 8% speedup over the previous release thanks to PPU optimizations
SFC: fixed nasty DB address wrapping regression from v099
SFC: USART developer controller removed; superseded by 21fx
SFC: Super Multitap option removed from controller port 1; ports
renamed 2-5
SFC: hidden option to experiment with 128KB VRAM (strictly for novelty)
higan: audio volume no longer divided by number of audio streams
higan: updated controller polling code to fix possible future mapping
issues
higan: replaced nall/stream with nall/vfs for file-loading subsystem
tomoko: can now load multi-slotted games via command-line
tomoko: synchronize video removed from UI; still available in the
settings file
tomoko, icarus: can navigate to root drive selection on Windows
all: major code cleanups and refactoring (~1MB diff against v099)
Note 1: the audio volume change means that SGB and MSU1 games won't
lose half the volume on the SNES sounds anymore. However, if one goes
overboard and drives the sound all the way to max volume with the MSU1,
clamping may occur. The obvious solution is not to drive volume that high
(it will vastly overpower the SNES audio, which usually never exceeds
25% volume.) Another option is to lower the volume in the audio settings
panel to 50%. In general, neither is likely to ever be necessary.
Note 2: the synchronize video option was hidden from the UI because it
is no longer useful. With the advent of compositors, the loss of the
complicated timing settings panel, support for the WonderSwan and its
75hz display, the need to emulate variable refresh rate behaviors in the
Game Boy, the unfortunate latency spike and audio distortion caused by
long Vsync pauses, and the arrival of adaptive sync technology ... it
no longer makes sense to present this option. However, as stated, you
can edit settings.bml to enable this option anyway if you insist and
understand the aforementioned risks.
Changelog (since v099r16 open beta):
- fixed MSU1 audio sign extension
- fixed compilation with SGB support disabled
- icarus can now navigate to root directory
- fixed compilation issues with OS X port
- (hopefully) fixed label height issue with hiro that affected icarus
import dialog
- (mostly) fixed BS Memory, Sufami Turbo slot loading
Errata:
- forgot to remove the " - Slot A", " - Slot B" suffixes for Sufami
Turbo slot loading
- this means you have to navigate up one folder and then into Sufami
Turbo/ to load games for this system
- moving WonderSwan orientation controls to the device slot is causing
some nastiness
- can now select orientation from the main menu, but it doesn't rotate
the display
byuu says:
Changelog:
- hiro: BrowserDialog can navigate up to drive selection on Windows
- nall: (file,path,dir,base,prefix,suffix)name =>
Location::(file,path,dir,base,prefix,suffix)
- higan/tomoko: rename audio filter label from "Sinc" to "IIR - Biquad"
- higan/tomoko: allow loading files via icarus on the command-line
once again
- higan/tomoko: (begrudging) quick hack to fix presentation window focus
on startup
- higan/audio: don't divide output audio volume by number of streams
- processor/r65816: fix a regression in (read,write)DB; fixes Taz-Mania
- fixed compilation regressions on Windows and Linux
I'm happy with where we are at with code cleanups and stability, so I'd
like to release v100. But even though I'm not assigning any special
significance to this version, we should probably test it more thoroughly
first.
byuu says:
Changelog:
- nall::lstring -> nall::string_vector
- added IntegerBitField<type, lo, hi> -- hopefully it works correctly...
- Multitap 1-4 -> Super Multitap 2-5
- fixed SFC PPU CGRAM read regression
- huge amounts of SFC PPU IO register cleanups -- .bits really is lovely
- re-added the read/write(VRAM,OAM,CGRAM) helpers for the SFC PPU
- but they're now optimized to the realities of the PPU (16-bit data
sizes / no address parameter / where appropriate)
- basically used to get the active-display overrides in a unified place;
but also reduces duplicate code in (read,write)IO
byuu says:
Changelog:
- (u)int(max,ptr) abbreviations removed; use _t suffix now [didn't feel
like they were contributing enough to be worth it]
- cleaned up nall::integer,natural,real functionality
- toInteger, toNatural, toReal for parsing strings to numbers
- fromInteger, fromNatural, fromReal for creating strings from numbers
- (string,Markup::Node,SQL-based-classes)::(integer,natural,real)
left unchanged
- template<typename T> numeral(T value, long padding, char padchar)
-> string for print() formatting
- deduces integer,natural,real based on T ... cast the value if you
want to override
- there still exists binary,octal,hex,pointer for explicit print()
formatting
- lstring -> string_vector [but using lstring = string_vector; is
declared]
- would be nice to remove the using lstring eventually ... but that'd
probably require 10,000 lines of changes >_>
- format -> string_format [no using here; format was too ambiguous]
- using integer = Integer<sizeof(int)*8>; and using natural =
Natural<sizeof(uint)*8>; declared
- for consistency with boolean. These three are meant for creating
zero-initialized values implicitly (various uses)
- R65816::io() -> idle() and SPC700::io() -> idle() [more clear; frees
up struct IO {} io; naming]
- SFC CPU, PPU, SMP use struct IO {} io; over struct (Status,Registers) {}
(status,registers); now
- still some CPU::Status status values ... they didn't really fit into
IO functionality ... will have to think about this more
- SFC CPU, PPU, SMP now use step() exclusively instead of addClocks()
calling into step()
- SFC CPU joypad1_bits, joypad2_bits were unused; killed them
- SFC PPU CGRAM moved into PPU::Screen; since nothing else uses it
- SFC PPU OAM moved into PPU::Object; since nothing else uses it
- the raw uint8[544] array is gone. OAM::read() constructs values from
the OAM::Object[512] table now
- this avoids having to determine how we want to sub-divide the two
OAM memory sections
- this also eliminates the OAM::synchronize() functionality
- probably more I'm forgetting
The FPS fluctuations are driving me insane. This WIP went from 128fps to
137fps. Settled on 133.5fps for the final build. But nothing I changed
should have affected performance at all. This level of fluctuation makes
it damn near impossible to know whether I'm speeding things up or slowing
things down with changes.
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.
byuu says:
Changelog:
- fixed FC AxROM / VRC7 regression
- BitField split to BooleanBitField/NaturalBitField (in preparation
for IntegerBitField)
- BitFieldReference removed
- GB CPU cleaned up
- GB Cartridge + Mappers cleaned up
- SFC CGRAM is now emulated as uint15[256] instead of uint[512]
- sfc/ppu/memory.cpp no longer needed; removed
- purged SFC Debugger hooks for now (some of the operator[] calls were
bypassing them anyway)
Unfortunately, for reasons that defy all semblance of logic, the CGRAM
change caused a slight speed hit. As have the last few changes. We're
now down to around 129.5fps compared to 123.fps for v099 and 134.5fps
at our peak (v099r01-r02).
I really like the style I came up with for the Game Boy mappers to settle
the purpose(ROM,RAM) vs (rom,ram)Purpose naming convention. If I ever get
around to redoing the NES mappers, that's likely the approach I'll take.
byuu says:
Changelog:
- NES PPU core updated to use BitFields (absolutely massive improvement
in code readability)
- NES APU core updated to new coding style
- NES cartridge/board and cartridge/chip updated to new coding style
- pushed NES PPU rendering one dot forward (doesn't fix King's Quest V
yet, sadly)
- fixed SNES PPU BG tilemask for 128KiB VRAM mode (doesn't fix Yoshi's
Island, though)
So ... I kind of went overboard with the fc/cartridge changes. This WIP
diff is 185KiB >_>
I didn't realize it was going to be as big a task as it was, but once
I started everything broke in a chain reaction, so I had to do it all
at once.
There's a massive chance we've broken a bunch of NES things. Any typos
in this WIP are going to be absolutely insidious to track down =(
But ... supposing I pulled it off, this means the Famicom core is now
fully converted to the new coding style as well. That leaves only the
GB and GBA cores. Once those are finished, then we'll finally be free
of these gigantic hellspawn diffs.
byuu says:
Changelog:
- higan/profile/ => higan/systems/ [temporary; unless we can't think of
a better base folder name]
- god-damn-better-have fixed the input polling bug
- re-added command-line and drag-and-drop loading
- command-line loading can now load multiple folders at once (SGB+GB
game; Sufami Turbo+Slot A+Slot B; etc)
- if you load just the base cart, it'll present you with a dialog to
optionally load slotted cart(s)
- MSU1 now goes through nall/vfs instead of directly accessing the
filesystem
- Famicom Cartridge, PPU cores updated to newer programming style
- there's countless opportunity for BitField and .bits() in the PPU
... but I'm worried about breaking things
If anyone has a working MSU1 game and can test the changes out, that'd
be appreciated. I still don't have a test ROM on my dev box.
I wouldn't worry too much about extensively testing the Famicom PPU
changes just yet ... I'm still struggling with what to name the structs
inside the classes between all of my emulators, and the BitField/.bits()
changes will be much more important to test at a later date.
The only use case left for Emulator::Interface::path(uint id) is for
21fx emulation. This peripheral loads a DLL/SO via LoadLibrary/dlopen,
which do not have any official ways to open a file in RAM. I'm
very hesitant to use the portable trick of writing the memory to a
temporary file, loading it, and deleting the temporary file once done
... it's a real waste of disk activity. I might make something like
vfs::file::isVirtual->bool,path()->string to get around this. But even
once I do, the underlying LoadLibrary/dlopen call is still going to be
direct disk access.
byuu says:
Changelog:
- Emulator::Interface::Medium::bootable removed
- Emulator::Interface::load(bool required) argument removed
[File::Required makes no sense on a folder]
- Super Famicom.sys now has user-configurable properties (CPU,PPU1,PPU2
version; PPU1 VRAM size, Region override)
- old nall/property removed completely
- volatile flags supported on coprocessor RAM files now (still not in
icarus, though)
- (hopefully) fixed SNES Multitap support (needs testing)
- fixed an OAM tiledata range clipping limit in 128KiB VRAM mode (doesn't
fix Yoshi's Island, sadly)
- (hopefully, again) fixed the input polling bug hex_usr reported
- re-added dialog box for when File::Required files are missing
- really cool: if you're missing a boot ROM, BIOS ROM, or IPL ROM,
it warns you immediately
- you don't have to select a game before seeing the error message
anymore
- fixed cheats.bml load/save location
byuu says:
Changelog:
- nall/vfs work 100% completed; even SGB games load now
- emulation cores now call load() for the base cartridges as well
- updated port/device handling; portmask is gone; device ID bug should
be resolved now
- SNES controller port 1 multitap option was removed
- added support for 128KiB SNES PPU VRAM (for now, edit sfc/ppu/ppu.hpp
VRAM::size=0x10000; to enable)
Overall, nall/vfs was a huge success!! We've substantially reduced
the amount of boilerplate code everywhere, while still allowing (even
easier than before) support for RAM-based game loading/saving. All of
nall/stream is dead and buried.
I am considering removing Emulator::Interface::Medium::id and/or
bootable flag. Or at least, doing something different with it. The
values for the non-bootable GB/BS/ST entries duplicate the ID that is
supposed to be unique. They are for GB/GBC and WS/WSC. Maybe I'll use
this as the hardware revision selection ID, and then gut non-bootable
options. There's really no reason for that to be there. I think at one
point I was using it to generate library tabs for non-bootable systems,
but we don't do that anymore anyway.
Emulator::Interface::load() may not need the required flag anymore ... it
doesn't really do anything right now anyway.
I have a few reasons for having the cores load the base cartridge. Most
importantly, it is going to enable a special mode for the WonderSwan /
WonderSwan Color in the future. If we ever get the IPLROMs dumped ... it's
possible to boot these systems with no games inserted to set user profile
information and such. There are also other systems that may accept being
booted without a cartridge. To reach this state, you would load a game and
then cancel the load dialog. Right now, this results in games not loading.
The second reason is this prevents nasty crashes when loading fails. So
if you're missing a required manifest, the emulator won't die a violent
death anymore. It's able to back out at any point.
The third reason is consistency: loading the base cartridge works the
same as the slot cartridges.
The fourth reason is Emulator::Interface::open(uint pathID)
values. Before, the GB, SB, GBC modes were IDs 1,2,3 respectively. This
complicated things because you had to pass the correct ID. But now
instead, Emulator::Interface::load() returns maybe<uint> that is nothing
when no game is selected, and a pathID for a valid game. And now open()
can take this ID to access this game's folder contents.
The downside, which is temporary, is that command-line loading is
currently broken. But I do intend on restoring it. In fact, I want to do
better than before and allow multi-cart booting from the command-line by
specifying the base cartridge and then slot cartridges. The idea should
be pretty simple: keep a queue of pending filenames that we fill from
the command-line and/or drag-and-drop operations on the main window,
and then empty out the queue or prompt for load dialogs from the UI
when booting a system. This also might be a bit more unorthodox compared
to the traditional emulator design of "loadGame(filename)", but ... oh
well. It's easy enough still.
The port/device changes are fun. We simplified things quite a bit. The
portmask stuff is gone entirely. While ports and devices keep IDs,
this is really just sugar-coating so UIs can use for(auto& port :
emulator->ports) and access port.id; rather than having to use for(auto
n : range(emulator->ports)) { auto& port = emulator->ports[n]; ... };
but they should otherwise generally be identical to the order they appear
in their respective ranges. Still, don't rely on that.
Input::id is gone. There was no point since we also got rid of the nasty
Input::order vector. Since I was in here, I went ahead and caved on the
pedantics and renamed Input::guid to Input::userData.
I removed the SNES controller port 1 multitap option. Basically, the only
game that uses this is N-warp Daisakusen and, no offense to d4s, it's
not really a good game anyway. It's just a quick demo to show 8-players
on the SNES. But in the UI, all it does is confuse people into wasting
time mapping a controller they're never going to use, and they're going
to wonder which port to use. If more compelling use cases for 8-players
comes about, we can reconsider this. I left all the code to support this
in place, so all you have to do is uncomment one line to enable it again.
We now have dsnes emulation! :D
If you change PPU::VRAM::size to 0x10000 (words), then you should now
have 128KiB of VRAM. Even better, it serializes the used-VRAM size,
so your save states shouldn't crash on you if you swap between the two
(though if you try this, you're nuts.)
Note that this option does break commercial software. Yoshi's Island in
particular. This game is setting A15 on some PPU register writes, but
not on others. The end result of this is things break horribly in-game.
Also, this option is causing a very tiny speed hit for obvious reasons
with the variable masking value (I'm even using size-1 for now.) Given
how niche this is, I may just leave it a compile-time constant to avoid
the overhead cost. Otherwise, if we keep the option, then it'll go into
Super Famicom.sys/manifest.bml ... I'll flesh that out in the near-future.
----
Finally, some fun for my OCD ... my monitor suddenly cut out on me
in the middle of working on this WIP, about six hours in of non-stop
work. Had to hit a bunch of ctrl+alt+fN commands (among other things)
and trying to log in headless on another TTY to do issue commands,
trying to recover the display. Finally power cycled the monitor and it
came back up. So all my typing ended up going to who knows where.
Usually this sort of thing terrifies me enough that I scrap a WIP and
start over to ensure I didn't screw anything up during the crashed screen
when hitting keys randomly.
Obviously, everything compiles and appears to work fine. And I know
it's extremely paranoid, but OCD isn't logical, so ... I'm going
to go over every line of the 100KiB r07->r08 diff looking for any
corruption/errors/whatever.
----
Review finished.
r08 diff review notes:
- fc/controller/gamepad/gamepad.cpp:
use uint device = ID::Device::Gamepad; not id = ...;
- gb/cartridge/cartridge.hpp:
remove redundant uint _pathID; (in Information::pathID already)
- gb/cartridge/cartridge.hpp:
pull sha256 inside Information
- sfc/cartridge/load/cpp:
add " - Slot (A,B)" to interface->load("Sufami Turbo"); to be more
descriptive
- sfc/controller/gamepad/gamepad.cpp:
use uint device = ID::Device::Gamepad; not id = ...;
- sfc/interface/interface.cpp:
remove n variable from the Multitap device input generation loop
(now unused)
- sfc/interface/interface.hpp:
put struct Port above struct Device like the other classes
- ui-tomoko:
cheats.bml is reading from/writing to mediumPaths(0) [system folder
instead of game folder]
- ui-tomoko:
instead of mediumPaths(1) - call emulator->metadataPathID() or something
like that
byuu says:
Changelog:
- (hopefully) fixed BS Memory and Sufami Turbo slot loading
- ported GB, GBA, WS cores to use nall/vfs
- completely removed loadRequest, saveRequest functionality from
Emulator::Interface and ui-tomoko
- loadRequest(folder) is now load(folder)
- save states now use a shared Emulator::SerializerVersion string
- whenever this is bumped, all older states will break; but this makes
bumping state versions way easier
- also, the version string makes it a lot easier to identify
compatibility windows for save states
- SNES PPU now uses uint16 vram[32768] for memory accesses [hex_usr]
NOTE: Super Game Boy loading is currently broken, and I'm not entirely
sure how to fix it :/
The file loading handoff was -really- complicated, and so I'm kind of
at a loss ... so for now, don't try it.
Everything else should theoretically work, so please report any bugs
you find.
So, this is pretty much it. I'd be very curious to hear feedback from
people who objected to the old nall/stream design, whether they are
happy with the new file loading system or think it could use further
improvements.
The 16-bit VRAM turned out to be a wash on performance (roughly the same
as before. 1fps slower on Zelda 3, 1fps faster on Yoshi's Island.) The
main reason for this was because Yoshi's Island was breaking horribly
until I changed the vramRead, vramWrite functions to take uint15 instead
of uint16.
I suspect the issue is we're using uint16s in some areas now that need
to be uint15, and this game is setting the VRAM address to 0x8000+,
causing us to go out of bounds on memory accesses.
But ... I want to go ahead and do something cute for fun, and just because
we can ... and this new interface is so incredibly perfect for it!! I
want to support an SNES unit with 128KiB of VRAM. Not out of the box,
but as a fun little tweakable thing. The SNES was clearly designed to
support that, they just didn't use big enough VRAM chips, and left one
of the lines disconnected. So ... let's connect it anyway!
In the end, if we design it right, the only code difference should be
one area where we mask by 15-bits instead of by 16-bits.
byuu says:
Changelog:
- Super Famicom core converted to use nall/vfs
- excludes Super Game Boy; since that's invoked from inside the GB core
This was definitely the major obstacle to test nall/vfs'
applicability. Things worked out pretty great in the end.
We went from 22.0KiB (cartridge) + 18.6KiB (interface) to 24.5KiB
(cartridge) + 11.4KiB (interface). Or 40.7KiB to 36.0KiB. This removes
a very large source of indirection. Before it was: "coprocessor <=>
cartridge <=> interface" for loading and saving data, and now it's just
"coprocessor <=> cartridge". And it may make sense to eventually turn
this into just "cartridge -> coprocessor" by making each coprocessor
class handle its own markup parsing.
It's nice to have all the manifest parsing in one location (well, sans
MSU1); but it's also nice for loading/unloading to be handled by each
coprocessor itself. So I'll have to think longer about that one.
I've also started handling Interface::save() differently. Instead of
keeping track of memory IDs and filenames, and iterating through that
vector of objects ... instead I now have a system that mirrors the markup
parsing on loading, but handles saving instead. This was actually the
reason the code size savings weren't more significant, but I like this
style more. As before, it removes an extra level of indirection.
So ... next up, I need to port over the GB, then GBA, then WS
cores. These shouldn't take too long since they're all very simple with
just ROM+RAM(+RTC) right now. Then get the SGB callbacks using vfs. Then
after that, gut all the old stream stuff from nall and higan. Kill the
(load,save)Request stuff, rename the load(Gamepak)Request to something
simpler, and then we should be good.
Anyway ... these are some huge changes.
byuu says:
Changelog:
- lots of code cleanups to processor/r6502 (the switch.cpp file is only
halfway done ...)
- lots of code cleanups to fc/cpu
- removed fc/input
- implemented fc/controller
hex_usr, you may not like this, but I want to keep the controller port
and expansion port interface separate, like I do with the SNES. I realize
the NES' is used more for controllers, and the SNES' more for hardware
expansions, but ... they're not compatible pinouts and you can't really
connect one to the other.
Right now, I've only implemented the controller portion. I'll have to
get to the peripheral portion later.
Also, the gamepad implementation there now may be wrong. It's based off
the Super Famicom version obviously. I'm not sure if the Famicom has
different behavior with latching $4016 writes, or not. But, it works in
Mega Man II, so it's a start.
Everyone, be sure to remap your controls, and then set port 1 -> gamepad
after loading your first Famicom game with the new WIP.
byuu says:
Changelog:
- finished cleaning up the SFC core to my new coding conventions
- removed sfc/controller/usart (superseded by 21fx)
- hid Synchronize Video option from the menu (still in the configuration
file)
Pretty much the only minor detail left is some variable names in the
SA-1 core that really won't look good at all if I move to camelCase,
so I'll have to rethink how I handle those. It's probably a good area
to attempt using BitFields, to see how it impacts performance. But I'll
do that in a test branch first.
But for the most part, this should be the end of the gigantic diffs (this
one was 174KiB), at least for the SFC/WS cores. Still have the FC/GB/GBA
cores to clean up more fully. Assuming we don't spot any new regressions,
we should be ~95% out of the woods on code cleanups breaking things.
byuu says:
Changelog:
- massive cleanups and optimizations on the PPU core
- ~9% speedup over v099 official
This is pretty much it for the low-hanging fruit of speeding up higan. Any
more gains from this point will be extremely hard-fought, unfortunately.
byuu says:
Time for a new release. There are a few important emulation improvements
and a few new features; but for the most part, this release focuses on
major code refactoring, the details of which I will mostly spare you.
The major change is that, as of v099, the SNES balanced and performance
cores have been removed from higan. Basically, in addition to my five
other emulation cores, these were too much of a burden to maintain. And
they've come along as far as I was able to develop them. If you need to
use these cores, please use these two from the v098 release.
I'm very well aware that ~80% of the people using higan for SNES
emulation were using the two removed profiles. But they simply had
to go. Hopefully in the future, we can compensate for their loss by
increasing the performance of the accuracy core.
Changelog (since v098):
SFC: balanced profile removed
SFC: performance profile removed
SFC: expansion port devices can now be changed during gameplay (atlhough
you shouldn't)
SFC: fixed bug in SharpRTC leap year calculations
SFC: emulated new research findings for the S-DD1 coprocessor
SFC: fixed CPU emulation-mode wrapping bug with pei, [dp], [dp]+y
instructions [AWJ]
SFC: fixed Super Game Boy bug that caused the bottom tile-row to flicker
in games
GB: added MBC1M (multi-cart) mapper; icarus can't detect these so manual
manifests are needed for now
GB: corrected return value when HuC3 unmapped RAM is read; fixes Robopon
[endrift]
GB: improved STAT IRQ emulation; fixes Altered Space, etc [endrift,
gekkio]
GB: partial emulation of DMG STAT write IRQ bug; fixes Legend of Zerd,
Road Rash, etc
nall: execute() fix, for some Linux platforms that had trouble detecting
icarus
nall: new BitField class; which allows for simplifying flag/register
emulation in various cores
ruby: added Windows WASAPI audio driver (experimental)
ruby: remove attempts to call glSwapIntervalEXT (fixes crashing on some
Linux systems)
ui: timing settings panel removed
video: restored saturation, gamma, luminance settings
video: added new post-emulation sprite system; light gun cursors are
now higher-resolution
audio: new resampler (6th-order Butterworth biquad IIR); quite a bit
faster than the old one
audio: added optional basic reverb filter (for fun)
higan: refresh video outside cooperative threads (workaround for shoddy
code in AMD graphics drivers)
higan: individual emulation cores no longer have unique names
higan: really substantial code refactoring; 43% reduction in binary size
Off the bat, here are the known bugs:
hiro/Windows: focus stealing bug on startup. Needs to be fixed in hiro,
not with a cheap hack to tomoko.
higan/SFC: some of the coprocessors are saving some volatile memory to
disk. Completely harmless, but still needs to be fixed.
ruby/WASAPI: some sound cards have a lot of issues with the current driver
(eg FitzRoy's). We need to find a clean way to fix this before it
can be made the default driver. Which would be a huge win because
the latency improvements are substantial, and in exclusive mode,
WASAPI allows G-sync to work very well.
[From the v099 WIP thread, here's the changelog since v098r19:
- GB: don't force mode 1 during force-blank; fixes v098r16 regression
with many Game Boy games
- GB: only perform the STAT write IRQ bug during vblank, not hblank
(still not hardware accurate, though)
-Ed.]
byuu says:
Changelog:
- added nall/bit-field.hpp
- updated all CPU cores (sans LR35902 due to some complexities) to use
BitFields instead of bools
- updated as many CPU cores as I could to use BitFields instead of union {
struct { uint8_t ... }; }; pairs
The speed changes are mostly a wash for this. In some instances,
I noticed a ~2-3% speedup (eg SNES emulation), and in others a 2-3%
slowdown (eg Famicom emulation.) It's within the margin of error, so
it's safe to say it has no impact.
This does give us a lot of new useful things, however:
- no more manual reconstruction of flag values from lots of left shifts
and ORs
- no more manual deconstruction of flag values from lots of ANDs
- ability to get completely free aliases to flag groups (eg GSU can
provide alt2, alt1 and also alt (which is alt2,alt1 combined)
- removes the need for the nasty order_lsbN macro hack (eventually will
make higan 100% endian independent)
- saves us from insane compilers that try and do nasty things with
alignment on union-structs
- saves us from insane compilers that try to store bit-field bits in
reverse order
- will allow some really novel new use cases (I'm planning an
instant-decode ARM opcode function, for instance.)
- reduces code size (we can serialize flag registers in one line instead
of one for each flag)
However, I probably won't use it for super critical code that's constantly
reading out register values (eg PPU MMIO registers.) I think there we
would end up with a performance penalty.
byuu says:
Changelog:
- hiro: fixed the BrowserDialog column resizing when navigating to new
folders (prevents clipping of filenames)
- note: this is kind of a quick-fix; but I have a good idea how to do
the proper fix now
- nall: added BitField<T, Lo, Hi> class
- note: not yet working on the SFC CPU class; need to go at it with
a debugger to find out what's happening
- GB: emulated DMG/SGB STAT IRQ bug; fixes Zerd no Densetsu and Road Rash
(won't fix anything else; don't get hopes up)
byuu says:
Changelog:
- fixed Super Game Boy regression from v096r04 with bottom tile row
flickering
- fixed GB STAT IRQ regression from previous WIP
- Altered Space is now playable
- GBVideoPlayer isn't; but nobody seems to know exactly what weird
hardware quirk that one relies on to work
- ~3-4% speed improvement in SuperFX games by eliminating function<>
callback on register assignments
- most noticeable in Doom in-game; least noticeable on Yoshi's Island
title screen (darn)
- finished GSU core and SuperFX coprocessor code cleanups
- did some more work cleaning up the LR35902 core and GB CPU code
Just a fair warning: don't get your hopes up on these GB
fixes. Cliffhanger now hangs completely (har har), and none of the
other bugs are fixed. We pretty much did all this work just for Altered
Space. So, I hope you like playing Altered Space.
byuu says:
Changelog:
- GNUmakefile: reverted $(call unique,) to $(strip)
- processor/r6502: removed templates; reduces object size from 146.5kb
to 107.6kb
- processor/lr35902: removed templates; reduces object size from 386.2kb
to 197.4kb
- processor/spc700: merged op macros for switch table declarations
- sfc/coprocessor/sa1: partial cleanups; flattened directory structure
- sfc/coprocessor/superfx: partial cleanups; flattened directory structure
- sfc/coprocessor/icd2: flattened directory structure
- gb/ppu: changed behavior of STAT IRQs
Major caveat! The GB/GBC STAT IRQ changes has a major bug in it somewhere
that's seriously breaking most games. I'm pushing the WIP anyway, because
I believe the changes to be mostly correct. I'd like to get more people
looking at these changes, and also try more heavy-handed hacking and
diff comparison logging between the previous WIP and this one.
byuu says:
Changelog:
- removed template usage from processor/spc700; cleaned up many function
names and the switch table
- object size: 176.8kb => 127.3kb
- source code size: 43.5kb => 37.0kb
- fixed processor/r65816 BRK/COP vector regression [hex_usr]
- corrected HuC3 unmapped RAM read value; fixes Robopon [endrift]
- cosmetic: simplified the butterworth constant calculation
[Wolfram|Alpha]
The SPC700 core changes took forever, about three hours of work.
Only the LR35902 and R6502 still need their template functions
removed. The point of this is that it doesn't cause any speed penalty
to do so, and it results in smaller binary sizes and faster compilation
times.
byuu says:
Changelog:
- improved attenuation of biquad filter by computing butterworth Q
coefficients correctly (instead of using the same constant)
- adding 1e-25 to each input sample into the biquad filters to try and
prevent denormalization
- updated normalization from [0.0 to 1.0] to [-1.0 to +1.0]; volume/reverb
happen in floating-point mode now
- good amount of work to make the base Emulator::Audio support any number
of output channels
- so that we don't have to do separate work on left/right channels;
and can instead share the code for each channel
- Emulator::Interface::audioSample(int16 left, int16 right); changed to:
- Emulator::Interface::audioSample(double* samples, uint channels);
- samples are normalized [-1.0 to +1.0]
- for now at least, channels will be the value given to
Emulator::Audio::reset()
- fixed GUI crash on startup when audio driver is set to None
I'm probably going to be updating ruby to accept normalized doubles as
well; but I'm not sure if I will try and support anything other 2-channel
audio output. It'll depend on how easy it is to do so; perhaps it'll be
a per-driver setting.
The denormalization thing is fierce. If that happens, it drops the
emulator framerate from 220fps to about 20fps for Game Boy emulation. And
that happens basically whenever audio output is silent. I'm probably
also going to make a nall/denormal.hpp file at some point with
platform-specific functionality to set the CPU state to "denormals as
zero" where applicable. I'll still add the 1e-25 offset (inaudible)
as another fallback.
byuu says:
Changelog:
- nall/dsp returns with new iir/biquad.hpp and resampler/cubic.hpp files
- nall/queue.hpp added (simple ring buffer ... nall/vector wouldn't
cause too many moves with FIFO)
- audio streams now only buffer 20ms; so even if multiple audio streams
desync, latency can never exceed 20ms
- replaced blackman windwed sinc FIR hermite audio filter with transposed
direct form II biquadratic sixth-order IIR butterworth filter (better
attenuation of frequencies above 20KHz, faster, no need for decimation,
less code)
- put in experimental eight-tap echo filter (a lot better than what I
had before, but still rather weak)
- substantial cleanups to the SuperFX GSU processor core (slightly
faster, 479KB->100KB object file, 42.7KB->33.4KB source code size,
way less code duplication)
We'll definitely want to test the whole SuperFX library (not many games)
just to make sure there's no regressions caused by this one.
Not sure what I want to do with audio processing effects yet. I've always
really wanted lots of fun controls to customize audio, and now finally
with this new biquad filter, I can finally start implementing real
effects. For instance, an equalizer wouldn't be too complicated anymore.
The new reverb effect is still a poor man's version. I need to find human
readable source for implementing a comb-filter properly. I'm pretty sure
I can already treat nall::queue as an all-pass filter since all that
does is phase shift (fancy audio term for "delay audio"). What's really
going to be hard is figuring out how to expose user-friendly settings for
controlling it. It looks like you need a bunch of coprime coefficients,
and I don't think casual users are going to be able to hand-enter coprime
values to get the echo effect they want. I uh ... don't even know how
to calculate coprime values dynamically right now >_> But we're going
to have to, as they are correlated to the output sampling rate.
We'll definitely want to make some audio profiles so that users can
quickly select pre-configured themes that sound nice, but expose the
underlying coefficients so that they can tweak stuff to their liking. This
isn't just about higan, this is about me trying to learn digital signal
processing, so please don't be too upset about feature creep or anything
on this.
Anyway ... I'm having some difficulties with my audio right now. When
the reverb effect is enabled, there's a bunch of static on system
reset for just a moment. But this should not be possible. nall::queue
is initializing all previous reverb sample elements to 0.0. I don't
understand where static is coming in from. Further, we have the same
issue with both the windowed sinc and the biquad filters ... a bit of
a popping sound when starting a game. Any help tracking this down would
be appreciated.
There's also one really annoying issue ... I can't seem to do reverb
or volume adjustments with normalized samples. If I say "volume *= 0.5"
in higan/audio/audio.cpp line 68, it doesn't just halve the volume, it
adds a whole bunch of distortion. This makes absolutely zero sense to
me. The sample values are between 0.0 (mute) and 1.0 (full volume) here,
so multiplying a double by 0.5 shouldn't cause distortion. So right now,
I'm doing these adjustments with less precision after denormalizing back
to int16. Anyone ever see something like that? :/
byuu says:
Changelog:
- higan/video: added support for Emulator::Sprite
- higan/resource: a new system for accessing embedded binary files
inside the emulation cores; holds the sprites
- higan/sfc/superscope,justifier: re-enabled display of crosshairs
- higan/sfc/superscope: fixed turbo toggle (also shows different
crosshair color when in turbo mode)
- higan/sfc/ppu: always outputs at 512x480 resolution now
- causes a slight speed-hit from ~127fps to ~125fps;
- but allows high-resolution 32x32 cursors that look way better;
- also avoids the need to implement sprite scaling logic
Right now, the PPU code to always output at 480-height is a really gross
hack. Don't worry, I'll make that nicer before release.
Also, superscope.cpp and justifier.cpp are built around a 256x240
screen. But since we now have 512x480, we can make the cursor's movement
much smoother by doubling the resolution on both axes. The actual games
won't see any accuracy improvements when firing the light guns, but the
cursors will animate nicer so I think it's still worth it. I'll work on
that before the next release as well.
The current 32x32 cursors are nicer, but we can do better now with full
24-bit color. So feel free to submit alternatives. I'll probably reject
them, but you can always try :D
The sprites don't support alpha blending, just color keying (0x00000000
= transparent; anything else is 0xff......). We can revisit that later
if necessary.
The way I have it designed, the only files that do anything with
Emulator::Sprite at all are the superscope and justifier folders.
I didn't have to add any hooks anywhere else. Rendering the sprite is
a lot cleaner than the old code, too.
byuu says:
Changelog:
- fixed nall/path.hpp compilation issue
- fixed ruby/audio/xaudio header declaration compilation issue (again)
- cleaned up xaudio2.hpp file to match my coding syntax (12.5% of the
file was whitespace overkill)
- added null terminator entry to nall/windows/utf8.hpp argc[] array
- nall/windows/guid.hpp uses the Windows API for generating the GUID
- this should stop all the bug reports where two nall users were
generating GUIDs at the exact same second
- fixed hiro/cocoa compilation issue with uint# types
- fixed major higan/sfc Super Game Boy audio latency issue
- fixed higan/sfc CPU core bug with pei, [dp], [dp]+y instructions
- major cleanups to higan/processor/r65816 core
- merged emulation/native-mode opcodes
- use camel-case naming on memory.hpp functions
- simplify address masking code for memory.hpp functions
- simplify a few opcodes themselves (avoid redundant copies, etc)
- rename regs.* to r.* to match modern convention of other CPU cores
- removed device.order<> concept from Emulator::Interface
- cores will now do the translation to make the job of the UI easier
- fixed plurality naming of arrays in Emulator::Interface
- example: emulator.ports[p].devices[d].inputs[i]
- example: vector<Medium> media
- probably more surprises
Major show-stoppers to the next official release:
- we need to work on GB core improvements: LY=153/0 case, multiple STAT
IRQs case, GBC audio output regs, etc.
- we need to re-add software cursors for light guns (Super Scope,
Justifier)
- after the above, we need to fix the turbo button for the Super Scope
I really have no idea how I want to implement the light guns. Ideally,
we'd want it in higan/video, so we can support the NES Zapper with the
same code. But this isn't going to be easy, because only the SNES knows
when its output is interlaced, and its resolutions can vary as
{256,512}x{224,240,448,480} which requires pixel doubling that was
hard-coded to the SNES-specific behavior, but isn't appropriate to be
exposed in higan/video.
byuu says:
Changelog:
- fixed major nall/vector/prepend bug
- renamed hiro/ListView to hiro/TableView
- added new hiro/ListView control which is a simplified abstraction of
hiro/TableView
- updated higan's cheat database window and icarus' scan dialog to use
the new ListView control
- compilation works once again on all platforms (Windows, Cocoa, GTK,
Qt)
- the loki skeleton compiles once again (removed nall/DSP references;
updated port/device ID names)
Small catch: need to capture layout resize events internally in Windows
to call resizeColumns. For now, just resize the icarus window to get it
to use the full window width for list view items.
byuu says:
Changelog:
- nall/vector rewritten from scratch
- higan/audio uses nall/vector instead of raw pointers
- higan/sfc/coprocessor/sdd1 updated with new research information
- ruby/video/glx and ruby/video/glx2: fuck salt glXSwapIntervalEXT!
The big change here is definitely nall/vector. The Windows, OS X and Qt
ports won't compile until you change some first/last strings to
left/right, but GTK will compile.
I'd be really grateful if anyone could stress-test nall/vector. Pretty
much everything I do relies on this class. If we introduce a bug, the
worst case scenario is my entire SFC game dump database gets corrupted,
or the byuu.org server gets compromised. So it's really critical that we
test the hell out of this right now.
The S-DD1 changes mean you need to update your installation of icarus
again. Also, even though the Lunar FMV never really worked on the
accuracy core anyway (it didn't initialize the PPU properly), it really
won't work now that we emulate the hard-limit of 16MiB for S-DD1 games.
byuu says:
Changelog:
- GB: support modeSelect and RAM for MBC1M (Momotarou Collection)
- audio: implemented native resampling support into Emulator::Stream
- audio: removed nall::DSP completely
Unfortunately, the new resampler didn't turn out quite as fast as I had
hoped. The final hermite resampling added some overhead; and I had to
bump up the kernel count to 500 from 400 to get the buzzing to go away
on my main PC. I think that's due to it running at 48000hz output
instead of 44100hz output, maybe?
Compared to Ryphecha's:
(NES) Mega Man 2: 167fps -> 166fps
(GB) Mega Man II: 224fps -> 200fps
(WSC) Riviera: 143fps -> 151fps
Odd that the WS/WSC ends up faster while the DMG/CGB ends up slower.
But this knocks 922 lines down to 146 lines. The only files left in all
of higan not written (or rewritten) by me are ruby/xaudio2.h and
libco/ppc.c
byuu says:
Changelog:
- emulation cores now refresh video from host thread instead of
cothreads (fix AMD crash)
- SFC: fixed another bug with leap year months in SharpRTC emulation
- SFC: cleaned up camelCase on function names for
armdsp,epsonrtc,hitachidsp,mcc,nss,sharprtc classes
- GB: added MBC1M emulation (requires manually setting mapper=MBC1M in
manifest.bml for now, sorry)
- audio: implemented Emulator::Audio mixer and effects processor
- audio: implemented Emulator::Stream interface
- it is now possible to have more than two audio streams: eg SNES
+ SGB + MSU1 + Voicer-Kun (eventually)
- audio: added reverb delay + reverb level settings; exposed balance
configuration in UI
- video: reworked palette generation to re-enable saturation, gamma,
luminance adjustments
- higan/emulator.cpp is gone since there was nothing left in it
I know you guys are going to say the color adjust/balance/reverb stuff
is pointless. And indeed it mostly is. But I like the idea of allowing
some fun special effects and configurability that isn't system-wide.
Note: there seems to be some kind of added audio lag in the SGB
emulation now, and I don't really understand why. The code should be
effectively identical to what I had before. The only main thing is that
I'm sampling things to 48000hz instead of 32040hz before mixing. There's
no point where I'm intentionally introducing added latency though. I'm
kind of stumped, so if anyone wouldn't mind taking a look at it, it'd be
much appreciated :/
I don't have an MSU1 test ROM, but the latency issue may affect MSU1 as
well, and that would be very bad.
byuu says:
Changelog:
- WS/WSC: re-added support for screen rotation (code is inside WS core)
- ruby: changed sample(uint16_t left, uint16_t right) to sample(int16_t
left, int16_t right);
- requires casting to uint prior to shifting in each driver, but
I felt it was misleading to use uint16_t just to avoid that
- ruby: WASAPI is now built in by default; has wareya's improvements,
and now supports latency adjust
- tomoko: audio settings panel has new "Exclusive Mode" checkbox for
WASAPI driver only
- note: although the setting *does* take effect in real-time, I'd
suggest restarting the emulator after changing it
- tomoko: audio latency can now be set to 0ms (which in reality means
"the minimum supported by the driver")
- all: increased cothread size from 512KiB to 2MiB to see if it fixes
bullshit AMD driver crashes
- this appears to cause a slight speed penalty due to cache locality
going down between threads, though
byuu says:
Changelog:
- SFC: fixed behavior of 21fx $21fe register when no device is connected
(must return zero)
- SFC: reduced 21fx buffer size to 1024 bytes in both directions to
mirror the FT232H we are using
- SFC: eliminated dsp/modulo-array.hpp [1]
- higan: implemented higan/video interface and migrated all cores to it
[2]
[1] the echo history buffer was 8-bytes, so there was no need for it at
all here. Not sure what I was thinking. The BRR buffer was 12-bytes, and
has very weird behavior ... but there's only a single location in the
code where it actually writes to this buffer. It's much easier to just
write to the buffer three times there instead of implementing an entire
class just to abstract away two lines of code. This change actually
boosted the speed from ~124.5fps to around ~127.5fps, but that's within
the margin of error for GCC. I doubt it's actually faster this way.
The DSP core could really use a ton of work. It comes from a port of
blargg's spc_dsp to my coding style, but he was extremely fond of using
32-bit signed integers everywhere. There's a lot of opportunity to
remove red tape masking by resizing the variables to their actual state
sizes.
I really need to find where I put spc_dsp6.sfc from blargg. It's a great
test to verify if I've made any mistakes in my implementation that would
cause regressions. Don't suppose anyone has it?
[2] so again, the idea is that higan/audio and higan/video are going to
sit between the emulation cores and the user interfaces. The hope is to
output raw encoding data from the emulation cores without having to
worry about the video display format (generally 24-bit RGB) of the host
display. And also to avoid having to repeat myself with eg three
separate implementations of interframe blending, and so on.
Furthermore, the idea is that the user interface can configure its side
of the settings, and the emulation cores can configure their sides.
Thus, neither has to worry about the other end. And now we can spin off
new user interfaces much easier without having to mess with all of these
things.
Right now, I've implemented color emulation, interframe blending and
SNES horizontal color bleed. I did not implement scanlines (and
interlace effects for them) yet, but I probably will at some point.
Further, for right now, the WonderSwan/Color screen rotation is busted
and will only show games in the horizontal orientation. Obviously this
must be fixed before the next official release, but I'll want to think
about how to implement it.
Also, the SNES light gun pointers are missing for now.
Things are a bit messy right now as I've gone through several revisions
of how to handle these things, so a good house cleaning is in order once
everything is feature-complete again. I need to sit down and think
through how and where I want to handle things like light gun cursors,
LCD icons, and maybe even rasterized text messages.
And obviously ... higan/audio is still just nall::DSP's headers. I need
to revamp that whole interface. I want to make it quite powerful with
a true audio mixer so I can handle things like
SNES+SGB+MSU1+Voicer-Kun+SNES-CD (five separate audio streams at once.)
The video system has the concept of "effects" for things like color
bleed and interframe blending. I want to extend on this with useful
other effects, such as NTSC simulation, maybe bringing back my mini-HQ2x
filter, etc. I'd also like to restore the saturation/gamma/luma
adjustment sliders ... I always liked allowing people to compensate for
their displays without having to change settings system-wide. Lastly,
I've always wanted to see some audio effects. Although I doubt we'll
ever get my dream of CoreAudio-style profiles, I'd like to get some
basic equalizer settings and echo/reverb effects in there.
byuu says:
It took several hours, but I've rebuilt much of the SNES' bus memory
mapping architecture.
The new design unifies the cartridge string-based mapping
("00-3f,80-bf:8000-ffff") and internal bus.map calls. The map() function
now has an accompanying unmap() function, and instead of a fixed 256
callbacks, it'll scan to find the first available slot. unmap() will
free slots up when zero addresses reference a given slot.
The controllers and expansion port are now both entirely dynamic.
Instead of load/unload/power/reset, they only have the constructor
(power/reset/load) and destructor (unload). What this means is you can
now dynamically change even expansion port devices after the system is
loaded.
Note that this is incredibly dangerous and stupid, but ... oh well. The
whole point of this was for 21fx. There's no way to change the expansion
port device prior to loading a game, but if the 21fx isn't active, then
the reset vector hijack won't work. Now you can load a 21fx game, change
the expansion port device, and simply reset the system to active the
device.
The unification of design between controller port devices and expansion
port devices is nice, and overall this results in a reduction of code
(all of the Mapping stuff in Cartridge is gone, replaced with direct bus
mapping.) And there's always the potential to expand this system more in
the future now.
The big missing feature right now is the ability to push/pop mappings.
So if you look at how the 21fx does the reset vector, you might vomit
a little bit. But ... it works.
Also changed exit(0) to _exit(0) in the POSIX version of nall::execute.
[The _exit(0) thing is an attempt to make higan not crash when it tries
to launch icarus and it's not on $PATH. The theory is that higan forks,
then the child tries to exec icarus and fails, so it exits, all the
unique_ptrs clean up their resources and tell the X server to free
things the parent process is still using. Calling _exit() prevents
destructors from running, and seems to prevent the problem. -Ed.]
byuu says:
Changelog:
- SFC: fixed a regression on auto joypad polling due to missing
parentheses
- SFC: exported new PPU::vdisp() const -> uint; function [1]
- SFC: merged PPU MMIO functions into the read/write handles (as
I previously did for the CPU)
- higan: removed individual emulator core names (bnes, bsnes, bgb, bgba,
bws) [2] Forgot:
- to remove /tomoko from the about dialog
[1] note that technically I was relying on the cached, per-frame
overscan setting when the CPU and light guns were polling the number of
active display scanlines per frame. This was technically incorrect as
you can change this value mid-frame and it'll kick in. I've never seen
any game toggle overscan every frame, we only know about this because
anomie tested this a long time ago. So, nothing should break, but ...
you know how the SNES is. You can't even look at the code without
something breaking, so I figured I'd mention it >_>
[2] I'll probably keep referring to the SNES core as bsnes anyway.
I don't mind if you guys use the b<system> names as shorthand. The
simplification is mostly to make the branding easier.
byuu says:
Changelog:
- SFC: balanced profile removed
- SFC: performance profile removed
- SFC: code for handling non-threaded CPU, SMP, DSP, PPU removed
- SFC: Coprocessor, Controller (and expansion port) shared Thread code
merged to SFC::Cothread
- Cothread here just means "Thread with CPU affinity" (couldn't think
of a better name, sorry)
- SFC: CPU now has vector<Thread*> coprocessors, peripherals;
- this is the beginning of work to allow expansion port devices to be
dynamically changed at run-time
- ruby: all audio drivers default to 48000hz instead of 22050hz now if
no frequency is assigned
- note: the WASAPI driver can default to whatever the native frequency
is; doesn't have to be 48000hz
- tomoko: removed the ability to change the frequency from the UI (but
it will display the frequency used)
- tomoko: removed the timing settings panel
- the goal is to work toward smooth video via adaptive sync
- the model is broken by not being in control of the audio frequency
anyway
- it's further broken by PAL running at 50hz and WSC running at 75hz
- it was always broken anyway by SNES interlace timing varying from
progressive timing
- higan: audio/ stub created (for now, it's just nall/dsp/ moved here
and included as a header)
- higan: video/ stub created
- higan/GNUmakefile: now includes build rules for essential components
(libco, emulator, audio, video)
The audio changes are in preparation to merge wareya's awesome WASAPI
work without the need for the nall/dsp resampler.
byuu says:
This release most notably adds WonderSwan and WonderSwan Color
emulation.
It is also the final release that will include the balanced and
performance profiles for bsnes.
Changelog (since v097):
- higan: added WonderSwan and WonderSwan Color emulation
- higan: simplified the coooperative-thread schedulers for all emulation
cores
- higan: moved from native (u)int[8,16,32,64]_t types to
Natural<T>/Integer<T> classes
- higan: major cleanups to the Makefiles; including auto-selection of
processor cores
- loki: very barebones skeleton in place now; does absolutely nothing
- these allow the removal of huge amounts of manual bit-twiddling with
more readable alternatives
- FC: fixed PPU OAM reads (mask the correct bits when writing) [hex_usr]
- SFC: fixed expansion port device mapping on game load
- SFC: reworked the way SGB games were loaded -* SFC core can now be
compiled without GB core (and thus without SGB support)
- SFC: added Super Disc expansion port device (although it's just
a non-functional skeleton so far)
- SFC: bugfix to SharpRTC emulation regarding leap year extra day counts
(Dai Kaijuu Monogatari II)
- SFC: major code cleanups to the CPU core and the R65816 processor base
class
- SFC: added 21fx emulation (not the old 21fx that became MSu1; reusing
the name for a new idea)
- basic idea is to move the serial USART to the expansion port along
with a reset vector hijack
- SFC: emulate reset vector pushing PC onto the stack on system soft
reset
- GB: pass gekkio's if_ie_registers and boot_hwio-G test ROMs
- GBA: reworked all handling of MMIO functions: removed the get/set
class functions
- nall: improved edge case return values for
(basename,pathname,dirname,...)
- ruby: fixed ~AudioXAudio2() typo (now calls destructor on exit)
- ruby: if DirectSoundCreate fails (no sound device present), return
false from init instead of crashing
- tomoko: added "All" option to filetype dropdown for ROM loading
- allows loading GBC games in SGB mode
- tomoko: locate() updated to search multiple paths [2]
- tomoko: fixed some oddities when changing the audio frequency/latency
settings
- icarus: can now work with WonderSwan and WonderSwan Color games
Note 1: 90% of the changelog for this release was related to the
WonderSwan emulation being in development. Doesn't make a lot of sense
to post about fixes since the code didn't exist publicly prior to this
release.
byuu says:
Changelog:
- bsnes-accuracy emulates reset vector properly[1]
- bsnes-balanced compiles once more
- bsnes-performance compiles once more
The balanced and performance profiles are fixed for the last time. They
will be removed for v098r01.
Please test this WIP as much as you can. I intend to release v098 soon.
I know save states are a little unstable for the WS/WSC, but they work
well enough for a release. If I can't figure it out soon, I'm going to
post v098 anyway.
[1] this one's been a really long time coming, but ... one of the bugs
I found when I translated Tekkaman Blade was that my translation patch
would crash every now and again when you hit the reset button on a real
SNES, but it always worked upon power on.
Turns out that while power-on initializes the stack register to $01ff,
reset does things a little bit differently. Reset actually triggers the
reset interrupt vector after putting the CPU into emulation mode, but it
doesn't initialize the stack pointer. The net effect is that the stack
high byte is set to $01, and the low byte is left as it was. And then
the reset vector runs, which pushes the low 16-bits of the program
counter, plus the processor flags, onto the stack frame. So you can
actually tell where the game was at when the system was reset ... sort
of.
It's a really weird behavior to be sure. But here's the catch: say
you're hacking a game, and so you hook the reset vector with jsl
showMyTranslationCreditsSplashScreen, and inside this new subroutine,
you then perform whatever bytes you hijacked, and then initialize the
stack frame to go about your business drawing the screen, and when
you're done, you return via rtl.
Generally, this works fine. But if S={0100, 0101, or 0102}, then the
stack will wrap due to being in emulation mode at reset. So it will
write to {0100, 01ff, 01fe}. But now in your subroutine, you enable
native mode. So when you return from your subroutine hijack, it reads
the return address from {01ff, 0200, 0201} instead of the expected
{01ff, 0100, 0101}. Thus, you get an invalid address back, and you
"return" to the wrong location, and your program dies.
The odds of this happening depend on how the game handles S, but
generally speaking, it's a ~1:85 chance.
By emulating this behavior, I'll likely expose this bug in many ROM
hacks that do splash screen hooks like this, including my own Tekkaman
Blade translation. And it's also very possible that there are commercial
games that screw this up as well.
But, it's what the real system does. So if any crashes start happening
as of this WIP upon resetting the game, well ... it'd happen on real
hardware, too.
byuu says:
Changelog:
- WS: fixed sprite window clipping (again)
- WS: don't set IRQ status bits of IRQ enable bits are clear
- SFC: signed/unsigned -> int/uint for DSP core
- SFC: removed eBoot
- SFC: added 21fx (not the same as the old precursor to MSU1; just
reusing the name)
Note: XI Little doesn't seem to be fixed after all ... but the other
three are. So I guess we're at 13 bugs :( And holy shit that music when
you choose a menu option is one of the worst sounds I've ever heard in
my life >_<
byuu says:
Changelog:
- fixed DAS instruction (Judgment Silversword score)
- fixed [VH]TMR_FREQ writes (Judgement Silversword audio after area 20)
- fixed initialization of SP (fixes seven games that were hanging on
startup)
- added SER_STATUS and SER_DATA stubs (fixes four games that were
hanging on startup)
- initialized IEEP data (fixes Super Robot Taisen Compact 2 series)
- note: you'll need to delete your internal.com in WonderSwan
(Color).sys folders
- fixed CMPS and SCAS termination condition (fixes serious bugs in four
games)
- set read/writeCompleted flags for EEPROM status (fixes Tetsujin 28
Gou)
- major code cleanups to SFC/R65816 and SFC/CPU
- mostly refactored disassembler to output strings instead of using
char* buffer
- unrolled all the subfolders on sfc/cpu to a single directory
- corrected casing for all of sfc/cpu and a large portion of
processor/r65816
I kind of went overboard on the code cleanup with this WIP. Hopefully
nothing broke. Any testing one can do with the SFC accuracy core would
be greatly appreciated.
There's still an absolutely huge amount of work left to go, but I do
want to eventually refresh the entire codebase to my current coding
style, which is extremely different from stuff that's been in higan
mostly untouched since ~2006 or so. It's dangerous and fickle work, but
if I don't do it, then the code will be a jumbled mess of several
different styles.
byuu says:
Changelog: (all WSC unless otherwise noted)
- fixed LINECMP=0 interrupt case (fixes FF4 world map during airship
sequence)
- improved CPU timing (fixes Magical Drop flickering and FF1 battle
music)
- added per-frame OAM caching (fixes sprite glitchiness in Magical Drop,
Riviera, etc.)
- added RTC emulation (fixes Dicing Knight and Judgement Silversword)
- added save state support
- added cheat code support (untested because I don't know of any cheat
codes that exist for this system)
- icarus: can now detect games with RTC chips
- SFC: bugfix to SharpRTC emulation (Dai Kaijuu Monogatari II)
- ( I was adding the extra leap year day to all 12 months instead of
just February ... >_< )
Note that the RTC emulation is very incomplete. It's not really
documented at all, and the two games I've tried that use it never even
ask you to set the date/time (so they're probably just using it to count
seconds.) I'm not even sure if I've implement the level-sensitive
behavior correctly (actually, now that I think about it, I need to mask
the clear bit in INT_ACK for the level-sensitive interrupts ...)
A bit worried about the RTC alarm, because it seems like it'll fire
continuously for a full minute. Or even if you turn it off after it
fires, then that doesn't seem to be lowering the line until the next
second ticks on the RTC, so that likely needs to happen when changing
the alarm flag.
Also not sure on this RTC's weekday byte. On the SharpRTC, it actually
computes this for you. Because it's not at all an easy thing to
calculate yourself in 65816 or V30MZ assembler. About 40 lines of code
to do it in C. For now, I'm requiring the program to calculate the value
itself.
Also note that there's some gibberish tiles in Judgement Silversword,
sadly. Not sure what's up there, but the game's still fully playable at
least.
Finally, no surprise: Beat-Mania doesn't run :P
byuu says:
Absolutely major improvements to the WS/C emulation today.
Changelog: (all WS/C related)
- fixed channel 3 sweep pitch adjustment
- fixed channel 3 sweep value sign extension
- removed errant channel 5 speed setting (not what's really going on)
- fixed sign extension on channel 5 samples
- improved DAC mixing of all five audio channels
- fixed r26 regression with PPU timing loop
- fixed sprite windowing behavior (sprite attribute flag is window mode;
not window enable)
- added per-scanline register latching to the PPU
- IRQs should terminate HLT even when the IRQ enable register bits are
clear
- fixed PALMONO reads
- added blur emulation
- added color emulation (based on GBA, so it heavily desaturates colors;
not entirely correct, but it helps a lot)
- no longer decimating audio to 24KHz; running at full 3.072MHz through
the windowed sinc filter [1]
- cleaned up PPU portRead / portWrite functions significantly
- emulated a weird quirk as mentioned by trap15 regarding timer
frequency writes enabling said timers [2]
- emulated LCD_CTRL sleep bit; screen can now be disabled (always draws
black in this case for now)
- improved OAM caching; but it's still disabled because it causes huge
amounts of sprite glitches (unsure why)
- fixed rendering of sprites that wrap around the screen edges back to
the top/left of the display
- emulated keypad interrupts
- icarus: detect orientation bit in game header
- higan: use orientation setting in manifest to set default screen
rotation
[1] the 24KHz -> 3.072MHz sound change is huge. Sound is substantially
improved over the previous WIPs. It does come at a pretty major speed
penalty, though. This is the highest frequency of any system in higan
running through an incredibly (amazing, yet) demanding sinc resampler.
Frame rate dropped from around 240fps to 150fps with the sinc filter on.
If you choose a different audio filter, you'll get most of that speed
back, but audio will sound worse again.
[2] we aren't sure if this is correct hardware behavior or not. It seems
to very slightly help Magical Drop, but not much.
The blur emulation is brutal. It's absolutely required for Riviera's
translucency simulation of selected menu items, but it causes serious
headaches due to the WS's ~75hz refresh rate running on ~60hz monitors
without vsync. It's probably best to leave it off and just deal with the
awful flickering on Riviera's menu options.
Overall, WS/C emulation is starting to get quite usable indeed. Couple
of major bugs that I'd really like to get fixed before releasing it,
though. But they're getting harder and harder to fix ...
Major Bugs:
- Final Fantasy battle background music is absent. Sound effects still
work. Very weird.
- Final Fantasy IV scrolling during airship flight opening sequence is
horribly broken. Scrolls one screen at a time.
- Magical Drop flickers like crazy in-game. Basically unplayable like
this.
- Star Hearts character names don't appear in the smaller dialog box
that pops up.
Minor Bugs:
- Occasional flickering during Riviera opening scenes.
- One-frame flicker of Leda's sprite at the start of the first stage.
byuu says:
Changelog:
- WS: fixed 8-bit sign-extended imul (fixes Star Hearts completely,
Final Fantasy world map)
- WS: fixed rcl/rcr carry shifting (fixes Crazy Climber, others)
- WS: added sound DMA emulation (Star Hearts rain sound for one example)
- WS: added OAM caching, but it's forced every line for now because
otherwise there are too many sprite glitches
- WS: use headphoneEnable bit instead of speakerEnable bit (fixes muted
audio in games)
- WS: various code cleanups (I/O mapping, audio channel naming, etc)
The hypervoice channel doesn't sound all that great just yet. But I'm
not sure how it's supposed to sound. I need a better example of some
more complex music.
What's left are some unknown register status bits (especially in the
sound area), keypad interrupts, RTC emulation, CPU prefetch emulation.
And then it's all just bugs. Lots and lots of bugs that need to be
fixed.
EDIT: oops, bad typo in the code.
ws/ppu/ppu.cpp line 20: change range(256) to range(224).
Also, delete the r.speed stuff from channel5.cpp to make the rain sound
a lot better in Star Hearts. Apparently that's outdated and not what the
bits really do.
byuu says:
Changelog:
- WS: added HblankTimer and VblankTimer IRQs; although they don't appear
to have any effect on any games that use them :/
- WS: added sound emulation; works perfectly in some games (eg Riviera);
is completely silent in most games (eg GunPey)
The sound emulation only partially supports the hypervoice (headphone
only) channel. I need to implement the SDMA before it'll actually do
anything useful. I'm a bit confused about how exactly things work. It
looks like the speaker volume shift and clamp only applies to speaker
mode and not headphone mode, which is very weird. Then there's the
software possibility of muting the headphones and/or the speaker.
Preferably, I want to leave the emulator always in headphone mode for
the extra audio channel. If there are games that force-mute the
headphones, but not speakers, then I may need to force headphones back
on but with the hypervoice channel disabled. I guess we'll see how
things go.
Rough guess is probably that the channels default to enabled after the
IPLROM, and games aren't bothering to manually enable them or something.
byuu says:
Changelog:
- WS: fixed bug when IRQs triggered during a rep string instruction
- WS: added sprite attribute caching (per-scanline); absolutely massive
speed-up
- WS: emulated limit of 32 sprites per scanline
- WS: emulated the extended PPU register bit behavior based on the
DISP_CTRL tile bit-depth setting
- WS: added "Rotate" key binding; can be used to flip the WS display
between horizontal and vertical in real-time
The prefix emulation may not be 100% hardware-accurate, but the edge
cases should be extreme enough to not come up in the WS library. No way
to get the emulation 100% down without intensive hardware testing.
trap15 pointed me at a workflow diagram for it, but that diagram is
impossible without a magic internal stack frame that grows with every
IRQ, and can thus grow infinitely large.
The rotation thing isn't exactly the most friendly set-up, but oh well.
I'll see about adding a default rotation setting to manifests, so that
games like GunPey can start in the correct orientation. After that, if
the LCD orientation icon turns out to be reliable, then I'll start using
that. But if there are cases where it's not reliable, then I'll leave it
to manual button presses.
Speaking of icons, I'll need a set of icons to render on the screen.
Going to put them to the top right on vertical orientation, and on the
bottom left for horizontal orientation. Just outside of the video
output, of course.
Overall, WS is getting pretty far along, but still some major bugs in
various games. I really need sound emulation, though. Nobody's going to
use this at all without that.
byuu says:
Changelog:
- emulated SuperDisc $21e1 basic interface (NEC 4-bit MCU); all hardware
tests pass now (but they don't test much)
- WS/V30MZ: fixed inc/dec reg flag calculation
- WS/V30MZ: fixed lds/les instructions
WS/C compatibility should be way up now. SuperDisc BIOS passes all tests
now (but they only test for the presence of the interface, nothing
more.)
byuu says:
Changelog:
- WS: fixed lods, scas instructions
- WS: implemented missing GRP4 instructions
- WS: fixed transparency for screen one
- WSC: added color-mode PPU rendering
- WS+WSC: added packed pixel mode support
- WS+WSC: added dummy sound register reads/writes
- SFC: added threading to SuperDisc (it's hanging for right now; need to
clear IRQ on $21e2 writes)
SuperDisc Timer and Sound Check were failing before due to not turning
off IRQs on $21e4 clear, so I'm happy that's fixed now.
Riviera starts now, and displays the first intro screen before crashing.
Huge, huge amounts of corrupted graphics, though. This game's really
making me work for it :(
No color games seem fully playable yet, but a lot of monochrome and
color games are now at least showing more intro screen graphics before
dying.
This build defaults to horizontal orientation, but I left the inputs
bound to vertical orientation. Whoops. I still need to implement
a screen flip key binding.
byuu says:
Changelog:
- icarus: WS/C detects RAM type/size heuristically now
- icarus: WS/C uses ram type=$type instead of $type
- WS: use back color instead of white for backdrop
- WS: fixed sprite count limit; removes all the garbled sprites from
GunPey
- WS: hopefully fixed sprite priority with screen 2
- WS: implemented keypad polling; GunPey is now fully playable
- SNES: added Super Disc expansion port device (doesn't do anything,
just for testing)
Note: WS is hard-coded to vertical orientation right now. But there's
basic code in there for all the horizontal stuff.
byuu says:
Changelog:
- WS: fixed a major CPU bug where I was using the wrong bits for
ModR/M's memory mode
- WS: added grayscale PPU emulation (exceptionally buggy)
GunPey now runs, as long as you add:
eeprom name=save.ram size=0x800
to the manifest after importing with icarus.
Right now, you can't control the game due to missing keypad polling.
There's also a lot of glitchiness with the sprites. Seems like they're
not getting properly cleared sometimes or something.
Also, the PPU emulation is totally unrealistic bullshit. I decode and
evaluate every single tile and sprite on every single pixel of output.
No way in hell the hardware could ever come close to that. The speed's
around 500fps without the insane sprite evaluations, and around 90fps
with it. Obviously, I'll fix this in time.
Nothing else seems to run that I've tried. Not even far enough to
display any output whatsoever. Tried Langrisser Millenium, Rockman
& Forte and Riviera. I really need to update icarus to try and encode
eeprom/sram sizes, because that's going to break a lot of stuff if it's
missing.
byuu says:
Changelog:
- fixed nall/windows/guard.hpp
- fixed hiro/(windows,gtk)/header.hpp
- fixed Famicom PPU OAM reads (mask the correct bits when writing)
[hex_usr]
- removed the need for (system := system) lines from higan/GNUmakefile
- added "All" option to filetype dropdown for ROM loading
- allows loading GBC games in SGB mode (and technically non-GB(C)
games, which will obviously fail to do anything)
- loki can load and play game folders now (command-line only) (extremely
unimpressive; don't waste your time :P)
- the input is extremely hacked in as a quick placeholder; not sure
how I'm going to do mapping yet for it
byuu says:
Changelog:
- fixed SNES sprite priority regression from r17
- added nall/windows/guard.hpp to guard against global namespace
pollution (similar to nall/xorg/guard.hpp)
- almost fixed Windows compilation (still accuracy profile only, sorry)
- finished porting all of gba/ppu's registers over to the new .bit,.bits
format ... all GBA registers.cpp files gone now
- the "processors :=" line in the target-$(ui)/GNUmakefile is no longer
required
- processors += added to each emulator core
- duplicates are removed using the new nall/GNUmakefile's $(unique)
function
- SFC core can be compiled without the GB core now
- "-DSFC_SUPERGAMEBOY" is required to build in SGB support now (it's
set in target-tomoko/GNUmakefile)
- started once again on loki (higan/target-loki/) [as before, loki is
Linux/BSD only on account of needing hiro::Console]
loki shouldn't be too horrendous ... I hope. I just have the base
skeleton ready for now. But the code from v094r08 should be mostly
copyable over to it. It's just that it's about 50KiB of incredibly
tricky code that has to be just perfect, so it's not going to be quick.
But at least with the skeleton, it'll be a lot easier to pick away at it
as I want.
Windows compilation fix: move hiro/windows/header.hpp line 18 (header
guard) to line 16 instead.
byuu says:
Changelog:
- ruby: if DirectSoundCreate fails (no sound device present), return
false from init instead of crashing
- nall: improved edge case return values for
(basename,pathname,dirname,...)
- nall: renamed file_system_object class to inode
- nall: varuint_t replaced with VariadicNatural; which contains
.bit,.bits,.byte ala Natural/Integer
- nall: fixed boolean compilation error on Windows
- WS: popa should not restore SP
- GBA: rewrote the CPU/APU cores to use the .bit,.bits functions;
removed registers.cpp from each
Note that the GBA changes are extremely major. This is about five hours
worth of extremely delicate work. Any slight errors could break
emulation in extremely bad ways. Let's hold off on extensive testing
until the next WIP, after I do the same to the PPU.
So far ... endrift's SOUNDCNT_X I/O test is failing, although that code
didn't change, so clearly I messed up SOUNDCNT_H somehow ...
To compile on Windows:
1. change nall/string/platform.hpp line 47 to
return slice(result, 0, 3);
2. change ruby/video.wgl.cpp line 72 to
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
3. add this line to the very top of hiro/windows/header.cpp:
#define boolean FuckYouMicrosoft
byuu says:
Changelog:
- sfc/ppu/sprite updated to use new .bit(s) functions; masked sizes
better; added valid flags instead of using magic numbers
- ws/ppu updates to use new .bit(s) functions
- ws/ppu: added line compare interrupt support
- added ws/eeprom; emulation of WS/WSC internal EEPROM and cartridge
EEPROM (1kbit - 16kbit supported)
- added basic read/write handlers for remaining WS/WSC PPU registers
WS EEPROM emulation is basically a direct copy of trap15's code. Still
some unknown areas in there, but hopefully it's enough to get further
into games that depend on EEPROM support. Note that you'll have to
manually add the eeprom line to the manifest for now, as icarus doesn't
know how to detect EEPROM/sizes yet.
I figured the changes to the SNES PPU sprites would slow it down a tad,
but it actually sped it up. Most of the impact from the integer classes
are gone now.
byuu says:
Got it. Wow, that didn't hurt nearly as much as I thought it was going
to.
Dropped from 127.5fps to 123.5fps to use Natural/Integer for
(u)int(8,16,32,64).
That's totally worth the cost.
byuu says:
This is a few days old, but oh well.
This WIP changes nall,hiro,ruby,icarus back to (u)int(8,16,32,64)_t.
I'm slowly pushing for (u)int(8,16,32,64) to use my custom
Integer<Size>/Natural<Size> classes instead. But it's going to be one
hell of a struggle to get that into higan.
byuu says:
I refactored my schedulers. Added about ten lines to each scheduler, and
removed about 100 lines of calling into internal state in the scheduler
for the FC,SFC cores and about 30-40 lines for the other cores. All of
its state is now private.
Also reworked all of the entry points to static auto Enter() and auto
main(). Where Enter() handles all the synchronization stuff, and main()
doesn't need the while(true); loop forcing another layer of indentation
everywhere.
Took a few hours to do, but totally worth it. I'm surprised I didn't do
this sooner.
Also updated icarus gmake install rule to copy over the database.
byuu says:
Nothing WS-related this time.
First, I fixed expansion port device mapping. On first load, it was
mapping the expansion port device too late, so it ended up not taking
effect. I had to spin out the logic for that into
Program::connectDevices(). This was proving to be quite annoying while
testing eBoot (SNES-Hook simulation.)
Second, I fixed the audio->set(Frequency, Latency) functions to take
(uint) parameters from the configuration file, so the weird behavior
around changing settings in the audio panel should hopefully be gone
now.
Third, I rewrote the interface->load,unload functions to call into the
(Emulator)::System::load,unload functions. And I have those call out to
Cartridge::load,unload. Before, this was inverted, and Cartridge::load()
was invoking System::load(), which I felt was kind of backward.
The Super Game Boy really didn't like this change, however. And it took
me a few hours to power through it. Before, I had the Game Boy core
dummying out all the interface->(load,save)Request calls, and having the
SNES core make them for it. This is because the folder paths and IDs
will be different between the two cores.
I've redesigned things so that ICD2's Emulator::Interface overloads
loadRequest and saveRequest, and translates the requests into new
requests for the SuperFamicom core. This allows the Game Boy code to do
its own loading for everything without a bunch of Super Game Boy special
casing, and without any awkwardness around powering on with no cartridge
inserted.
This also lets the SNES side of things simply call into higher-level
GameBoy::interface->load,save(id, stream) functions instead of stabbing
at the raw underlying state inside of various Game Boy core emulation
classes. So things are a lot better abstracted now.
byuu says:
Alright, well interrupts are in. At least Vblank is.
I also fixed a bug in vector() indexing, MoDRM mod!=3&®==6 using SS
instead of DS, opcodes a0-a3 allowing segment override, and added the
"irq_disable" stuff to the relevant opcodes to suppress IRQs after
certain instructions.
But unfortunately ... still no go on Riviera. It's not reading any
unmapped ports, and although it enables Vblank IRQs and they set port
$b4's status bit, the game never sets the IE flag, so no interrupts ever
actually fire. The game does indeed appear to be sitting in a rather
huge loop, which is probably dependent upon some RAM variable being set
from the Vblank IRQ, but I don't know how I'm supposed to be triggering
it.
... I'm really quite stumped here >_>
byuu says:
All 256 instructions implemented fully. Fixed a major bug with
instructions that both read and write to ModRM with displacement.
Riviera now runs into an infinite loop ... possibly crashed, possibly
waiting on interrupts or in to return something. Added a bunch of PPU
settings registers, but nothing's actually rendering with them yet.
244 of 256 opcodes implemented now, although the interrupt triggering
portions are missing from them still. Much better handling of prefixes
now.
I definitely have a newfound hatepreciation for x86 now >_>
byuu says:
Up to 211 opcodes implemented, with the caveat that the four opcodes
that make up group 3 and group 4 don't do anything yet. Both groups seem
to have some "illegal" instructions in them, so that'll be "fun".
I have a new mechanic in place for opcode prefixes, but it could use
some work still. I also only have it working to override ModRM mem
addressing, but of course it does it in a lot of other places like the
string operations.
Making it about 5.5 million instructions into Gunpey now, but of course
that doesn't mean much. Could be going off the rails at any point due to
CPU bugs or unimplemented ports. Riviera's still crashing.
byuu says:
26 hours in, 173 instructions implemented. Although the four segment
prefix opcodes don't actually do anything yet. There's less than 256
actual instructions on the 80186, not sure of the exact count.
Gunpey gets around ~8,200 instructions in before hitting an unsupported
opcode (loop). Riviera goes off the rails on a retf and ends up
executing an endless stream of bad opcodes in RAM =( Both games hammer
the living shit out of the in/out ports pretty much immediately.
byuu says:
Man, the 80186 is taking a lot longer to implement than I thought it
would. So far I'm 18 hours into this emulator. Whereas I had Super Mario
Bros fully playable (no sound) in 12 hours for the NES >_>
I refactored all the byte/word variant functions to single functions
that take a size parameter. Cuts the amount of code in half.
Also implemented repz/repnz + movsb/movsw, so Riviera now gets 299
instructions in before dying. Nobody really bothers to explain how the
CPU actually implements these instructions, but I think I have it right:
ignore non-string opcodes that follow rep, invoke the string operations
inside the rep opcodes to prevent interrupts from triggering between the
two (which will be even more fun for segment selector overrides ...)
The next opcode needed is 0xC7, which ... throws ModRM on its head. In
this mode, ModRM is only used to determine the target operand (and it
doesn't use the middle bits for that at all), and the source is an
immediate that follows it. Gonna have to waste a few more hours thinking
about how best to handle that.
Also, disabled HiDPI for higan as well on OS X.
byuu says:
More V30MZ implemented, a lot more to go.
icarus now supports importing WS and WSC games. It expects them to have
the correct file extension, same for GB and GBC.
> Ugh, apparently HiDPI icarus doesn't let you press the check boxes.
I set the flag value in the plist to false for now. Forgot to do it for
higan, but hopefully I won't forget before release.
byuu says:
Lots of improvements. We're now able to start executing some V30MZ
instructions. 32 of 256 opcodes implemented so far.
I hope this goes without saying, but there's absolutely no point in
loading WS/WSC games right now. You won't see anything until I have the
full CPU and partial PPU implemented.
ROM bank 2 works properly now, the I/O map is 16-bit (address) x 16-bit
(data) as it should be*, and I have a basic disassembler in place
(adding to it as I emulate new opcodes.)
(* I don't know what happens if you access an 8-bit port in 16-bit mode
or vice versa, so for now I'm just treating the handlers as always being
16-bit, and discarding the upper 8-bits when not needed.)
byuu says:
So, this WIP starts work on something new for higan. Obviously, I can't
keep it a secret until it's ready, because I want to continue daily WIP
releases, and of course, solicit feedback as I go along.
byuu says:
Note: balanced/performance profiles still broken, sorry.
Changelog:
- added nall/GNUmakefile unique() function; used on linking phase of
higan
- added nall/unique_pointer
- target-tomoko and {System}::Video updated to use
unique_pointer<ClassName> instead of ClassName* [1]
- locate() updated to search multiple paths [2]
- GB: pass gekkio's if_ie_registers and boot_hwio-G test ROMs
- FC, GB, GBA: merge video/ into the PPU cores
- ruby: fixed ~AudioXAudio2() typo
[1] I expected this to cause new crashes on exit due to changing the
order of destruction of objects (and deleting things that weren't
deleted before), but ... so far, so good. I guess we'll see what crops
up, especially on OS X (which is already crashing for unknown reasons on
exit.)
[2] right now, the search paths are: programpath(), {configpath(),
"higan/"}, {localpath(), "higan/"}; but we can add as many more as we
want, and we can also add platform-specific versions.
byuu says:
A minor WIP to get us started.
Changelog:
- System::Video merged to PPU::Video
- System::Audio merged to DSP::Audio
- System::Configuration merged to Interface::Settings
- created emulator/emulator.cpp and accompanying object file for shared
code between all cores
Currently, emulator.cpp just holds a videoColor() function that takes
R16G16B16, performs gamma/saturation/luma adjust, and outputs
(currently) A8R8G8B8. It's basically an internal function call for cores
to use when generating palette entries. This code used to exist inside
ui-tomoko/program/interface.cpp, but we have to move it internal for
software display emulation. But in the future, we could add other useful
cross-core functionality here.
byuu says:
This release features improvements to all emulation cores, but most
substantially for the Game Boy core. All of blargg's test ROMs that pass
in gambatte now either pass in higan, or are off by 1-2 clocks (the
actual behaviors are fully emulated.) I consider the Game Boy core to
now be fairly accurate, but there's still more improvements to be had.
Also, what's sure to be a major feature for some: higan now has full
support for loading and playing ordinary ROM files, whether they have
copier headers, weird extensions, or are inside compressed archives. You
can load these games from the command-line, from the main Library menu
(via Load ROM Image), or via drag-and-drop on the main higan window. Of
course, fans of game folders and the library need not worry: that's
still there as well.
Also new, you can drop the (uncompressed) Game Boy Advance BIOS onto the
higan main window to install it into the correct location with the
correct file name.
Lastly, this release technically restores Mac OS X support. However,
it's still not very stable, so I have decided against releasing binaries
at this time. I'd rather not rush this and leave a bad first impression
for OS X users.
Changelog (since v096):
- higan: project source code hierarchy restructured; icarus directly
integrated
- higan: added software emulation of color-bleed, LCD-refresh,
scanlines, interlacing
- icarus: you can now load and import ROM files/archives from the main
higan menu
- NES: fixed manifest parsing for board mirroring and VRC pinouts
- SNES: fixed manifest for Star Ocean
- SNES: fixed manifest for Rockman X2,X3
- GB: enabling LCD restarts frame
- GB: emulated extra OAM STAT IRQ quirk required for GBVideoPlayer
(Shonumi)
- GB: VBK, BGPI, OBPI are readable
- GB: OAM DMA happens inside PPU core instead of CPU core
- GB: fixed APU length and sweep operations
- GB: emulated wave RAM quirks when accessing while channel is enabled
- GB: improved timings of several CPU opcodes (gekkio)
- GB: improved timings of OAM DMA refresh (gekkio)
- GB: CPU uses open collector logic; return 0xFF for unmapped memory
(gekkio)
- GBA: fixed sequencer enable flags; fixes audio in Zelda - Minish Cap
(Jonas Quinn)
- GBA: fixed disassembler masking error (Lioncash)
- hiro: Cocoa support added; higan can now be compiled on Mac OS X 10.7+
- nall: improved program path detection on Windows
- higan/Windows: moved configuration data from %appdata% to
%localappdata%
- higan/Linux,BSD: moved configuration data from ~/.config/higan to
~/.local/higan
byuu says:
Changelog:
- configuration files are now stored in localpath() instead of configpath()
- Video gamma/saturation/luminance sliders are gone now, sorry
- added Video Filter->Blur Emulation [1]
- added Video Filter->Scanline Emulation [2]
- improvements to GBA audio emulation (fixes Minish Cap) [Jonas Quinn]
[1] For the Famicom, this does nothing. For the Super Famicom, this
performs horizontal blending for proper pseudo-hires translucency. For
the Game Boy, Game Boy Color, and Game Boy Advance, this performs
interframe blending (each frame is the average of the current and
previous frame), which is important for things like the GBVideoPlayer.
[2] Right now, this only applies to the Super Famicom, but it'll come to
the Famicom in the future. For the Super Famicom, this option doesn't
just add scanlines, it simulates the phosphor decay that's visible in
interlace mode. If you observe an interlaced game like RPM Racing on
a real SNES, you'll notice that even on perfectly still screens, the
image appears to shake. This option emulates that effect.
Note 1: the buffering right now is a little sub-optimal, so there will
be a slight speed hit with this new support. Since the core is now
generating native ARGB8888 colors, it might as well call out to the
interface to lock/unlock/refresh the video, that way it can render
directly to the screen. Although ... that might not be such a hot idea,
since the GBx interframe blending reads from the target buffer, and that
tends to be a catastrophic option for performance.
Note 2: the balanced and performance profiles for the SNES are
completely busted again. This WIP took 6 1/2 hours, and I'm exhausted.
Very much not looking forward to working on those, since those two have
all kinds of fucked up speedup tricks for non-interlaced and/or
non-hires video modes.
Note 3: if you're on Windows and you saved your system folders somewhere
else, now'd be a good time to move them to %localappdata%/higan
byuu says:
This WIP finally achieves the vision I've had for icarus.
I also fixed a mapping issue with Cx4 that, oddly enough, only caused
the "2" from the Mega Man X2 title screen to disappear.
[Editor's note - "the vision for icarus" was described in a separate,
public forum post: http://board.byuu.org/phpbb3/viewtopic.php?p=20584
Quoting for posterity:
icarus is now a full-fledged part of higan, and will be bundled with
each higan WIP as well. This will ensure that in the future, the
exact version of icarus you need to run higan will be included right
along with it. As of this WIP, physical manifest files are now truly
and entirely optional.
From now on, you can associate your ROM image files with higan's
main binary, or drop them directly on top of it, to load and play
your games.
Furthermore, there are two new menu options that appear under the
library menu when icarus is present:
- "Load ROM File ..." => gives you a single-file selection dialog to
import (and if possible) run the game
- "Import ROM Files ..." => gives you a multi-file import dialog
with checkboxes to pull in multiple games at once
Finally, as before, icarus can generate manifest.bml files for
folders that lack them.
For people who like the game folder and library system, nothing's
changed. Keep using higan as you have been.
For people who hate it, you can now use higan like your classic
emulators. Treat the "Library->{System Name}" entries as your
"favorites" list: the games you actually play. Treat the
"Library->Load ROM" as your standard open file dialog in other
emulators. And finally, treat "Advanced->Game Library" as your save
data path for cheat codes, save states, save RAM, etc.
]
byuu says:
Changelog:
- GB: re-enabling the LCD resets the display to LY=0,LX=0 [1]
- GB: emulated new findings (as of today!) for a DMG quirk that triggers
an extra OAM STAT IRQ when Vblank STAT IRQs are off
- GB: made VBK, BGPI, OBPI readable
- GB: fixed APU length operations
- GB: fixed APU sweep operations
- NES: fixed cartridge/ -> board/ manifest lookups for mirroring/pinous
- hiro/Cocoa: added endrift's plist keys
Fixed:
- Astro Rabby is fully playable, even the title screen works correctly
- Bomb Jack is fully playable
- Kirby's Dream Land 2 intro scrolling first scanline of Rick is now fixed
- GBVideoPlayer functions correctly [2]
- Shin Megami Tensei: Devichil series regression fixed
[1] doesn't pass oam_bug-2/1-lcd_sync; because it seems to want
LY=0,LX>0, and I can't step the PPU in a register write as it's not
a state machine; the effect is emulated, it just starts the frame a tiny
bit sooner. blargg's testing is brutal, you can't be even one cycle off
or the test will fail.
[2] note that you will need the GBC Display Emulation shader from
hunterk's repository, or it will look like absolute shit. The
inter-frame blending is absolutely critical here.
byuu says:
Changelog:
- fixed S-DD1 RAM writes (Star Ocean audio fixed)
- applied all of the DMG test ROM fixes discussed earlier; passes many
more test ROMs now
- at least until the GBVideoPlayer is working: for debugging purposes,
CPU/PPU single-step now instead of sync just-in-time (~30% slower)
- fixed OS X crash on NSTextView (hopefully, would be very odd if not)
Unfortunately passing these test ROMs caused my favorite GB/GBC game to
break all of its graphics =(
Shin Megami Tensei - Devichil - Kuro no Sho (Japan) is all garbled now.
I'm really quite bummed by this ... but I guess I'll go through and
revert r04's fixes one at a time until I find what's causing it.
On the plus side, Astro Rabby is playable now. Still acts weird when
pressing B/A on the first screen, but the start button will start the
game.
EDIT: got it. Shin Megami Tensei - Devichil requires FF4F (VBK) to be
readable. Before, it was always returning 0x00. With my return 0xFF
patch, that broke. But it should be returning the VBK value, which also
fixes it. Also need to handle FF68/FF6A reads. Was really hoping that'd
help GBVideoPlayer too, but nope. It doesn't read any of those three
registers.
byuu says:
Changelog:
- fixed icarus to save settings properly
- fixed higan's full screen toggle on OS X
- increased "Add Codes" button width to avoid text clipping
- implemented cocoa/canvas.cpp
- added 1s delay after mapping inputs before re-enabling the window
(wasn't actually necessary, but already added it)
- fixed setEnabled(false) on Cocoa's ListView and TextEdit widgets
- updated nall::programpath() to use GetModuleFileName on Windows
- GB: system uses open collector logic, so unmapped reads return 0xFF,
not 0x00 (passes blargg's cpu_instrs again) [gekkio]
byuu says:
Warning: this is not for the faint of heart. This is a very early,
unpolished, buggy release. But help testing/fixing bugs would be greatly
appreciated for anyone willing.
Requirements:
- Mac OS X 10.7+
- Xcode 7.2+
Installation Commands:
cd higan
gmake -j 4
gmake install
cd ../icarus
gmake -j 4
gmake install
(gmake install is absolutely required, sorry. You'll be missing key
files in key places if you don't run it, and nothing will work.)
(gmake uninstall also exists, or you can just delete the .app bundles
from your Applications folder, and the Dev folder on your desktop.)
If you want to use the GBA emulation, then you need to drop the GBA BIOS
into ~/Emulation/System/Game\ Boy\ Advance.sys\bios.rom
Usage:
You'll now find higan.app and icarus.app in your Applications folders.
First, run icarus.app, navigate to where you keep your game ROMs. Now
click the settings button at the bottom right, and check "Create
Manifests", and click OK. (You'll need to do this every time you run
icarus because there's some sort of bug on OSX saving the settings.) Now
click "Import", and let it bring in your games into ~/Emulation.
Note: "Create Manifests" is required. I don't yet have a pipe
implementation on OS X for higan to invoke icarus yet. If you don't
check this box, it won't create manifest.bml files, and your games won't
run at all.
Now you can run higan.app. The first thing you'll want to do is go to
higan->Preferences... and assign inputs for your gamepads. At the very
least, do it for the default controller for all the systems you want to
emulate.
Now this is very important ... close the application at this point so
that it writes your config file to disk. There's a serious crashing bug,
and if you trigger it, you'll lose your input bindings.
Now the really annoying part ... go to Library->{System} and pick the
game you want to play. Right now, there's a ~50% chance the application
will bomb. It seems the hiro::pListView object is getting destroyed, yet
somehow the internal Cocoa callbacks are being triggered anyway. I don't
know how this is possible, and my attempts to debug with lldb have been
a failure :(
If you're unlucky, the application will crash. Restart and try again. If
it crashes every single time, then you can try launching your game from
the command-line instead. Example:
open /Applications/higan.app \
--args ~/Emulation/Super\ Famicom/Zelda3.sfc/
Help wanted:
I could really, really, really use some help with that crashing on game
loading. There's a lot of rough edges, but they're all cosmetic. This
one thing is pretty much the only major show-stopping issue at the
moment, preventing a wider general audience pre-compiled binary preview.
byuu says:
Changelog:
- restructured the project and removed a whole bunch of old/dead
directives from higan/GNUmakefile
- huge amounts of work on hiro/cocoa (compiles but ~70% of the
functionality is commented out)
- fixed a masking error in my ARM CPU disassembler [Lioncash]
- SFC: decided to change board cic=(411,413) back to board
region=(ntsc,pal) ... the former was too obtuse
If you rename Boolean (it's a problem with an include from ruby, not
from hiro) and disable all the ruby drivers, you can compile an
OS X binary, but obviously it's not going to do anything.
It's a boring WIP, I just wanted to push out the project structure
change now at the start of this WIP cycle.
byuu says:
Changelog:
- added Cocoa target: higan can now be compiled for OS X Lion
[Cydrak, byuu]
- SNES/accuracy profile hires color blending improvements - fixes
Marvelous text [AWJ]
- fixed a slight bug in SNES/SA-1 VBR support caused by a typo
- added support for multi-pass shaders that can load external textures
(requires OpenGL 3.2+)
- added game library path (used by ananke->Import Game) to
Settings->Advanced
- system profiles, shaders and cheats database can be stored in "all
users" shared folders now (eg /usr/share on Linux)
- all configuration files are in BML format now, instead of XML (much
easier to read and edit this way)
- main window supports drag-and-drop of game folders (but not game files
/ ZIP archives)
- audio buffer clears when entering a modal loop on Windows (prevents
audio repetition with DirectSound driver)
- a substantial amount of code clean-up (probably the biggest
refactoring to date)
One highly desired target for this release was to default to the optimal
drivers instead of the safest drivers, but because AMD drivers don't
seem to like my OpenGL 3.2 driver, I've decided to postpone that. AMD
has too big a market share. Hopefully with v093 officially released, we
can get some public input on what AMD doesn't like.
byuu says:
Changelog:
- you can now drop game folders (not game files, sorry) onto higan's
main window to load them
- audio buffer will clear on Windows when entering modal loop (entering
menu, moving or resizing window)
- this prevents DirectSound driver's audio repetition
- ruby defaults to the optimal driver for each platform, rather than the
safest driver, now
- added Cydrak's gl_Position.zw change to ruby
- added fixes for all the changes to nall, ruby, phoenix over the past
three months
byuu says:
This will be another massive diff from the previous version.
All of higan was updated to use the new foo& bar syntax, and I also
updated switch statements to be consistent as well (but not in the
disassemblers, was starting to get an RSI just from what I already did.)
phoenix/{windows, cocoa, qt} need to be updated to use "string foo"
instead of "const string& foo", and after that, the major diffs should
be finished.
This archive is the first time I'm posting my copy-on-write,
size+capacity nall::string class, so any feedback on that is welcome as
well.
byuu says:
Changelog:
- fixed cartridge load window focus on Windows
- lots of updates to nall, ruby and phoenix
- ethos and Emulator::Interface updated from "foo &bar" to "foo& bar"
syntax (work-in-progress)
Before I had mixed the two ways to declare variables/arguments all over
the place, so the goal is to unify them all for consistency. So the
changelog for this release will be massive (750KB >.>) due to the syntax
change. Yeah, that's what I spent the last three days working on ...
byuu says:
- OpenGL should work on OS X now; it uses VAOs and VBOs, and is fully
OpenGL 3.2 core compliant
- all configuration files are now stored in BML format, instead of CFG
format (half the size, much more readable)
- some old nall libraries that were never used have been removed
- make install works with or without root now (copies core files to
/usr/share/higan [non-configurable])
- make install also works on OS X (copies to /Library/Application
Support/higan)
byuu says:
Changelog:
- added support for ruby shader folders (place in "Video Shaders/")
- higan now also looks in your shared folder for configuration files and
system media folders
- added CFBundleExecutable key to OS X Info.plist
Shared folder locations:
- Windows XP: C:\Documents and Settings\All Users\Application Data\higan
- Windows 7: C:\ProgramData\higan
- OS X: /Library/Application Support/higan
- Linux: /etc/higan
Evaluation order:
- look for item in binary folder: if found, use this folder
- look for item in user folder: if found, use this folder
- look for item in shared folder: if found, use this folder
- create item in user folder
For people repackaging higan for other distros: you should chmod 777
/etc/higan. Failure to do so could result in higan breaking. No, I will
not copy the files from the shared path to the user path.
byuu says:
This release should be polished enough for a general release.
This release should be polished enough for a general release.
Anyone with a real, clean Mac up for posting compiled binaries?
Preferably compile with "make profile=balanced" In fact, I'd like it if
someone were willing to host a "higan for Mac" page, with binaries of
each of the latest releases. Only really needed for major official
releases, but it'd be preferable to have the builds updated as soon as
possible after I post new builds.
Changelog:
- no more keyboard chimes when pressing keys
- status bar added, fully functional
- Label::minimumSize() takes frame into account (but note a few places
hard-code raw Font::size(), so a few text labels are still clipped)
- resizing the main window looks smooth regardless of whether a game is
running or not
- currently, resizing the window pauses the emulation. Allowing it to
run the main loop was lagging out the window resize process too much
to be worth it
Additional OS X integration enhancements:
- closing the main window unloads the current game, but does not quit
the application (quit via the main menu or the dock menu)
- clicking the icon in the dock will (re)display the main menu
byuu says:
This is the first release with full support for OS X, although it's
certainly still very buggy.
Known issues:
- window status bars are still unsupported (they just don't show up)
- you get the bad keypress chime when you use the keyboard
- window geometry and font metrics aren't perfect (bit of clipping here
and there)
- list view headers that aren't auto-sized are sometimes too short (file
browser)
- input assignment is really rough (assigning a key also moves around in
the list or beeps at you)
Custom OS X integration support so far:
- 512x512 ICNS application icon: will look razor-sharp even on a retina
display
- basic Info.plist added to application bundle
- program menu about, preferences, quit all connected
- Settings->Configuration removed (use higan->Preferences instead)
- global menubar
To compile and use this, you'll need:
- Xz Utils (to extract .tar.xz)
- Xcode 4.6
- Lion 10.7.4 or newer
mkdir higan_v092r04
tar -xJf higan_v092r04.tar.xz -C higan_v092r04
cd higan_v092r04
make -j 2
ananke is missing, and I haven't updated purify yet, so you'll have to
move game folders from Windows or Linux over, or make them by hand (a
not so enjoyable experience, to say the least.)
byuu says:
This release adds the phoenix/Cocoa port, and rewrites a lot of the
higan user interface to work with all of the new changes (like blocking
in the main run loop and in modal windows.)
It doesn't yet modify the compilation flags to actually build on OS
X yet, and even then, we don't really have ruby drivers, so there'd be
no video, audio or input.
Two months between a single WIP point release ... for the first six
years, I never went more than a month without a full official release.
I guess I should be happy that it's become so refined, but I sure do
miss those halcyon days of exciting progress.
byuu says:
Changelog:
- merged AWJ's hires color blending improvements (most notably: fixes
Marvelous' text)
- created sfc/base/ to store base unit (expansion port device) emulation
- synchronized the markup of Satellaview and Sufami Turbo cartridge
slots in the board markup
- fixed "Initializing ..." typo in timing settings
If at all possible, I'd really like to have heavy testing of games that
use hires graphics to check for any regressions.
I trust AWJ's code, and all of the test ROMs I have thrown at it all
appear to work great. But better safe than sorry. Same deal for any core
changes, it's a lot better to catch it now than after v093 is released.
byuu says:
higan changelog:
- compiler is set to g++-4.7, subst(cc,++) rule is gone, C files compile
with $(compiler) -x c
- make throws an error when you specify an invalid profile or compile on
an unsupported platform (instead of hanging forever)
- added unverified.png to resources (causes too big of a speed hit to
actually check for folder/unverified file ... so disabled for now)
- fixed default browser paths for Game Boy, Sufami Turbo and BS-X
Satellaview (have to delete paths.cfg to see this)
- browser home button seeks to configpath()/higan/library.cfg
- settings->driver is now settings->advanced, and it adds game library
path setting and profile information
- emulation cores now load manifest files internally, manifest.bml is
not required for a game folder to be recognized by higan as such
- BS-X Satellaview and Sufami Turbo slot cartridge handling moved out of
sfc/chip and into sfc/slot
- Video::StartFullScreen only sets fullscreen when a game is specified
on the command-line
purify and ananke changelog:
- library output path shown in purify window
- added button to change library path
- squelch firmware warning windows to prevent multi-threading crash, but
only via purify (they show up in higan still)
In the release thread, byuu says:
The first official release of higan has been posted. higan is the
new name for bsnes, and it continues with the latter's version
numbering.
Note that as of now, bsnes still exists. It's a module distributed
inside of higan. bsnes is now specific to my SNES emulator.
Due to last minute changes to the emulator interface, and missing
support in ananke, I wasn't able to include Cydrak's Nintendo DS
emulator dasShiny in this build, but I hope to do so in the next
release.
http://code.google.com/p/higan/downloads/list
For both new and experienced users, please read the higan user guide
first:
http://byuu.org/higan/user-guide
In the v091 WIP thread, byuu says:
r15->r16:
- BS-X MaskROM handling (partial ... need to split bsx/flash away
from sfc/chip, restructure code - it requires tagging the base
cart markup for now, but it needs to parse the slotted cart
markup)
- phoenixflags / phoenixlink += -m32
- nall/sort stability
- if(input.poll(scancode[activeScancode]) == false) return;
- MSU1 / USART need to use interface->path(1)
- MSU1 needs to use Markup::Document, not XML::Document
- case-insensitive folder listings
- remove nall/emulation/system.hpp files (move to ananke)
- remove rom/ram id= checks with indexing
X have cores ask for manifest.bml (skipped for v092's release, too
big a change)
- rename compatibility profile to balanced (so people don't assume
it has better compatibility than accuracy)
byuu says:
Changelog:
- all media types always show base name in the title now (eg Super Game
Boy + Mega Man II)
- Game Boy loading via ananke has been fixed
- phoenix is dynamically linked on Windows now (needed for ananke)
- Linux port shows the higan program icon (once you install the program
to get the bitmap into /usr/local/share/pixmaps)
- paths.cfg defaults to "userpath()/Emulation/System Name/" when it is
created from scratch
[Later, after the v092 release, byuu posted this additional changelog:
- new compilation rules for win32
- OS::setName
- default to ~/Emulation/media.name for paths.cfg
]
byuu says:
higan changelog:
- generates title displayed in emulator window by asking the core
- core builds title solely from "information/title" ... if it's not
there, you don't get a title at all
- sub-system load menu is gone ... since there are multiple revisions of
the SGB, this never really worked well anyway
- to load an SGB, BS-X or ST cartridge, load the base cartridge first
- "File->Load Game" moved to "Load->Import Game" ... may cause a bit of
confusion to new users, but I don't like having a single-item menu,
we'll just have to explain it to new users
- browser window redone to look like ananke
- home button here goes to ~/Emulation rather than just ~ like ananke,
since this is the home of game folders
- game folder icon is now the executable icon for the Tango theme
(orange diamond), meant to represent a complete game rather than
a game file or archive
ananke changelog:
- outputs GBC games to "Game Boy Color/" instead of "Game Boy/"
- adds the file basename to "information/title"
Known issues:
- using ananke to load a GB game trips the Super Famicom SGB mode and
fails (need to make the full-path auto-detection ignore non-bootable
systems)
- need to dump and test some BS-X media before releasing
- ananke lacks BS-X Satellaview cartridge support
- v092 isn't going to let you retarget the ananke/higan game folder path
of ~/Emulation, you will have to wait for a future version if that
bothers you so greatly
[Later, after the v092 release, byuu posted this additional changelog:
- kill laevateinn
- add title()
- add bootable, remove load
- combine file, library
- combine [][][] paths
- fix SFC subtype handling XML->BML
- update file browser to use buttons
- update file browser keyboard handling
- update system XML->BML
- fix sufami turbo hashing
- remove Cartridge::manifest
]
byuu says (about higan):
- dropped release/ root node for individual games (still there in
ananke's database.)
- Memory export uses smarter names (vram.rwm -> video.ram, etc.)
- cheat database moved from XML to BML (3.1MB to 1.9MB file size.)
- cheat codes moved from XML to BML
- resource manifest moved from XML to BML
What can I say, I like consistency. But I'll leave the shaders alone
until I get around to shader folders.
byuu says (about ananke):
Works with higan v091r13. Only does SNES stuff so far.
byuu says:
This release refines HSU1 support as a bidirectional protocol, nests SFC
manifests as "release/cartridge" and "release/information" (but release/
is not guaranteed to be finalized just yet), removes the database
integration, and adds support for ananke.
ananke represents inevitability. It's a library that, when installed,
higan can use to load files from the command-line, and also from a new
File -> Load Game menu option.
I need to change the build rules a bit for it to work on Windows (need
to make phoenix a DLL, basically), but it works now on Linux.
Right now, it only takes *.sfc file names, looks them up in the included
database, converts them to game folders, and returns the game folder
path for higan to load.
The idea is to continue expanding it to support everything we can that
I don't want in the higan core:
- load *.sfc, *.smc, *.swc, *.fig files
- remove SNES copier headers
- split apart merged firmware files
- pull in external firmware files (eg dsp1b.rom - these are staying
merged, just as SPC7110 prg+dat are merged)
- load *.zip and *.7z archives
- prompt for selection on multi-file archives
- generate manifest files based on heuristics
- apply BPS patches
The "Load" menu option has been renamed to "Library", to represent games
in your library. I'm going to add some sort of suffix to indicate
unverified games, and use a different folder icon for those (eg
manifests built on heuristics rather than from the database.)
So basically, to future end users:
File -> Load Game will be how they play games.
Library -> (specific system) can be thought of as an infinitely-sized
recent games list.
purify will likely become a simple stub that invokes ananke's functions.
No reason to duplicate all that code.
[r07 and r08 were not posted to the WIP thread. -Ed.]
byuu says:
I'd appreciate it if you guys wouldn't mind testing out the database
functionality.
Save this file as database.bml (remove the date) inside
~/.config/higan/Super Famicom.sfc/ or %APPDATA%/higan/Super Famicom.sfc/
http://byuu.org/snes/database/database_2012-10-21.bml
Now load any of the 20 games in the database from the file dialog. They
need to be named *.sfc, have no copier header, and have firmware
appended (for Mario Kart only so far.)
If anyone actually does test it, please let me know how it goes for you
and what you think. Note that future versions of higan will have the
database.bml file included with the release.
byuu says:
This release adds initial database support.
The way it works is you can now load game folders as you always have, or
you can load a game file. If you load a game file, it tries to create
a game folder for you by looking up the file's sha256 in a database. If
it can't find it, sorry, the game won't play. I'm not hooking up the
oldschool "make up a manifest" code here. The easiest way to handle this
is to get me every game so I can dump it and add it to the database :D
The database entries are complete entries that can be copied directly.
So it describes the board, the information, file layout, etc. That'll be
what comes with higan releases in the future.
Internally, I'm separating the information and board descriptions, and
will use a tool to merge the two together.
Here's a current database copy, with one game in it. Still hammering out
some details, but it's mostly how it's going to look.
cartridge region=NTSC
board type=1CB5B-20
superfx revision=2
rom name=program.rom size=0x200000
ram name=save.rwm size=0x8000
map id=io address=00-3f,80-bf:3000-32ff
map id=rom address=00-3f:8000-ffff mask=0x8000
map id=rom address=40-5f:0000-ffff
map id=ram address=00-3f,80-bf:6000-7fff size=0x2000
map id=ram address=70-71:0000-ffff
information
name: Super Mario World 2 - Yoshi's Island (SNS) (1.1)
title: Super Mario World 2: Yoshi's Island
sha256: bd763c1a56365c244be92e6cffefd318780a2a19eda7d5baf1c6d5bd6c1b3e06
board: SHVC-1CB5B-20
rom: 0x200000
ram: 0x8000
layout
file name=program.rom size=0x200000
[No prior releases were posted to the WIP thread. -Ed.]
byuu says:
Super Famicom mapping system has been reworked as discussed with the
mask= changes. offset becomes base, mode is gone. Also added support for
comma-separated fields in the address fields, to reduce the number of
map lines needed.
<?xml version="1.0" encoding="UTF-8"?>
<cartridge region="NTSC">
<superfx revision="2">
<rom name="program.rom" size="0x200000"/>
<ram name="save.rwm" size="0x8000"/>
<map id="io" address="00-3f,80-bf:3000-32ff"/>
<map id="rom" address="00-3f:8000-ffff" mask="0x8000"/>
<map id="rom" address="40-5f:0000-ffff"/>
<map id="ram" address="00-3f,80-bf:6000-7fff" size="0x2000"/>
<map id="ram" address="70-71:0000-ffff"/>
</superfx>
</cartridge>
Or in BML:
cartridge region=NTSC
superfx revision=2
rom name=program.rom size=0x200000
ram name=save.rwm size=0x8000
map id=io address=00-3f,80-bf:3000-32ff
map id=rom address=00-3f:8000-ffff mask=0x8000
map id=rom address=40-5f:0000-ffff
map id=ram address=00-3f,80-bf:6000-7fff size=0x2000
map id=ram address=70-71:0000-ffff
As a result of the changes, old mappings will no longer work. The above
XML example will run Super Mario World 2: Yoshi's Island. Otherwise,
you'll have to write your own.
All that's left now is to work some sort of database mapping system in,
so I can start dumping carts en masse.
The NES changes that FitzRoy asked for are mostly in as well.
Also, part of the reason I haven't released a WIP ... but fuck it, I'm
not going to wait forever to post a new WIP.
I've added a skeleton driver to emulate Campus Challenge '92 and
Powerfest '94. There's no actual emulation, except for the stuff I can
glean from looking at the pictures of the board. It has a DSP-1 (so
SR/DR registers), four ROMs that map in and out, RAM, etc.
I've also added preliminary mapping to upload high scores to a website,
but obviously I need the ROMs first.
byuu says:
Basically just a project rename, with s/bsnes/higan and the new icon
from lowkee added in.
It won't compile on Windows because I forgot to update the resource.rc
file, and a path transform command isn't working on Windows.
It was really just meant as a starting point, so that v091 WIPs can flow
starting from .00 with the new name (it overshadows bsnes v091, so
publicly speaking this "shouldn't exist" and will probably be deleted
from Google Code when v092 is ready.)