Compare commits

...

90 Commits
v104b ... v106

Author SHA1 Message Date
Tim Allen
b55783c322 Update to v106 release.
byuu says:

Changelog (since v105tr1):

Changelog:

  - added Emulation/AutoSaveMemory/Interval setting to specify number of
    seconds between auto-saves
  - added Game Notes tool
  - added 64 new SNES PAL games to the icarus preservation database

The Games Notes tool is a new feature that gives you a blank text box to
enter notes about a game that you're playing: so you can write down
things like level select codes for games with save RAM, combo moves, or
whatever other information you'd like quick and easy access to.

This is kind of an experiment. Ideally, we'd wanna allow more
personalized information, drawings, etc. But hey, let's try it out and
see what people think.
2017-11-19 23:05:02 +11:00
Tim Allen
3ec08cebbe Add credits from Talarubi's README.TXT to the docs. 2017-11-12 17:10:37 +11:00
Tim Allen
8d7d452534 We don't need to override compiler when building.
It seems on Windows, `compiler` has defaulted to `g++` for a while now,
so we didn't need to override it in the `make` invocation.

Since v105r01, `compiler` defaults to `g++` on Linux too, so we don't
need to override it there either.
2017-11-11 22:21:31 +11:00
Tim Allen
56cb9c01a5 Hack around some code-block formatting errors.
By default, mkdocs uses "highlight.js" to apply syntax-highlighting
to code blocks. Left to its own devices, highlight.js will guess the
language being used in the code block, apply the "hljs" CSS class
(so the code block will be given a nice border, a sensible font-size,
etc.) and apply the appropriate formatting markup. If it guesses wrongly,
you can give a language hint on the opening line of the block.

If you use a language that highlight.js does not recognise, or
the special name "nohighlight", highlight.js will leave the block
alone. Unfortunately, in mkdocs' default theme, that means it will be
formatted like *inline* code, with a border and background that wraps
behind each line of the block.

In order to make a code-block that looks like a code-block, you have
to carefully pick a language that highlight.js has heard of, but whose
syntax is sufficiently different from whatever's in the block that no
unwanted highlighting will occur.

This seems to be fixed in the readthedocs theme that comes with mkdocs
0.16.1, but ReadTheDocs doesn't actually seem to be using that version. :/
2017-11-11 18:22:08 +11:00
Tim Allen
e9d2d56df9 Update to v105r1 release.
byuu says:

Changelog:

  - higan: readded support for soft-reset to Famicom, Super Famicom,
    Mega Drive cores (work in progress)
      - handhelds lack soft reset obviously
      - the PC Engine also lacks a physical reset button
      - the Master System's reset button acts like a gamepad button, so
        can't show up in the menu
  - Mega Drive: power cycle wasn't initializing CPU (M68K) or APU (Z80)
    RAM
  - Super Famicom: fix SPC700 opcode 0x3b regression; fixes Majuu Ou
    [Jonas Quinn]
  - Super Famicom: fix SharpRTC save regression; fixes Dai Kaijuu
    Monogatari II's real-time clock [Talarubi]
  - Super Famicom: fix EpsonRTC save regression; fixes Tengai Makyou
    Zero's real-time clock [Talarubi]
  - Super Famicom: removed `*::init()` functions, as they were never used
  - Super Famicom: removed all but two `*::load()` functions, as they
    were not used
  - higan: added option to auto-save backup RAM every five seconds
    (enabled by default)
      - this is in case the emulator crashes, or there's a power outage;
        turn it off under advanced settings if you want
  - libco: updated license from public domain to ISC, for consistency
    with nall, ruby, hiro
  - nall: Linux compiler defaults to g++; override with g++-version if
    g++ is <= 4.8
      - FreeBSD compiler default is going to remain g++49 until my dev
        box OS ships with g++ >= 4.9

Errata: I have weird RAM initialization constants, thanks to hex_usr
and onethirdxcubed for both finding this:
http://wiki.nesdev.com/w/index.php?title=CPU_power_up_state&diff=11711&oldid=11184

I'll remove this in the next WIP.
2017-11-07 09:05:54 +11:00
Tim Allen
6d487925d0 Build documentation in a UTF-8 locale. 2017-10-27 17:16:29 +11:00
Tim Allen
7aad868adb Fix copy/pasto for libretro build. 2017-10-27 17:04:46 +11:00
Tim Allen
dd06dd0fed Include the licence and documentation with each WIP build. 2017-10-27 16:58:41 +11:00
Tim Allen
3c26736d4b Fix mojibake in README.txt 2017-10-27 14:45:52 +11:00
Talarubi
f53cb33eb9 Add icarus to LICENSE.txt 2017-10-25 18:22:10 -04:00
Talarubi
426de198b7 Initial attempt at a README.txt for release archives 2017-10-25 18:02:54 -04:00
Talarubi
9e06857e4d Update version and license
Added LICENSE.txt and GPLv3.txt. Also updated libco documentation.

After discussion with byuu, libco gets a more specific ISC license
to match nall, ruby and hiro. higan, as clarified in LICENSE.txt,
continues to be GPL version 3 only (no "or later" clause).
2017-10-24 23:37:22 -04:00
Talarubi
e28aa32324 Fixed: Typo in SPC700 instruction table
https://board.byuu.org/viewtopic.php?p=48325#p48325

Per Screwtape and Jonas Quinn, this fixes 魔獣王 (Majuu Ou)
hanging at the title.
2017-10-24 23:37:21 -04:00
Talarubi
a9571ff5b8 Fixed: Restore SPC7110 and S-RTC time properly
Loading and unloading the RTC is a little odd, since it's normally
always powered in the first place. What we want, and what the load()
functions really do, is to resync using the saved timestamps or
reset it. unload() proper doesn't do anything.

However, an interface refactoring after v098 reordered the above
operations, and this (along with a typo, shh!) was causing the already
synced time to be cleared.

I've added checks so that whenever rtc.ram can't be found, load() gets
called with empty arguments to initialise the defaults (like putting
in a fresh battery).
2017-10-24 23:16:22 -04:00
Tim Allen
3d21e9afe0 Mention that higan does not yet emulate the timing of the SGB2. 2017-10-23 13:24:14 +11:00
Tim Allen
1cb37fc974 Fix another stupid typo. :( 2017-10-08 18:51:47 +11:00
Tim Allen
f92fc276af Fix typo in libretro path. 2017-10-08 18:44:25 +11:00
Tim Allen
18afd41a80 Using "--no-commit" didn't work, let's try something else. 2017-10-08 18:17:48 +11:00
Tim Allen
3507c522f4 Don't commit the libretro test merge.
git requires a name and email to be configured before it can commit a change. We're not going to push the merge result anywhere, so we don't strictly speaking need it to commit.
2017-10-08 17:54:49 +11:00
Tim Allen
7a4bfca106 Fix git merge command 2017-10-08 17:29:14 +11:00
Tim Allen
0db886f91d Building the libretro core doesn't need UI libraries, but needs git.
The git dependency is only because we want to do some merge shenanigans for testing purposes.
2017-10-08 14:33:16 +11:00
Tim Allen
904d11a3f7 Next release, we need to update the libretro branch too. 2017-10-08 14:33:11 +11:00
Tim Allen
214b921388 Test that the libretro core builds with each change to higan. 2017-10-08 14:25:42 +11:00
Tim Allen
b8b5aef165 Update the release instructions after their first use. 2017-10-07 20:00:17 +11:00
Tim Allen
f8e71b50d0 Update to v105 release.
byuu says:

This release provides several major improvements to Mega Drive emulation
which enhances compatibility a good deal. It also includes important
Super Famicom mosaic emulation improvements, plus a much-needed SuperFX
save state issue fix.

Changelog (since v104):

  - higan: many improvements to Emulator::Interface to support
    forks/frontends
  - higan: refreshed program icon
  - icarus: new program icon
  - Game Boy Advance: slight emulation speedup over v104
  - Game Boy Advance: synchronize APU FIFO updates better
  - Mega Drive: added automatic region detection [hex_usr]
  - Mega Drive: support 8-bit SRAM
  - Game Boy Advance: fixed bug when changing to THUMB mode via MSR
    [MerryMage]
  - Master System: fix bug in backdrop color and background 0 priority
    [hex_usr]
  - Mega Drive: backgrounds always update output priority bit [Cydrak]
  - Mega Drive: emulated interlaced video output
  - Mega Drive: emulated shadow/highlight mode [Cydrak]
  - Super Famicom: auto joypad polling clears the shift register when
    starting
  - Super Famicom: added new low-entropy RAM initialization mode to more
    closely match hardware
  - Game Boy Advance: rumble will now time out after being left on for
    500ms
  - ruby: improved rumble support in udev input driver [ma_rysia]
  - M68K: `move.b (a7)[+/-]` adjust a7 by two
  - M68K: illegal/lineA/lineF opcodes do not modify the stack register
  - Mega Drive: emulate VIP status bit
  - uPD7725: improved emulation of OV1/S1 flags [byuu, AWJ, Lord
    Nightmare]
  - uPD7725: improved handling of DP, RP updates [Jonas Quinn]
  - Super Famicom: improved emulation of mosaic effects in hires,
    interlace, and offset-per-tile modes [byuu, Cydrak]
  - ruby: improved Direct3D exclusive mode monitor selection [Cydrak]
  - Super Famicom: fixed save state bug affecting SuperFX games
    [Cydrak]
  - Mega Drive: added workaround for Clang compiler bug; allowing this
    core to work on macOS [Cydrak, Sintendo]
  - higan: hotkeys now also trigger when the main window lacks focus yet
    higan is set to allow input on focus loss
  - higan: fixed an edge case where `int16_t` ↔ `double` audio
    conversion could possibly result in overflows
  - higan: fixed a crash on macOS when choosing quit from the
    application menu [ncbncb]

Changelog (since the previous WIP):

  - higan: restored `make console=true`
  - tomoko: if you allow input when main window focus is lost, hotkeys
    can now be triggered without focus as well
  - hiro/cocoa: fix crash on exit from menu [ncbncb]
  - ruby: smarter `double` → `int16_t` conversion to prevent
    underflow/overflow
2017-10-07 19:49:07 +11:00
Tim Allen
9a13863adb Update to v104r17 release.
byuu says:

Changelog:

  - processor/m68k: fix error in disassembler [Sintendo]
  - processor/m68k: work around Clang compiler bug [Cydrak, Sintendo]

This is one of the shortest WIPs I've done, but I'm trying not to change
anything before v105.
2017-10-05 17:13:03 +11:00
Tim Allen
5dbaec85a7 Update to v104r16 release.
byuu says:

Changelog:

  - processor/upd96050: always potentially update S1 on ALU ops, sans NOP
      - theory by Lord Nightmare. I'm impartial on this one, but may as
        well match his design
  - sfc: fixed save state hang [reported by FitzRoy; fixed by Cydrak]
  - icarus: do not save settings.bml file when in library mode
2017-10-02 19:04:28 +11:00
Tim Allen
92d86aef16 Remind myself what I need to do for a higan release. 2017-09-29 21:27:55 +10:00
Tim Allen
6524a7181d Update to v104r15 release.
byuu says:

Changelog:

  - processor/huc6280,mos6502,wdc65816: replaced abbreviated opcode
    names with descriptive names
  - nall: replaced `PLATFORM_MACOSX` define with `PLATFORM_MACOS`
  - icarus: added `Icarus::missing() -> string_vector` to list missing
    appended firmware files by name
  - ruby, hiro: fix macosx→macos references

The processor instruction renaming was really about consistency with the
other processor cores. I may still need to do this for one or two more
processors.

The icarus change should allow a future release of the icarus
application to import games with external SNES coprocessor firmware once
again. It will also allow this to be possible when used in library mode.
2017-09-29 20:36:35 +10:00
Tim Allen
fbc58c70ae Update to v104r14 release.
byuu says:

Changelog:

  - Emulator::Interface::videoResolution() -\> VideoResolution renamed
    to videoInformation() -\> VideoInformation
  - added double VideoInformation::refreshRate
  - higan: added `binary := (application|library)` — set this to
    `library` to produce a dynamic link library
  - higan: removed `-march=native` for macOS application builds; and for
    all library builds
  - higan: removed `console` build flag; uncomment  `link += -mwindows`
    instead
  - nall/GNUmakefile: `macosx` platform renamed `macos`
      - still need to do this for nall/intrinsics.hpp
  - Game Gear: return region=NTSC as the only option, so that the system
    frequency is always set correctly
  - hiro/cocoa: fixed typo [Sintendo]
  - hiro/Windows: removed GetDpiForMonitor, as it's Windows 8+ only; DPI
    is no longer per-monitor aware
  - icarus: core Icarus class now has virtual functions for
    directory::create, <file::exists>, <file::copy>, <file::write>
  - icarus: Sufami Turbo can import save RAM files now
  - icarus: setting `ICARUS_LIBRARY` define will compile icarus without
    main(), GUI components
  - ruby/video/Direct3D: choose the current monitor instead of top-left
    monitor for fullscreen exclusive [Cydrak]
  - ruby/video/Direct3D: do not set `WS_EX_TOPMOST` on fullscreen
    exclusive window [Cydrak]
      - this isn't necessary for exclusive mode, and it just makes
        getting out of the application more difficult
2017-09-24 11:01:48 +10:00
Tim Allen
c63e6f2953 Apparently icarus requires dashes in PF94 game ROM names. 2017-09-12 10:45:15 +10:00
Tim Allen
b899ee9a9c Document the command-line interface for games with cartridge slots. 2017-09-09 18:32:11 +10:00
Tim Allen
28fc75737e Add directions for manually importing PowerFest '94.
Special thanks to hex_usr for figuring out the details:
https://board.byuu.org/viewtopic.php?p=46289#p46289
2017-09-09 16:50:33 +10:00
Tim Allen
1ff315838e Update to v104r13 release.
byuu says:

Changelog:

  - nall/GNUmakefile: build=release changed to -O2, build=optimize is
    now -O3
  - hiro: added Monitor::dpi(uint index) → Position [returns logical
    DPI for x, y]
      - Position is a bad name, but dpi(monitor).(x,y)() make more sense
        than .(width,height)()
  - hiro: Position, Size, Geometry, Font changed from using signed int
    to float
  - hiro: Alignment changed from using double to float
  - hiro: added skeleton (unused) Application::scale(), setScale()
    functions

Errata:

  - hiro/cocoa's Monitor::dpi() is untested. Probably will cause issues
    with macOS' automatic scaling.
  - hiro/gtk lacks a way to get both per-monitor and per-axis (x,y) DPI
    scaling
  - hiro/qt lacks a way to get per-monitor DPI scaling (Qt 5.x has this,
    but I still use Qt 4.x)
      - and just to get global DPI, hiro/qt's DPI retrieval has to use
        undocumented functions ... fun

The goal with this WIP was basically to prepare hiro for potential
automatic scaling. It'll be extremely difficult, but I'm convinced that
it must be possible if macOS can do it.

By moving from signed integers to floats for coordinates, we can now
scale and unscale without losing precision. That of course isn't the
hard part, though. The hard part is where and how to do the scaling. In
the ideal application, hiro/core and hiro/extension will handle 100% of
this, and the per-platform hiro/(cocoa,gtk,qt,windows) will not be aware
of what's going on, but ... to even make that possible, things will need
to change in every per-platform core, eg the per-platform code will have
to call a core function to change geometry, which will know about the
scaling and unscale the values back down again.

Gonna be a lot of work, but ... it's a start.
2017-09-08 16:06:21 +10:00
Tim Allen
2e4cd09800 Document the new Credits menu item. 2017-09-06 12:41:32 +10:00
Tim Allen
4fb8ce2821 Update to v104r12 release.
byuu says:

Changelog:

  - higan: URLs updated to HTTPS
  - sfc/ppu/background: use hires/interlace/mosaic-adjusted X/Y
    coordinates for offset-per-tile mode
  - sfc/ppu/background: hires mosaic seems to advance pixel counter on
    subscreen pixels
  - tomoko: added “Help→Credits” menu option (currently the page does
    not exist; should before v105)
  - tomoko: reduced volume slider from {0% - 500%} to {0% - 200%}.
    Distortion is too intense above 200%.
      - technically, I've encountered distortion at 200% as well in
        Prince of Persia for the SNES
  - nall/run/invoke: use program path for working directory
      - allows you to choose “Library→Import ROMs” from a different
        directory on the command-line

I don't know how to assign credit for the mosaic stuff. It's been a
work-in-progress with me, Cydrak, and hex_usr.

The current design should be correct, but very unpleasant. The code
desperately needs to be refactored, but my recent attempt at doing so
ended in spectacular failure.
2017-09-06 12:38:00 +10:00
Tim Allen
3dce3aa3c8 Update to v104r11 release.
byuu says:

Changelog:

  - sfc/ppu/background: minor code cleanup and simplification
  - sfc/ppu/background: $2106 MOSAIC register was implemented
    incorrectly
  - sfc/ppu/background: fixed mosaic effects in hires mode (temporary
    fix)
  - sfc/ppu/background: fixed mosaic effects in interlace mode [Cydrak]

Errata:

  - sfc/ppu/background/background.cpp:48: should be
    `if(!mosaic.enable) {`

Turns out there is only one mosaic size, and the other four bits are
per-BG mosaic enable. This matters a lot for hires/interlace, as
mosaicSize=0 (2x2) is not the same thing as mosaicEnable=false (1x1).

Although I've now implemented this, I really don't like how my mosaic
implementation works right now. I tried to redesign the entire system,
and completely failed. So I started over from v104r10 again and instead
went with a more evolutionary improvement for now. I'll keep trying.

Also, the combination of mosaic + offset-per-tile is still sketchy, as
is mode 6 offset-per-tile. I'll get to those in the future as well.
2017-09-05 10:56:52 +10:00
Tim Allen
28060d3a69 Update to v104r10 release.
byuu says:

Changelog:

  - processor/upd96050: per manual errata note, SGN always uses SA1;
    never SB1 [fixes v104r09 regression]
  - processor/upd96050: new OV1/S1 calculation that doesn't require OV0
    history buffer [AWJ]
  - processor/upd96050: do not update DP in OP if DST=4 [Jonas Quinn]
  - processor/upd96050: do not update RP in OP if DST=5 [Jonas Quinn]
  - resource: recreated higan+icarus icons, higan logo as 32-bit PNGs

So higan v104r08 and earlier were 930KiB for the source tarball. After
creating new higan and icarus icons, the size jumped to 1090KiB, which
was insane for only adding one additional icon.

After digging into why, I discovered that ImageMagick defaults to
64-bit!! (16-bits per channel) PNG images when converting from SVG.
You know, for all those 16-bit per channel monitors that don't exist.
Sigh. Amazingly, nobody ever noticed this.

The logo went from 78.8KiB to 24.5KiB, which in turn also means the
generated resource.cpp shrank dramatically.

The old higan icon was 32-bit PNG, because it was created before I
installed FreeBSD and switched to ImageMagick. But the new higan icon,
plus the new icarus icon, were both 64-bit as well. And they're now
32-bit.

So the new tarball size, thanks to the logo optimization, dropped to
830KiB.

Cydrak had some really interesting results in converting higan's
resources to 8-bit palletized PNGs with the tRNS extension for alpha
transparency. It reduces the file sizes even more without much visual
fidelity loss. Eg the higan logo uses 778 colors currently, and 256
represents nearly all of it very well to the human eye. It's based off
of only two colors, the rest are all anti-aliasing. Unfortunately,
nall/image doesn't support this yet, and I didn't want to flatten the
higan logo to not have transparency, in case I ever want to change the
about screen background color.
2017-09-01 21:21:06 +10:00
Tim Allen
9dcbd12159 Don't let gitlab cache .o files.
higan's makefiles don't always model dependencies properly, so caching
.o files just invites stale .o files.
2017-09-01 16:05:14 +10:00
Tim Allen
5352c5ab27 Update to v104r09 release.
byuu says:

Changelog:

  - processor/upd96050: SGN should select between (A,B).S1 flag using
    ASL opcode bit
  - processor/upd96050: use a temporary to cache new S1, then compute
    OV1 using old S1, then assign new S1
  - processor/upd96050: add SR.(siack,soack) and connect to relevant
    jump instructions (serial not implemented)
  - processor/upd96050: initialize SR properly in power() [r08
    regression]
  - icarus: improve Makefile rules [Screwtape]
  - higan: new program icon
  - icarus: new program icon
2017-08-31 23:58:54 +10:00
Tim Allen
b47488ab09 As of higan v104r07, higan no longer imports separate firmware files.
icarus now requires games and firmware to be combined into a single file,
so we must describe how to achieve that.
2017-08-31 17:05:47 +10:00
Tim Allen
96c45420d1 Use the en_AU spelling of "synchronise".
I've generally tried to keep to en_AU spellings rather than en_US spellings
for the sake of my own sanity, but it's difficult when documenting a program
that exclusively uses en_US spellings since I'm quoting the text on
menu-items and in config files.
2017-08-31 15:50:34 +10:00
Tim Allen
fd9194e4c2 On Linux, install higan before icarus.
Strictly speaking, there's no dependency between them, but higan's
install target happens to create the destination bin directory if it
doesn't already exist, so we want to run that install script first.
2017-08-31 15:34:57 +10:00
Tim Allen
593d32b885 Many typos and grammar fixes from dan1982 on the higan forums. 2017-08-31 15:19:43 +10:00
Tim Allen
fb31df6eb8 Windows changed their not-found error message apparently. 2017-08-31 15:12:36 +10:00
Tim Allen
a81802422f No-Intro changed their naming conventions.
Sufami Turbo games are in a separate set now, they don't have the "(ST)"
marker in the filename.

Satellaview memory paks may have "(BS)", "(BS SoundLink)" or "(BSROM)"
for various reasons that aren't important to higan, so let's just not mention
them at all.
2017-08-31 14:57:24 +10:00
Tim Allen
a1eaec493a Italicise more game names.
Also, it turns out the canonical spelling is "Mega Man", not "Megaman".
2017-08-31 14:56:46 +10:00
Tim Allen
2956930d1c Standardise on "SHA256". 2017-08-31 14:51:48 +10:00
Tim Allen
c557d68ec4 Spell-check the documentation.
Changes include a few typos, a few capitalization changes, and a lot of hyphenation of compound words that were not as widely used as I thought.
2017-08-31 14:48:52 +10:00
Tim Allen
6b8c003ff8 Sufami Turbo carts are not memory paks! 2017-08-30 14:12:44 +10:00
Tim Allen
25bda4f159 Update to v104r08 release.
byuu says:

Changelog:

  - processor/upd96050: code cleanups
  - processor/upd96050: improved emulation of S1/OV1 flags [thanks to
    Cydrak, Lord Nightmare]
  - tomoko/settings/audio: reduced the size of the frequency/latency
    combo boxes to show longer device driver names

Errata: I need to clear regs.sr in uPD96050::power()

Note: the S1/OV1 emulation is likely not 100% correct yet, but it's a
step in the right direction. No SNES games actually use S1/OV1, so this
shouldn't result in any issues, I'd just like to have this part of the
chip emulated correctly.
2017-08-30 13:44:51 +10:00
Tim Allen
d8a8f06c35 Finally finished reviewing and polishing all the text! 2017-08-29 17:22:11 +10:00
Tim Allen
fab830f84b byuu mentioned Ballz 3D requires DSP1B. 2017-08-29 13:50:52 +10:00
Tim Allen
f669c424c4 higan v104r07 changes the expected filenames for the SGB boot ROM. 2017-08-29 13:49:44 +10:00
Tim Allen
9c25f128f9 Update to v104r07 release.
byuu says:

Changelog:

  - md/vdp: added VIP bit to status register; fixes Cliffhanger
  - processor/m68k/disassembler: added modes 7 and 8 to LEA address
    disassembly
  - processor/m68k/disassembler: enhanced ILLEGAL to display LINEA/LINEF
    $xxx variants
  - processor/m68k: ILLEGAL/LINEA/LINEF do not modify the stack
    register; fixes Caeser no Yabou II
  - icarus/sfc: request sgb1.boot.rom and sgb2.boot.rom separately; as
    they are different
  - icarus/sfc: removed support for external firmware when loading ROM
    images

The hack to run Mega Drive Ballz 3D isn't in place, as I don't know if
it's correct, and the graphics were corrupted anyway.

The SGB boot ROM change is going to require updating the icarus database
as well. I will add that in when I start dumping more cartridges here
soon.

Finally ... I explained this already, but I'll do so here as well: I
removed icarus' support for loading SNES coprocessor firmware games with
external firmware files (eg dsp1.program.rom + dsp1.data.rom in the same
path as supermariokart.sfc, for example.)

I realize most are going to see this as an antagonizing/stubborn move
given the recent No-Intro discussion, and I won't deny that said thread
is why this came to the forefront of my mind. But on my word, I honestly
believe this was an ineffective solution for many reasons not related to
our disagreements:

 1. No-Intro distributes SNES coprocessor firmware as a merged file, eg
    "DSP1 (World).zip/DSP1 (World).bin" -- icarus can't possibly know
    about every ROM distribution set's naming conventions for firmware.
    (Right now, it appears GoodSNES and NSRT are mostly dead; but there
    may be more DATs in the future -- including my own.)
 2. Even if the user obtains the firmware and tries to rename it, it
    won't work: icarus parses manifests generated by the heuristics
    module and sees two ROM files: dsp1.program.rom and dsp1.data.rom.
    icarus cannot identify a file named dsp1.rom as containing both
    of these sub-files. Users are going to have to know how to split
    files, which there is no way to do on stock Windows. Merging files,
    however, can be done via `copy /b supermariokart.sfc+dsp1.rom
    supermariokartdsp.sfc`; - and dsp1.rom can be named whatever now.
    I am not saying this will be easy for the average user, but it's
    easier than splitting files.
 3. Separate firmware breaks icarus' database lookup. If you have
    pilotwings.sfc but without firmware, icarus will not find a match
    for it in the database lookup phase. It will then fall back on
    heuristics. The heuristics will pick DSP1B for compatibility with
    Ballz 3D which requires it. And so it will try to pull in the
    wrong firmware, and the game's intro will not work correctly.
    Furthermore, the database information will be unavailable, resulting
    in inaccurate mirroring.

So for these reasons, I have removed said support. You must now load
SNES coprocessor games into higan in one of two ways: 1) game paks with
split files; or 2) SFC images with merged firmware.

If and when No-Intro deploys a method I can actually use, I give you all
my word I will give it a fair shot and if it's reasonable, I'll support
it in icarus.
2017-08-28 22:46:14 +10:00
Tim Allen
c273297577 More cleanups. 2017-08-26 15:17:15 +10:00
Tim Allen
afa8ea61c5 Update to v104r06 release.
byuu says:

Changelog:

  - gba,ws: removed Thread::step() override¹
  - processor/m68k: move.b (a7)+ and move.b (a7)- adjust a7 by two, not
    by one²
  - tomoko: created new initialize(Video,Audio,Input)Driver() functions³
  - ruby/audio: split Audio::information into
    Audio::available(Devices,Frequencies,Latencies,Channels)³
  - ws: added Model::(WonderSwan,WonderSwanColor,SwanCrystal)()
    functions for consistency with other cores

¹: this should hopefully fix GBA Pokemon Pinball. Thanks to
SuperMikeMan for pointing out the underlying cause.

²: this fixes A Ressaha de Ikou, Mega Bomberman, and probably more
games.

³: this is the big change: so there was a problem with WASAPI where
you might change your device under the audio settings panel. And your
new device may not support the frequency that your old device used. This
would end up not updating the frequency, and the pitch would be
distorted.

The old Audio::information() couldn't tell you what frequencies,
latencies, or channels were available for all devices simultaneously, so
I had to split them up. The new initializeAudioDriver() function
validates you have a correct driver, or it defaults to none. Then it
validates a correct device name, or it defaults to the first entry in
the list. Then it validates a correct frequency, or defaults to the
first in the list. Then finally it validates a correct latency, or
defaults to the first in the list.

In this way ... we have a clear path now with no API changes required to
select default devices, frequencies, latencies, channel counts: they
need to be the first items in their respective lists.

So, what we need to do now is go through and for every audio driver that
enumerates devices, we need to make sure the default device gets added
to the top of the list. I'm ... not really sure how to do this with most
drivers, so this is definitely going to take some time.

Also, when you change a device, initializeAudioDriver() is called again,
so if it's a bad device, it will disable the audio driver instead of
continuing to send samples at it and hoping that the driver blocked
those API calls when it failed to initialize properly.

Now then ... since it was a decently-sized API change, it's possible
I've broken compilation of the Linux drivers, so please report any
compilation errors so that I can fix them.
2017-08-26 11:15:49 +10:00
Tim Allen
ea3c2dafda More cleanups. 2017-08-25 18:40:20 +10:00
Tim Allen
b38a657192 Update to v104r05 release.
byuu says:

Changelog:

  - emulator/random: new array function with more realistic RAM
    initializations
  - emulator/random: both low and high entropy register initializations
    now use PCG
  - gba/player: rumble will time out and disable after being left on for
    500ms; fixes Pokemon Pinball issue
  - ruby/input/udev: fixed rumble effects [ma\_rysia]
  - sfc/system: default to low-entropy randomization of memory

The low-entropy memory randomization is modeled after one of my SHVC
2/1/3 systems. It generates striped patterns in memory, using random
inputs (biased to 0x00/0xff), and has a random chance of corrupting 1-2
bits of random values in the pool of memory (to prevent easy emulator
detection and to match observed results on hardware.)

The reasoning for using PCG on register initializations, is that I don't
believe they're going to have repeating patterns like RAM does anyway.
And register initializations are way more vital.

I want to have the new low-entropy RAM mode tested, so at least for the
next few WIPs, I've set the SNES randomization over to low-entropy.
We'll have to have a long discussion and decide whether we want official
releases to use high-entropy or low-entropy.

Also, I figured out the cause of the Prince of Persia distortion ... I
had the volume under the audio settings tab set to 200%. I didn't
realize there were SNES games that clipped so easily, given how
incredibly weak SNES audio is compared to every other sound source on my
PC. So with no entropy or low-entropy, indeed the game now sounds just
fine.

I can't actually test the udev fixes, so I guess we'll see how that goes
for Screwtape and ma\_rysia.
2017-08-25 00:24:34 +10:00
Tim Allen
a8f2bfc533 Another doc cleanup. 2017-08-24 22:13:44 +10:00
Tim Allen
d060904b8d Revert an accidental ruby change.
I made a change to ruby/input/joypad/udev.cpp while diagnosing a problem
with higan's rumble behaviour on Linux, and accidentally committed it
in 15b3dc8b0b as part of a documentation
change.
2017-08-24 22:09:49 +10:00
Tim Allen
56293c585b Clean up the higan Settings docs. 2017-08-24 22:09:03 +10:00
Tim Allen
15b3dc8b0b More cleanups and revision. 2017-08-24 18:34:37 +10:00
Tim Allen
d621136d69 Update to v104r04 release.
byuu says:

Changelog:

  - higan/emulator: added new Random class with three entropy settings:
    none, low, and high
  - md/vdp: corrected Vcounter readout in interlace mode [MoD]
  - sfc: updated core to use the new Random class; defaults to high
    entropy

No entropy essentially returns 0, unless the random.bias(n) function is
called, in which case, it returns n. In this case, n is meant to be the
"logical/ideal" default value that maximizes compatibility with games.

Low entropy is a very simple entropy modeled after RAM initialization
striping patterns (eg 32 0x00s, followed by 32 0xFFs, repeating
throughout.) It doesn't "glitch" like real hardware does on rare
occasions (parts of the pattern being broken from time to time.) It also
only really returns 0 or ~0. So the entropy is indeed extremely low, and
not very useful at all for detecting bugs. Over time, we can try to
improve this, of course.

High entropy is PCG. This replaces the older, lower-entropy and more
predictable, LFSR. PCG should be more than enough for emulator
randomness, while still being quite fast.

Unfortunately, the bad news ... both no entropy and low entropy fix the
Konami logo popping sound in Prince of Persia, but all three entropy
settings still cause the distortion in-game, especially evident at the
title screen. So ... this may be a more serious bug than first
suspected.
2017-08-24 12:45:24 +10:00
Tim Allen
c0934b826c Mention shaders in our install instructions.
If we're going to lug them around, we might as well use them.
2017-08-23 20:55:09 +10:00
Tim Allen
86f3a8e670 Install shaders somewhere that higan will find them. 2017-08-23 20:46:24 +10:00
Tim Allen
b308661fa3 General tidying and tightening of docs. 2017-08-23 17:48:24 +10:00
Tim Allen
a4483339e5 Rename higan-config.md to higan-settings.md
The file was originally named `higan-config.md` because the dialog box
it described was called "higan Configuration", which was because the
menu-item to open it was in a menu called "Settings" and it would have
been weird to have a "Settings" item in a "Settings" menu.

Now there are individual menu-items for each tab in the Settings dialog,
none of which are named Settings, so the dialog has been renamed back to
"Settings", and the filename should match.
2017-08-23 17:05:33 +10:00
Tim Allen
1c13f0ad42 Hint more strongly that Linux distros may already have higan packages 2017-08-23 16:57:17 +10:00
Tim Allen
d416bb7231 *facepalm* 2017-08-23 16:56:51 +10:00
Tim Allen
4ba37e6cbe We're kind of official docs, now. 2017-08-23 16:55:58 +10:00
Tim Allen
6c7a9adaad Consistently use "folder" over "directory", except for Linux documentation.
For Windows documentation, "folder" is the correct term. For generic
documentation, probably either would do but I suspect people are
slightly more likely to be familiar with "folder".
2017-08-23 14:59:16 +10:00
Tim Allen
bafdb09e1b Let's be consistent about quoting console names here. 2017-08-23 14:52:54 +10:00
Tim Allen
53c0002274 Move the link to the Quick Start section as early as practical. 2017-08-23 14:51:38 +10:00
Tim Allen
15c467b482 This documentation is now up to date as of v104. 2017-08-23 14:51:24 +10:00
Tim Allen
bfcd4e376b Remove the mkdocs link to the higan repo.
It shows up as "Edit on Source" in mkdocs, which sounds weird, and it
doesn't show up on readthedocs at all, so let's get rid of it.
2017-08-23 13:43:50 +10:00
Tim Allen
d13f1dd9ea Update to v104r03 release.
byuu says:

Changelog:

  - md/vdp: added full interlace emulation [byuu, Sik, Eke, Mask of
    Destiny]
  - md/vdp: fix an issue with overscan/highlight when setting was
    disabled [hex\_usr]
  - md/vdp: serialize field, and all oam/objects state
  - icarus/md: do not enable RAM unless header 0x1b0-1b1 == "RA"
    [hex\_usr]

I really can't believe how difficult the interlace support was to add. I
must have tried a hundred combinations of adjusting Y, Vscroll, tile
addressing, heights, etc. Many of the changes were a wash that improved
some things, regressed others.

In the end I ended up needing input from three different people to
implement what should have been trivial. I don't know if the Mega Drive
is just that weird, if I've declined that much in skill since the days
when I implemented SNES interlace, or if I've just never been that good.

But either way, I'm disappointed in myself for not being able to figure
either this or shadow/highlight out on my own. Yet I'm extremely
grateful to my friends for helping carry me when I get stuck.

Since it wasn't ever documented before, I'm going to try and document
the changes necessary to implement interlace mode for any future
emudevs.
2017-08-22 19:11:43 +10:00
Tim Allen
8976438118 Fix all the broken links.
Also, some of the text in the higan and icarus settings docs wanted to
link to a discussion of why we ignore manifests by default; now we have
such a thing.
2017-08-22 18:12:17 +10:00
Tim Allen
11357169a5 Update to v104r02 release.
byuu says:

Changelog:

  - md/vdp: backgrounds always update priority bit output [Cydrak]
  - md/vdp: vcounter.d0 becomes vcounter.d8 in interlace mode 3
  - md/vdp: return field number in interlace modes from status register
  - md/vdp: rework scanline/frame counting in main loop so first frame
    won't clock to field 1 instead of field 0
  - md/vdp: add support for shadow/highlight mode; optimize to minimal
    code [Cydrak]
  - md/vdp: update outputPixel() to support interlace modes
  - sfc/cpu: auto joypad polling start should clear the shift registers;
    fixes Nuke (PD)
      - thanks to BMF54123 for this bug report
  - tomoko: if an invalid video/audio/input driver is found in the
    configuration file, it's reset to "None"
      - prevents showing the wrong driver under advanced settings; no
        longer requires possibly two reboots to fix

Note: the Mega Drive interlace mode 1 should be working fully, but I
don't know any games that use it. Interlace mode 3 (Sonic 2's two-player
mode) does not work at all yet, but this is a good start.
2017-08-22 11:09:07 +10:00
Tim Allen
9be4e59a05 Starting to fix broken links in the documentation.
Also, moved the "you should install the GBA BIOS" advice from the
install pages (where I doubt anybody would see it) to the "importing and
playing" guide, which I figure people are more likely to stumble across.
The actually instructions are still in `install/general.md` for lack of
anywhere more appropriate.
2017-08-21 23:29:53 +10:00
Tim Allen
281b22e1c0 Remove leading "What is..." headings from Concepts pages.
It's kind of implicit that an article about the concept of X will start
by describing what X is.
2017-08-21 17:07:49 +10:00
Tim Allen
c9c931ecab Refresh the "game library" documentation. 2017-08-21 17:05:17 +10:00
Tim Allen
366e9cebff Update to v104r01 release.
byuu says:

Changelog:

  - gba/cpu: synchronize to the PPU, not oneself, when the CPU is
    stopped
      - this bug was patched in the official v104 release; but not in
        the .tar.xz archive
  - ms/vdp: backdrop color is on the second 16-entry palette, not the
    first [hex\_usr]
  - ms/vdp: fix background color 0 priority; fixes Alex Kidd in High
    Tech World text boxes [hex\_usr]
  - tomoko: choose first option when loading files via the command-line
    [hex\_usr]
  - icarus: lo/hi RAM addressing was backwards; M68K is big endian;
    fixes save files in Sonic 3

Many thanks to hex\_usr for the Master System / Game Gear VDP fix.
That's a tricky system to get good technical information on. The fix
should be correct, but please report if you spot any regressions just in
case.
2017-08-18 22:48:29 +10:00
Tim Allen
58d70c7c9a Add a link to the bsnes-mercury fork.
Also, sort the list of forks by the version they forked from.
2017-08-18 17:20:21 +10:00
Tim Allen
d0b90d0b5c Break "Manifests and Game Folders" into two articles.
Also, substantially re-work each of them.
2017-08-18 15:18:15 +10:00
Tim Allen
e0512b9100 Mention connecting controllers in the console menu. 2017-08-14 21:43:15 +10:00
Tim Allen
08e1f93f71 Update the rest of the settings docs to match the new Video settings. 2017-08-14 18:12:49 +10:00
Tim Allen
6caad914ad Update the video settings documentation. 2017-08-14 17:51:00 +10:00
Tim Allen
c39ef91307 Fully document the "no audio → too fast" problem. 2017-08-13 00:07:55 +10:00
Tim Allen
f0cf1df4af Document higan's region-selection features. 2017-08-12 23:41:58 +10:00
294 changed files with 7090 additions and 6141 deletions

View File

@@ -5,22 +5,21 @@ image: debian:stable
linux-x86_64-binaries:
script:
- apt-get update && apt-get -y install build-essential libgtk2.0-dev libpulse-dev mesa-common-dev libgtksourceview2.0-dev libcairo2-dev libsdl1.2-dev libxv-dev libao-dev libopenal-dev libudev-dev
- apt-get update && apt-get -y install build-essential libgtk2.0-dev libpulse-dev mesa-common-dev libgtksourceview2.0-dev libcairo2-dev libsdl1.2-dev libxv-dev libao-dev libopenal-dev libudev-dev mkdocs
- make -C icarus compiler=g++
- make -C higan compiler=g++
- LC_ALL=C.UTF-8 mkdocs build
- mkdir higan-nightly
- cp -a icarus/out/icarus higan-nightly/icarus
- cp -a icarus/Database higan-nightly/
- cp -a higan/out/higan higan-nightly/higan
- cp -a higan/systems/* higan-nightly/
- cp -a shaders "higan-nightly/Video Shaders"
- cp -a docs_build higan-nightly/docs
- cp -a GPLv3.txt higan-nightly/
artifacts:
paths:
- higan-nightly/*
cache:
paths:
- icarus/obj/*.o
- higan/obj/*.o
windows-x86_64-binaries:
# This is a normal Windows cross-compile process, except that
@@ -28,20 +27,33 @@ windows-x86_64-binaries:
# though it's a POSIX function, and for some weird reason mingw has
# clock_gettime() in the pthread library.
script:
- apt-get update && apt-get -y install build-essential mingw-w64
- apt-get update && apt-get -y install build-essential mingw-w64 mkdocs
- sed -i -e 's/-lole32/& -static -lpthread/' nall/GNUmakefile
- make -C icarus platform=windows compiler="x86_64-w64-mingw32-g++ -static-libgcc -static-libstdc++" windres="x86_64-w64-mingw32-windres"
- make -C higan platform=windows compiler="x86_64-w64-mingw32-g++ -static-libgcc -static-libstdc++" windres="x86_64-w64-mingw32-windres"
- LC_ALL=C.UTF-8 mkdocs build
- mkdir higan-nightly
- cp -a icarus/out/icarus higan-nightly/icarus.exe
- cp -a icarus/Database higan-nightly/
- cp -a higan/out/higan higan-nightly/higan.exe
- cp -a higan/systems/* higan-nightly/
- cp -a shaders "higan-nightly/Video Shaders"
- cp -a docs_build higan-nightly/docs
- cp -a GPLv3.txt higan-nightly/
artifacts:
paths:
- higan-nightly/*
cache:
libretro-test:
script:
- apt-get update && apt-get -y install build-essential git
# git refuses to even attempt a merge if you haven't told it who you are,
# even if you use --no-commit. *sigh*
- EMAIL=fake-email@example.com git merge origin/libretro
- make -C higan compiler=g++ binary=library target=libretro
- mkdir libretro-nightly
- cp -a higan/out/higan_sfc_libretro.so libretro-nightly/
- cp -a GPLv3.txt libretro-nightly/
artifacts:
paths:
- icarus/obj/*.o
- higan/obj/*.o
- libretro-nightly/*

View File

@@ -3,7 +3,7 @@ Contributing to higan
If you would like to propose a change to higan,
you should create an account on the [official forums][f],
go to the "Projects" forum and the "higan" subforum,
go to the "Projects" forum and the "higan" sub-forum,
and post your idea in a new topic there.
[f]: https://board.byuu.org/

674
GPLv3.txt Normal file
View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

44
LICENSE.txt Normal file
View File

@@ -0,0 +1,44 @@
----------------------------------------------------------------------
higan - Suite of videogame console emulators
icarus - Game library importer for higan
Copyright © 2004-2017 byuu
https://byuu.org/
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, specifically version 3 of the License
and no other version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
----------------------------------------------------------------------
----------------------------------------------------------------------
hiro - User interface toolkit
libco - C cooperative threading library
nall - C++ template library
ruby - Hardware abstraction layer
Copyright © 2006-2017 byuu
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all
copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
----------------------------------------------------------------------

View File

@@ -1,7 +1,7 @@
The unofficial higan repository
===============================
higan emulates a number of classic videogame consoles of the 1980s and 1990s,
higan emulates a number of classic video-game consoles of the 1980s and 1990s,
allowing you to play classic games on a modern general-purpose computer.
This repository includes

294
README.txt Normal file
View File

@@ -0,0 +1,294 @@

higan - "Now you're playing with fire!"
=======================================
higan is a multi-system emulator that began development on October 14th, 2004.
It currently plays games for the following systems:
* Nintendo Famicom (NES), Super Famicom (SNES)
* Nintendo Game Boy, Game Boy Color + Game Boy Advance
* Sega Master System, Game Gear + Mega Drive (Genesis)
* NEC PC Engine (TurboGrafx) + SuperGrafx
* Bandai WonderSwan + WonderSwan Color
Supported Systems
-----------------
* FreeBSD 10+
* Windows 7, 8, 10
* Linux 3.2+
* OS X 10.7 Lion or above
You'll need a fast CPU, with clock speed being vastly more important.
Dual-core is perfectly adequate, since higan doesn't make significant use
of more than one core.
For Intel, you're looking at a 3.5 GHz Haswell architecture or better,
whilst AMD users will want a similarly specced Ryzen build.
Controller Setup
----------------
First, you'll want to configure your controllers. Choose Settings -> Input and
pick the system you'd like to configure. If you have two players, or a special
game (eg. Mario Paint), you can pick the controller port and device here.
To assign inputs, double click the name and press the stick or button on your
controller. You can have multiple assignments, for example both keyboard and
joypad. The Erase button clears the assignments for one input; Reset clears
them all in one go.
(Normally you only need to do this once. But because of how USB works,
it's impossible to tell identical controllers apart. This means if you move
one to another port, it counts as a new device, and you'll have to reassign
the buttons or move it back.)
Loading Games
-------------
After this you can go to Library -> Load ROM File and select a game. higan
adds it to your library, and it should start immediately. (Game Boy Advance
titles need one more step; please see the FAQ below.)
To add games en masse, you can use Library -> Import ROM Files. This opens
icarus, where you can choose a folder of ROMs, then select the ones you want
to import.
In both cases, if you choose a system under the Library submenus, all games
added will show up in a file browser under the Emulation folder in your user
profile. The path can be changed under Settings -> Advanced if desired.
Controller Ports
----------------
If you're emulating a console, you need to plug the controllers in, since
there's no connection by default.
Usually this means selecting eg. Super Famicom -> Controller Port 1 -> Gamepad,
for example. However, some games require other peripherals like the SNES Mouse.
Troubleshooting & FAQ
---------------------
Q: What's the Library?
A: higan loads folders containing all the files needed to run the game.
Odds are you have PC games and music albums organised the same way.
This does mean that to play the games, you have to import them first.
If you're familiar with iTunes or Steam, you already know how this works!
Q: Importing vs. loading? What's the difference?
A: The "Library -> Load ROM File" menu is a shortcut. It adds the game to your
library, then opens it without the manual import process.
However, if you have lots of games to add at once, you'll want
"Import ROM Files" instead.
Q: Why's higan say I'm missing a file ("Game Boy Advance.sys/bios.rom")?
A: This is the ROM for the startup screen you see when you switch on the
Game Boy Advance. Games require it to run, but like other ROMs, it's
copyrighted and therefore not provided with higan.
Having acquired a copy, you'll have to drop it in the requested folder,
then rename it to bios.rom.
Q: Where are the games imported? Where did all my save files go?
A: Check the path under Settings -> Advanced. On Windows it'll probably be
something like C:\Users\<name>\Emulation, organised by system. The saves
are typically named save.ram.
Q: Where can I find the settings?
A: There's a few possible locations for settings.bml.
1) In the same folder as the higan executable.
2) In the older location if you previously installed higan:
C:\Users\<name>\AppData\Roaming\higan (Windows)
/home/<name>/.config/higan (BSD, Linux)
3) In the new location (created if the others aren't found):
C:\Users\<name>\AppData\Local\higan (Windows)
/home/<name>/.local/share/higan (BSD, Linux)
/Users/<name>/Library/Application Support/higan (Mac)
higan checks these in order, so you can make a portable install if you like.
(macOS normally hides the Library folder. To open it, switch to Finder,
hold the Option key and select Go -> Library from the menu.)
Q: I set up my gamepads, but they don't work!
A: Try configuring the ports found in the system menu (eg.
Super Famicom -> Controller Port 1 -> Gamepad). Like a real console,
fresh higan installs come without any controllers plugged in.
Q: I upgraded higan, why do I get a black screen? What's "Ignore Manifests?"
A: higan looks at a file called "manifest.bml" to get the information needed
to run each game. However, the format has changed over time, making older
manifests incompatible with newer higan releases.
If you tick "Settings -> Advanced -> Ignore Manifests," you might find this
resolves the problem. This can be useful for developers and testers.
However, it breaks a few titles that require manifests to work!
Should you find yourself in this situation, consider removing manifest.bml.
(By default, no manifests are created; higan looks at the files in the
game folder, and with the help of a database, tries to regenerate the
correct one each time you load the game.)
Q: I have "Ignore Manifests" ticked, but the game won't run?
A: A few games have especially quirky setups that require manifests for
the time being, so you'll need to untick this option:
* Far East of Eden: Tengai Makyou Zero (English translation only)
* Campus Challenge '92
* PowerFest '94
Q: Why's the audio lag, stutter, distort, or sound robotic?
A: If you have an Atom, certain Celeron models, or an older AMD processor
(or even an especially old Intel such as a Core 2 Duo)... then these aren't
fast enough, sorry. :(
Try going into the Settings -> Advanced menu, then pick a different audio
driver and restart higan. WASAPI can be fussy on some devices.
Select Settings -> Audio and experiment with the latency. Larger values
should be more reliable, with the downside of laggier game controls.
Occasionally software that hooks into the system or other apps, for example
mouse settings panels, can cause lag and other problems.
Because higan is CPU-intensive and single-threaded, it can interact badly
with video capture which is yet another burden on the system. If you're
trying to stream or broadcast, and you have Windows 7, consider disabling
DWM. Also, look up how to configure hardware encoding (eg. QuickSync).
Q: Can I get smoother video?
A: Try Settings -> Video -> Exclusive mode, then switch to fullscreen. This
currently requires the Direct3D video driver under Settings -> Advanced
in order to work.
(Exclusive fullscreen is pretty experimental at the moment.
There are cases where it fails badly, so save your work!)
Exclusive mode will normally yield what's known as "tearing." If this
bothers you, there's an alternative... albeit one with serious gotchas,
which is why it's hidden away.
Close higan, then open up settings.bml and look for the following:
Video
Driver:Direct3D
Synchronize:false
...
Change false to true, save the file, then start higan and untick
Settings -> Synchronize Audio.
Keep in mind that this setting can and will reduce sound quality, as GPUs
and sound cards in modern PCs generally are not synchronised with each
other. The second big consideration is that your refresh rate needs to
match the game.
PAL and NTSC titles run at 50 Hz and 60 Hz, respectively. This applies to
all console systems. Of the handhelds: Game Boy, Game Boy Color and
Game Boy Advance run at 60 Hz, while WonderSwan runs at 75 Hz.
This means you'll need a monitor that supports these frequencies, set to
the appropriate display mode. Not all of them do. If your refresh rate
doesn't match, games will run at the wrong speed.
Online Resources
----------------
Official homepage + forum:
https://byuu.org/emulation/higan
https://board.byuu.org/viewforum.php?f=4
Unoffical source code repository + documentation:
https://gitlab.com/higan/higan
https://higan.readthedocs.io
Info on game folders and firmware:
https://byuu.org/emulation/higan/game-paks
https://byuu.org/emulation/higan/firmware
Donations:
https://patreon.com/byuu
Commercial use:
https://byuu.org/emulation/higan/licensing
Credits
-------
Original author:
byuu
We'd like to acknowledge many invaluable contributions made to higan
by the following individuals:
Andreas Naive Hendricks266 Overload
Ange Albertini hex_usr p4plus2
anomie jchadwick quequotion
AWJ Jonas Quinn RedDwarf
Bisqwit kode54 Richard Bannister
blargg krom Ryphecha
Łukasz Krawczyk Lioncash segher
Cydrak Lord Nightmare Sintendo
Danish lowkey SuperMikeMan
DMV27 MerryMage tetsuo55
Dr. Decapitator Matthew Callis TmEE
endrift mightymo TRAC
Fatbag Nach wareya
FitzRoy ncbncb zones
gekkio neviksti
GIGO OV2
It's been a long, wild ride... apologies to anyone we've missed!
For more information, please see:
https://board.byuu.org/viewtopic.php?f=4&t=1631&p=41575#p41575
License
-------
higan is provided under the GNU General Public License, version 3.
However, certain libraries may be used under the more permissive ISC license.
Please see LICENSE.txt for details.

View File

@@ -1,89 +1,99 @@
What is a game folder?
----------------------
A game folder
is higan's way of grouping all
the information and resources required
to properly emulate a particular game.
For example,
to represent a Super Famicom game named `dkc3`,
higan would create a game folder named `dkc3.sfc`,
and inside it store the game data as `program.rom`
and the save data as `save.ram`:
TODO
```python
+- Super Famicom
|
+- dkc3.sfc
|
+- program.rom
|
+- save.ram
```
In contrast,
other emulators typically
group resources related to a game
by requiring that every file has the same base name
but different file extensions.
For example,
if another emulator loaded the game `dkc3.sfc`
it might store the save data in `dkc3.srm`:
```python
+- Super Famicom
|
+- dkc3.sfc
|
+- dkc3.srm
```
Why game folders?
-----------------
A game is more than just
the raw data originally encased in a game's ROM chip.
If a game allows you to save your progress,
that information needs to be stored somewhere.
If you use an emulator's [save states](#save-states),
those save states need to be stored somewhere.
If you use Game Genie or Pro Action Replay codes,
information about what codes exist,
what codes are enabled,
and what they do
needs to be stored somewhere.
A file extension doesn't offer
much room for description,
so the traditional name-based-grouping system
only really works when games use a small number of files,
Also,
since file extensions traditionally describe
the format of the file in question,
it also means a game can't use
two or more files in the same format.
On the technical side,
a physical game cartridge contains a circuit board
that makes the game data available to the console,
and different games used circuit boards that work differently.
That circuit-layout information needs to be stored somewhere.
Some games included custom processors
to do calculations the base console could not do quickly enough
(like the SuperFX chip used in _StarFox_ for the Super Famicom)
and information about extra chips needs to be stored somewhere.
Some of those custom processors require extra data to work
that's not part of the main game data
(like the DSP chip used in Super Mario Kart for the Super Famicom)
and that data needs to be stored somewhere too.
Compared to other emulators,
higan can use a larger number of files per game.
For example,
higan's low-level emulation of Super Famicom co-processors
often requires [separate firmware files][firmware].
higan's [MSU-1 feature][msu1]
supports up to 99 audio tracks per game,
and higan supports up to 133 save-states per game.
Thus,
higan suffers from the limitations of name-based-grouping
more than most.
higan keeps all this game-related information together
in a single place:
a game folder in the higan library.
higan's game folders allow a game
to have unique, descriptive filenames
for all its resources,
and for each file to use the extension
that's most appropriate.
They also allow emulator-specific extras
like save-states and the cheat database
to be kept separate from the game's actual data,
by putting it in a sub-folder.
[msu1]: ../guides/import.md#msu-1-games
[firmware]: ../guides/import.md#games-with-co-processor-firmware
For a more detailed motivation for game folders,
see [Game Paks on the higan website][gp]
see [Game Paks on the higan website][gp].
[gp]: https://byuu.org/emulation/higan/game-paks
What is a manifest?
-------------------
TODO
The most important file in a game folder is `manifest.bml`,
which describes how all the other files should be wired together
to create a runnable game cartridge.
However,
the manifest format has occasionally changed
as new emulation details were uncovered
that could not be represented in the old format.
Therefore,
icarus [defaults](#the-icarus-settings-dialog)
to not writing out manifests when it imports games,
and higan [defaults](#the-configuration-dialog)
to ignoring manifests that are present.
Instead,
when higan loads a game,
it will ask icarus to generate a temporary manifest in the latest format,
based on the files present in the game folder
and how they are likely to go together.
You can view this temporary manifest
in [the Manifest Viewer](#the-manifest-viewer).
What's in a game folder?
------------------------
As mentioned [above](#why-game-folders),
a game folder collects all the information relevant
A game folder collects all the information relevant
to emulating a particular game.
Not all of the following files
are relevant to every emulated console,
or to every game on a given console,
but they may be relevantunder particular circumstances.
are relevant for every console,
or even for every game on a console,
but they may be present under particular circumstances.
All the files directly in the game folder
are expected to be useful
to all emulators that support them:
- `manifest.bml`:
The [manifest](#what-is-a-manifest)
for this game folder.
The [manifest](manifests.md) for this game folder.
- `program.rom`:
For most consoles,
this contains
@@ -97,7 +107,7 @@ to all emulators that support them:
from the cartridge's ROM chips.
- `ines.rom`:
While other consoles typically include enough hints
in `program.rom` for icarus to generate a manifest,
in `program.rom` for icarus to guess a working manifest,
the Famicom does not.
Famicom games not stored in game folders
typically include an "iNES header" to store that information,
@@ -106,36 +116,31 @@ to all emulators that support them:
Games that include a save feature
will create this file.
Note that it is only written to disk
when higan exits gracefully,
when higan exits gracefully;
if higan crashes or is forced to quit,
in-game saves may be lost.
Other emulators sometimes call this an "SRAM file",
even though the same filename is used
for cartridges that use EEPROM or Flash storage,
with games that included EEPROM or Flash storage,
not just battery-backed Static RAM.
- `rtc.ram`:
Games that include a calendar or real-time clock
will create this file.
- `*.data.rom`, `*.program.rom`:
Files named like this are usually
[co-processor firmware](#importing-and-playing-games-with-co-processor-firmware).
Files named like this are usually [co-processor firmware][firmware].
- `msu1.rom`:
Holds streamable data for
[the MSU-1](#importing-and-playing-MSU-1-games).
Holds streamable data for [the MSU-1][msu1].
- `track-*.pcm`:
Holds streamable audio for
[the MSU-1](#importing-and-playing-MSU-1-games).
Holds streamable audio for [the MSU-1][msu1].
Files that are only useful to higan specifically
are placed in a `higan` subdirectory:
are placed in a `higan` sub-folder:
- `cheats.bml`:
All information present in
[the Cheat Editor](#the-cheat-editor)
[the Cheat Editor](../interface/higan-tools.md#the-cheat-editor)
is stored here.
- `states/quick/slot-*.bst`:
All the save states made to
[Quick state slots](#quick-states).
All [Quick States](save-states.md#quick-states) are stored here.
- `states/managed/slot-*.bst`:
All the save states made with
[the State Manager](#the-state-manager).
All [Manager States](save-states.md#manager-states) are stored here.

View File

@@ -1,56 +1,87 @@
higan maintains a "game library"
containing all the games you've played.
The game library
is the folder where all the
[game folders](game-folders.md) go.
When [icarus](../interface/icarus.md) imports a game,
it creates or updates
the corresponding game folder in the game library.
When you use the console sub-menu items
in [higan's Library menu](../interface/higan.md#the-library-menu),
higan shows you the games for that console
that are already in the library.
- In Windows,
the default location of
the game library is the `Emulation` folder
inside your profile folder
(To find your profile folder,
press `Win+R` to open the Run dialog,
then type `%USERPROFILE%` and press Enter).
- In Linux,
the default location of
the game library is the `Emulation` directory
inside your home directory.
- On all platforms,
the game library location can be configured.
See [Moving the Game Library](#moving-the-game-library)
below.
Inside the library directory there is a subdirectory for each system,
and inside each system directory are the game folders
Inside the game library folder
there is a sub-folder for each system.
Inside each system folder
are the game folders
for each imported game.
For more information about game folders,
see [Why game folders?](#why-game-folders)
and [What's in a game folder?](#whats-in-a-game-folder)
Why a game library?
-------------------
higan [requires game folders](game-folders.md#why-game-folders),
but it also invented game folders,
so existing games need
to be converted to game folder format
before higan can play them.
The converted copy of a game needs to go *somewhere*.
Also,
for people who have a huge collection of games,
the game library only lists the games they actually play,
rather than every possible game,
making it easier to find the games they like.
Where is the game library?
--------------------------
In Windows,
the default location of
the game library is the `Emulation` folder
inside your profile folder
(To find your profile folder,
press `Win+R` to open the Run dialog,
then type `%USERPROFILE%` and press Enter).
In Linux,
the default location of
the game library is the `Emulation` directory
inside your home directory.
On all platforms,
the game library location can be configured.
See [Moving the Game Library](#moving-the-game-library)
below.
Moving the game library
-----------------------
Moving the game library is a little complicated,
because there's two parts to it:
because there are two parts to it:
telling icarus where to put imported games,
and telling higan where to find them.
1. If necessary,
create the folder you want higan to use
1. Move your existing game library folder
to the new location,
or otherwise create the folder you want higan to use
as its game library.
1. Launch icarus,
then click the "Settings ..." button in the lower-right,
to open the Settings dialog.
to open
[the Settings dialog][icsettings].
1. Click the "Change ..." button on the right.
A [filesystem browser](#the-filesystem-browser) window will appear,
A [filesystem browser][fsbrowser] window will appear,
allowing you to choose
where imported games will be stored.
1. Launch higan,
then from the Settings menu,
choose "Configuration ..."
to open [the Configuration dialog](#the-configuration-dialog).
1. Click the Advanced tab
then click the "Change ..." button.
A [filesystem browser](#the-filesystem-browser) will appear,
allowing you to choose the same directory again.
then from [the Settings menu][settingsmenu],
choose "Advanced ..."
to open [higan's Advanced settings][advsettings].
1. Click the "Change ..." button on the right.
A [filesystem browser][fsbrowser] will appear,
allowing you to choose the same folder again.
[icsettings]: ../interface/icarus.md#the-icarus-settings-dialog
[fsbrowser]: ../interface/common.md#the-filesystem-browser
[settingsmenu]: ../interface/higan.md#the-settings-menu
[advsettings]: ../interface/higan-settings.md#advanced

142
docs/concepts/manifests.md Normal file
View File

@@ -0,0 +1,142 @@
If a [game folder](game-folders.md) is
the emulation equivalent of
a physical game cartridge,
a manifest is like
the circuit board inside the cartridge:
it connects all the other parts together
and to the console itself.
If you load a game into higan,
you can look at the game's manifest
by opening [the Tools menu](../interface/higan.md#the-tools-menu)
and choosing [Manifest Viewer](../interface/higan-tools.md#the-manifest-viewer).
Why manifests?
--------------
For most consoles,
a manifest isn't strictly necessary:
the raw game data provides enough clues
for emulators to guess the circuit board configuration,
or at least
to guess a *reasonable* configuration.
However,
relying on such heuristics often leads to problems:
- Inventing heuristics
that correctly guess the configuration
for a particular game is very difficult.
- If you change the rules,
you really need to re-test
the console's entire game library
to check you haven't broken anything.
- Some games accidentally do the wrong thing.
- The Mega Drive game *Warrior of Rome II*
follows the rule for a European game running at 50fps,
when it's really an American game designed for 60fps.
- Some games deliberately do the wrong thing.
- The Game Boy Advance game *Top Gun - Combat Zones*
follows the rule for
(several kinds of)
save-game storage.
If it detects any save-game storage,
it assumes it's running in an emulator
and disables all the main menu options.
- Heuristics are difficult to reason about.
- If a homebrew developer
takes a game that almost does what they want
and changes it slightly,
it may cause the emulator
to do something completely different
because the modified game
is now a closer match to some other game.
- Heuristics can make sensible configurations impossible.
- If a homebrew developer wants
a particular hardware configuration
that no official games happened to use,
it may not be possible
to trigger it heuristically.
- It's not hardware accurate.
- The original console did not use heuristics
to guess a hardware configuration,
it just used the actual configuration
of the actual hardware.
Manifests provide a way to describe
*exactly* what hardware configuration to use,
no guessing required,
avoiding all these problems entirely.
Where do manifests come from?
-----------------------------
Ideally,
everybody who extracts the data from a game cartridge would
also record the board configuration in a manifest file.
Unfortunately,
manifests were invented long after cartridge extracting,
so there are a lot of previously extracted games
with no manifest attached.
If a game doesn't come with a manifest,
it may be possible to look up the correct manifest.
The
[SNES Preservation Project](https://preservation.byuu.org/)
intends to re-dump every Super Famicom game
and record its board configuration at the same time.
Given a game's data,
you can take the SHA256 fingerprint
and look it up in the Project's database
to find the correct manifest to use.
Unfortunately,
this doesn't help for any other console.
Even for the Super Famicom,
there will always be games
too rare to acquire for re-dumping,
and homebrew that was never on a physical cartridge to begin with.
For these games,
heuristics will always be needed as a fallback,
but at least if the heuristics are wrong
they can be overridden.
Ignoring manifests
------------------
Occasionally,
a newly-dumped game will turn out to have
a configuration that can't be expressed
in the existing manifest file format,
and a new format must be designed.
If manifests were always written inside game folders,
games with old-format manifests
would break when played in emulators that supported the new format.
Therefore,
icarus [defaults](../interface/icarus.md#the-icarus-settings-dialog)
to not writing out manifests when it imports games,
and higan [defaults](../interface/higan-settings.md#advanced)
to ignoring manifests that are present.
Instead,
when higan loads a game,
it will ask icarus to generate a temporary manifest in the latest format,
based on the files present in the game folder
and how they are likely to go together.
If the manifest that icarus generates
for some particular game
is broken or buggy,
you'll need to switch the manifest machinery back on
so you can fix it:
- Turn on "Create manifests" in icarus' settings
- Re-import the game in question
to store the broken manifest
as `manifest.bml` in the game folder.
- Edit `manifest.bml` as you see fit
- Turn off "Ignore manifests" in higan's settings
- Load the game in higan to check that your changes fixed the problem
If the manifest format changes in the future,
you'll have to repeat this process
to create a fixed manifest in the new format.

View File

@@ -105,12 +105,12 @@ higan has five Quick State slots,
which can be used from
[the Tools menu](../interface/higan.md#the-tools-menu),
or with the appropriate
[hotkeys](../interface/higan-config.md#hotkeys).
[hotkeys](../interface/higan-settings.md#hotkeys).
Quick states are useful
as extra checkpoints
in games that don't have them,
or where they aren't close enough together.
in games whose checkpoints are too far apart,
or in games that don't have checkpoints at all.
Map the "Save Quick State" and "Load Quick State" hotkeys
to your controller,
and you can cheese your way through just about anything.

62
docs/credits.md Normal file
View File

@@ -0,0 +1,62 @@
higan's original author:
- byuu
We'd like to acknowledge
many invaluable contributions made to higan
by the following individuals:
- Andreas Naive
- Ange Albertini
- anomie
- AWJ
- Bisqwit
- blargg
- Łukasz Krawczyk
- Cydrak
- Danish
- DMV27
- Dr. Decapitator
- endrift
- Fatbag
- FitzRoy
- gekkio
- GIGO
- Hendricks266
- hex_usr
- jchadwick
- Jonas Quinn
- kode54
- krom
- Lioncash
- Lord Nightmare
- lowkey
- MerryMage
- Matthew Callis
- mightymo
- Nach
- ncbncb
- neviksti
- OV2
- Overload
- p4plus2
- quequotion
- RedDwarf
- Richard Bannister
- Ryphecha
- segher
- Sintendo
- SuperMikeMan
- tetsuo55
- TmEE
- TRAC
- wareya
- zones
It's been a long, wild ride...
apologies to anyone we've missed!
For more information,
see the [credits thread](
https://board.byuu.org/viewtopic.php?f=4&t=1631&p=41575#p41575)
on the official forums.

View File

@@ -1,15 +1,14 @@
I see "tearing" when a game scrolls. How can I enable vsync?
------------------------------------------------------------
higan supports synchronizing video output
to the display's vertical-synchronization (or "vsync") signal,
higan supports synchronising video output
to the display's vertical-synchronisation (or "vsync") signal,
but the option is hidden
because it often causes more problems than it solves
(see the next question).
To enable video synchronisation:
To enable video synchronization:
- Open the higan's configuration file, `settings.bml`
- Open higan's configuration file, `settings.bml`
- On Windows, look in `%LOCALAPPDATA%\higan`
or beside `higan.exe`
- On Linux, look in `~/.local/share/higan`
@@ -23,19 +22,19 @@ To enable video synchronization:
- Save your changes to `settings.bml`
and restart higan
Why is video synchronization a problem for higan?
Why is video synchronisation a problem for higan?
-------------------------------------------------
**The short version:**
Turning on video synchronization
Turning on video synchronisation
cleans up video tearing,
turning on audio synchronization
turning on audio synchronisation
cleans up audio glitches,
but turning on both
makes audio glitches worse.
**The long version:**
Enabling video synchronization
Enabling video synchronisation
locks the frame-rate of the emulated console
to the frame-rate of your computer's display.
If your display's refresh rate exactly matches
@@ -50,20 +49,20 @@ the emulated console's refresh rate:
- The Super Famicom usually runs a little faster than 60Hz
- the PAL variants of most consoles run at 50Hz
- the WonderSwan runs at 75Hz
- While the Game Boy does run its LCD at 60Hz
it can turn it off and on at any time,
- While the Game Boy does run its LCD at 60Hz,
games can turn the LCD off and on at any time,
requiring emulation to pause
until it can get back in sync
with the computer display.
Because of these frame-rate differences,
enabling video synchronization
enabling video synchronisation
can force games to run
faster or slower than intended.
The consoles that higan emulates
produce video frames and audio samples at a particular rate.
If video synchronization causes
If video synchronisation causes
the emulated console to run, say, 5% faster than intended,
that means audio samples are also being produced 5% faster.
You might not notice the changed game speed,
@@ -72,9 +71,9 @@ the game's audio glitching constantly
as your sound card tries to keep up.
Enabling
[audio synchronization](interface/higan.md#the-settings-menu)
[audio synchronisation](interface/higan.md#the-settings-menu)
normally fixes this kind of audio glitching,
but with video synchronization it makes things worse:
but with video synchronisation it makes things worse:
audio is likely to glitch
while higan waits for a video frame to be shown,
and video is likely to stutter
@@ -86,21 +85,24 @@ Games run too fast
higan runs as fast as it can,
but it will pause and wait
for the audio and video drivers to catch up
if [Synchronize Audio](interface/higan.md#the-settings-menu)
and [video synchronization][vsync]
if [audio synchronisation](interface/higan.md#the-settings-menu)
and [video synchronisation][vsync]
are enabled, respectively.
If games are running way too fast, here's some things to check:
If games are running way too fast, here are some things to check:
- Make sure "Synchronize Audio" is ticked in
[the Settings menu](interface/higan.md#the-settings-menu)
- Make sure the Audio driver is not set to "None"
in [the Advanced settings](interface/higan-config.md#advanced)
in [the Advanced settings](interface/higan-settings.md#advanced)
(remember to restart higan if you change driver settings)
- Make sure your computer has speakers or headphones connected
(some computers disable all audio if no ouputs are available)
(some computers disable all audio if no outputs are available)
- If you want the game to be silent,
tick "Mute Audio" in
[the Settings menu](interface/higan.md#the-settings-menu)
- If you can't connect speakers or headphones to your computer,
or you did but it didn't help,
try enabling the secret [video synchronisation][vsync] option.
[vsync]: #i-see-tearing-when-a-game-scrolls-how-can-i-enable-vsync
@@ -114,17 +116,17 @@ Full-speed emulation for the Super Famicom base unit
requires an Intel Core 2 Duo (or AMD equivalent),
full-speed for games with the SuperFX chip
requires an Intel Ivy Bridge (or equivalent),
full-speed for the wireframe animations in Mega Man X2
full-speed for the wire-frame animations in *Mega Man X2*
requires an even faster computer.
Low-power CPUs like ARM chips,
or Intel Atom and Celeron CPUS
or Intel Atom and Celeron CPUs
generally aren't fast enough to emulate the Super Famicom with higan,
although other emulated consoles may work.
If your computer meets the general speed requirements
but games run too slowly,
try choosing a different
[audio driver](interface/higan-config.md#advanced),
[audio driver](interface/higan-settings.md#advanced),
since that's usually what drives higan's timing.
On some computers,
@@ -134,7 +136,7 @@ may be confused by higan's unusual pattern of CPU usage
and the next few milliseconds of audio,
then stops dead as it waits for output to complete).
If holding down
the [fast forward hotkey](interface/higan-config.md#hotkeys)
the [fast forward hotkey](interface/higan-settings.md#hotkeys)
runs too fast but the game normally runs too slow,
try disabling "power saver" mode
or enabling "performance" mode.
@@ -165,11 +167,11 @@ Games can and do depend on timing details like
it will interrupt the CPU at exactly the right time
for the CPU to fiddle with the video chip".
higan is therefore very cautious about timing:
while it's emulating the audio chip (for example),
at every point the emulated CPU *might* interrupt
the emulated audio chip,
higan switches to emulating the CPU up to the same point
to find out whether the CPU *will* interrupt it.
while it's emulating the CPU (for example),
at every point the emulated audio chip *might* interrupt
the emulated CPU,
higan switches to emulating the audio chip up to the same point
to find out whether it *will* interrupt the CPU.
In this way,
higan is a little bit like
@@ -177,8 +179,8 @@ an office-worker trying to do the jobs of three other people
by running from desk to desk,
sending the same emails
that those three people would send to each other,
leaving themselves a note at each desk to remind themselves
where they were up to when they come back.
leaving itself a note at each desk to remind it
where it was up to when it comes back.
Although this constant switching
is slow and inefficient,
higan does it
@@ -221,8 +223,8 @@ Why can't higan use multiple CPU cores?
These days,
most computers contain multiple CPU cores,
allowing them to run different programs,
or different parts of the same program
allowing them to run different programs
(or different parts of the same program)
at the same time.
Since higan requires high CPU performance,
sometimes people suggest that it should split its work
@@ -246,7 +248,7 @@ device B will have finished operation Y
and be ready to do something new.
Meanwhile, higan's emulated components
take an unpredictable amount of time to do their work,
so without deliberate synchronization
so without deliberate synchronisation
things would break almost immediately.
It's not practical to make higan's emulated devices
@@ -254,26 +256,28 @@ do their work in exactly the same amount of time
as their hardware counterparts.
The problem is forty years of technology
designed to make programs run as fast as possible:
optimizing compilers and superscalar, out-of-order CPU architectures
optimising compilers
and super-scalar, out-of-order CPU architectures
change programs to make them faster,
speeding up some programs more than others
in ways that are very difficult to understand and predict.
Even if higan's emulated devices
ran at the exact, correct speed
on one particular computer,
they'd still run differently on any other computer,
or with a smarter compiler,
or with a smarter CPU.
they'd still run differently on
a computer with a smarter CPU,
or when compiled with a smarter compiler.
Since higan needs its emulated components
to run at particular speeds,
and they won't run at those speeds naturally,
and it's not practical
to make them run at those speeds naturally,
it must force them manually.
An emulated device runs for a little while,
then all the others are run until they catch up.
It's this careful management,
regular stopping and starting,
that makes higan slow,
not the actual emulation of each device,
and so it doesn't make sense
for higan to be multi-threaded.
not the actual emulation of each device.
Having multiple CPU cores waiting on each other
would not help them wait any faster.

View File

@@ -1,11 +1,10 @@
Unfortunately,
there's no standard for
there's no cross-platform standard for
displaying video,
playing audio,
and accepting input from game controllers
that works on every operating system.
and accepting input from game controllers.
Or rather,
there's many standards,
there are many standards,
and different ones work best
on different computers.
Therefore,
@@ -15,12 +14,12 @@ so you can find the one that works best for you.
To see what drivers you're currently using,
or to choose different ones,
go to
[the Advanced tab](../interface/higan-config.md#Advanced)
[the Advanced tab](../interface/higan-settings.md#advanced)
of the Settings window.
Here are the most notable drivers
for each platform
for each category.
in each category.
If your copy of higan
includes a driver not listed here,
it's probably a reasonable choice,
@@ -44,15 +43,15 @@ Video
On Windows:
- **OpenGL** is usually the best choice,
since it supports [custom shaders](shaders.md),
however it does require support for OpenGL 3.2
which excludes some integrated graphics chipsets
and old graphics cards.
- **OpenGL** is the best choice,
since it's fast
and it supports [custom shaders](shaders.md),
but requires support for OpenGL 3.2.
This excludes some older and weaker hardware.
- **Direct3D** is a good choice
if OpenGL is unavailable.
It also allows
[Exclusive fullscreen](../interface/higan-config.md#video),
[Exclusive fullscreen](../interface/higan-settings.md#video),
bypassing Windows' desktop compositor.
- **GDI** is the safest choice,
but performs very poorly at large sizes.
@@ -62,7 +61,7 @@ On Linux:
- **OpenGL** is the best choice,
since it's fast
and it supports [custom shaders](shaders.md),
but requires OpenGL 3.2.
but requires support for OpenGL 3.2.
You can check what version of OpenGL
your system supports by running
`glxinfo | grep 'core profile version'`
@@ -82,9 +81,9 @@ On Windows:
- **ASIO** offers the lowest possible latency,
but is the least likely to work on any given computer.
- **WASAPI** offers low latency,
but is only slightly more likely to work.
but is only slightly more likely to work than ASIO.
It also offers
[Exclusive Mode](../interface/higan-config.md#audio),
[Exclusive Mode](../interface/higan-settings.md#audio),
which can improve audio quality and lower latency,
but may be better or worse than shared mode
in practice.
@@ -121,12 +120,11 @@ On Linux:
PulseAudio's OSS emulation,
or not work at all.
TODO: If the audio driver is set to None,
or you have no audio device,
Sync Audio does not work
and games will run in fast-forward
unless you enable Sync Video.
https://board.byuu.org/viewtopic.php?p=44138#p44138
**Note:**
By default,
higan uses the audio driver to regulate its emulation speed.
If games run too fast on your computer,
see [Games run too fast](../faq.md#games-run-too-fast) in the FAQ.
Input
-----

View File

@@ -5,33 +5,62 @@ be stored correctly in
For [regular games](#regular-games)
this is simple,
but some games require special treatment,
especially games that make use of
especially those that make use of
unusual hardware.
Regular games
-------------
icarus supports importing games
higan's importing tool, icarus, can import games
in the most commonly-used formats
for each supported console,
and also those same formats inside `.zip` files.
and also those same formats inside `.zip` files
(as long as the `.zip` file contains only one game).
More advanced compression formats
like RAR or 7-zip are not supported.
For most games
that do not use special chips or co-processors,
importing a game is straight-forward.
From [the Library menu](#the-library-menu)
To import a game,
open [the Library menu](../interface/higan.md#the-library-menu),
choose "Load ROM File ..."
to open [a filesystem browser](#the-filesystem-browser),
choose the game you want to play,
and it will be imported into the library and loaded.
to open [a filesystem browser](../interface/common.md#the-filesystem-browser),
choose the ROM file of the game you want to play,
and it will be imported into the library and start playing.
To play the game again
select the console the game runs on from
[the Library menu](#the-library-menu)
to open another [filesystem browser](#the-filesystem-browser)
that lists all the previously-imported games for that platform.
**Note:**
If you want to import many games,
run icarus directly,
or choose "Import ROM Files ..."
from the Library menu
(which just runs icarus anyway).
See [the icarus documentation](../interface/icarus.md) for details.
To play a game for a particular console from your library,
open the Library menu,
pick the console manufacturer sub-menu
(Nintendo for the Super Famicom,
Bandai for the WonderSwan,
etc.)
then choose the appropriate console menu item.
A filesystem browser will appear
listing all the games in the library
for that particular console.
Select the game you want to play
and click the Open button,
or just double-click the game,
and it will begin playing.
**Note:**
Sometimes
the NTSC and PAL variants of a particular console
behave differently,
or the Japanese and American variants.
When choosing a game from the Game Library,
a drop-down list in the bottom-right of the filesystem browser
allows you to choose which regional variant
of the console higan should emulate.
For most consoles,
higan can reliably guess which variant to use,
and the list defaults to "Auto".
Games with co-processor firmware
--------------------------------
@@ -43,7 +72,7 @@ those extra chips were separate CPUs
running their own separate firmware,
and for those cases
higan requires a copy of the co-processor firmware
as well as the actual game.
as well as the actual game data.
Unfortunately,
like games themselves,
co-processor firmware cannot legally be distributed,
@@ -52,14 +81,31 @@ copies of the relevant firmware data
yourself.
To import a game that requires co-processor firmware,
you must copy the required firmware files
beside the game you want to import.
you must first combine the game data and the firmware into a single file.
For example,
if you want to import Megaman X2,
which is stored in the file `mmx2.sfc`,
the file `cx4.data.rom`
must be placed in the same folder
for the import to succeed.
let's say you want to import *Super Bases Loaded 2* for the Super Famicom,
which is stored in the file `sbl2.sfc`
and requires firmware for the DSP1 co-processor
stored in `dsp1.program.rom` and `dsp1.data.rom`.
On Windows,
you can combine them from the command-line like this:
```dos
copy /b sbl2.sfc + dsp1.program.rom + dsp1.data.rom
```
On Linux,
the equivalent command-line syntax is:
```bash
cat dsp1.program.rom dsp1.data.rom >> sbl2.sfc
```
(note the use of `>>` to append rather than `>` to overwrite)
**Note:**
For co-processor chips with multiple firmware files,
you must put the "program" file before the "data" file.
Wikipedia [lists which Super Famicom games use which co-processors][wpec],
although not all co-processors require separate firmware.
@@ -183,42 +229,41 @@ but the firmware inside is identical.
**Note 2:**
The DSP1B is very similar to the DSP1A,
but has some bugs fixed.
but fixes some bugs.
Note that icarus' heuristics cannot distinguish between
a game that uses DSP1
and one that uses DSP1B,
a game that uses the DSP1
and one that uses the DSP1B,
so if it cannot find your game in its manifest database,
it will assume it uses DSP1B.
Many games work just as well with either DSP1 or DSP1B,
but Pilotwings is a notable exception.
Many games work just as well with either variant,
but *Pilotwings* requires the DSP1 firmware,
while *Ballz 3D* requires the DSP1B.
If you try to import a game
using the "Import ROM Files ..." option
in [the Library menu](#the-library-menu)
in [the Library menu](../interface/higan.md#the-library-menu)
(or using icarus directly)
but do not have the required firmware files
in the correct place,
but it does not include the correct firmware data,
a window will appear saying
"Import completed, but with 1 errors. View log?"
(or howevery many games were lacking the correct firmware).
(or however many games were lacking the correct firmware).
If you press "Yes",
a new window will appear listing the games that couldn't be imported,
and at least one firmware file that was missing or incorrect, like this:
and what problem was detected:
> [smk.zip] firmware (dsp1b.program.rom) missing or invalid
> [sbl2.sfc] ROM image is missing DSP1 firmware data
If you try to import a game
using the "Load ROM File ..." option
in [the Library menu](#the-library-menu)
but do not have the required firmware files
in the correct place,
in [the Library menu](../interface/higan.md#the-library-menu)
but it does not include the correct firmware data,
nothing will happen,
and higan will just sit there
with "No cartridge loaded" in
[the status bar](#the-status-bar).
[the status bar](../interface/higan.md#the-status-bar).
Once a game with co-processor firmware is imported,
you can play it just like any [regular game](#importing-and-playing-regular-games).
you can play it just like any [regular game](#regular-games).
Satellaview games
-----------------
@@ -234,13 +279,13 @@ browse online services,
and download games and data.
This control cartridge was called
*BS-X Sore wa Namae o Nusumareta Machi no Monogatari*,
which translates as
which in English is
*BS-X The Story of The Town Whose Name Was Stolen*.
[wpbsx]: https://en.wikipedia.org/wiki/Satellaview
The control cartridge had a slot that accepted
rewritable "memory paks",
re-writable "memory paks",
so that people could store the games and data they downloaded.
A small number of games that did not use the Satellaview modem
also had a memory pak slot,
@@ -254,7 +299,7 @@ were sold in retail stores
containing extra content for specific games.
Importing a game that has a slot for a memory pak
is just like [importing a regular game](#importing-and-playing-regular-games).
is just like [importing a regular game](#regular-games).
Importing a memory pak is like importing a regular game,
but the name of the memory pak file *must* end in `.bs`
@@ -263,17 +308,17 @@ that's OK,
but the name *inside* the `.zip` file
must end in `.bs`)
in order for it to be successfully imported.
Sometimes memory pak filenames end in `(BSROM).sfc`,
Sometimes memory pak filenames end in `.sfc`,
which will make higan try to import them as
regular Super Famicom games,
and fail miserably.
regular Super Famicom games
and fail.
Rename the file and it should work beautifully.
Playing a game that has a slot for a memory pak
is just like playing a regular game,
but after you have selected which game you want to play
higan will open another
[filesystem browser](#the-filesystem-browser)
[filesystem browser](../interface/common.md#the-filesystem-browser)
to let you pick which previously-imported memory pak
you want to insert into the game.
If you press "Cancel" at this point,
@@ -282,7 +327,7 @@ the game will load without any cartridge in its memory pak slot.
If you load the control cartridge into higan,
make sure the emulated Satellaview
is connected to the emulated Super Famicom's expansion port
by going to the "Super Famicom" menu,
by opening the "Super Famicom" menu,
selecting the "Expansion Port" sub-menu,
and choosing "Satellaview".
If the expansion port was previously
@@ -318,16 +363,16 @@ but some games can make use of additional data
from a game in slot B.
Importing the Sufami Turbo cartridge
is just like [importing a regular game](#importing-and-playing-regular-games).
is just like [importing a regular game](#regular-games).
Importing a mini-cartridge is like importing a regular game,
but the name of the memory pak file *must* end in `.st`
but the name of the mini-cartridge file *must* end in `.st`
(if it's in a `.zip` file,
that's OK,
but the name *inside* the `.zip` file
must end in `.st`)
in order for it to be successfully imported.
Sometimes memory pak filenames end in `(ST).sfc`,
Sometimes mini-cartridge filenames end in `.sfc`,
which will make higan try to import them as
regular Super Famicom games,
and fail miserably.
@@ -336,7 +381,7 @@ Rename the file and it should work beautifully.
To play a Sufami Turbo game,
load the Sufami Turbo cartridge like any other game.
higan will open another
[filesystem browser](#the-filesystem-browser)
[filesystem browser](../interface/common.md#the-filesystem-browser)
to let you pick which previously-imported mini-cartridge
you want to insert into slot A.
If you press "Cancel" at this point,
@@ -346,7 +391,7 @@ to turn off your Super Famicom,
insert a game into slot A,
and try again.
If you chose a cartridge for slot A,
higan will yet open another
higan will open yet another
filesystem browser
to let you choose a mini-cartridge for slot B.
If you press "Cancel" at this point,
@@ -362,17 +407,24 @@ released for the Super Famicom
(and all its regional variants around the world)
that allowed Game Boy games to be played
via the Super Famicom's controllers and video output.
The Super Game Boy 2 was released in Japan,
and had some minor extra features
beyond the original Super Game Boy,
but importing and playing games
works the same way in higan.
The Super Game Boy does not emulate the Game Boy hardware,
it physically includes all the Game Boy components
so compatibility with Game Boy games is high.
However, the Super Game Boy drives the Game Boy hardware
from the Super Famicom's timing signals, which means
games play 2.4% faster than on a real Game Boy.
The Super Game Boy cartrige includes
the complete hardware of an original
(black-and-white)
Game Boy,
so it needs a boot ROM:
The Super Game Boy 2 was a Japan-only release
that fixed the timing problem of the original Super Game Boy,
and included a different set of default borders.
higan supports the Super Game Boy 2 base cartridge,
so you can use the extra borders,
but does not yet emulate the timing change
so games still play slightly too fast.
Because the Super Game Boy cartridge includes
the original Game Boy hardware,
it needs a boot ROM:
<table>
<thead>
@@ -386,55 +438,53 @@ so it needs a boot ROM:
<tbody>
<tr>
<th scope="row">SGB</th>
<td><code>sgb.boot.rom</code></td>
<td><code>sgb1.boot.rom</code></td>
<td>256</td>
<td><code>0e4ddff32fc9d1eeaae812a157dd246459b00c9e14f2f61751f661f32361e360</code></td>
</tr>
<tr>
<th scope="row">SGB2</th>
<td><code>sgb.boot.rom</code></td>
<td><code>sgb2.boot.rom</code></td>
<td>256</td>
<td><code>fd243c4fb27008986316ce3df29e9cfbcdc0cd52704970555a8bb76edbec3988</code></td>
</tr>
</tbody>
</table>
Yes,
the SGB and SGB2 have different firmware,
but higan expects the same filename for both.
To import the SGB base cartridge,
you must copy the required firmware file
into the same directory.
Then you may import it just like
[a regular game](#importing-and-playing-regular-games).
you must first combine the base cartridge data
and the boot ROM into a single file,
just like
[games with co-processor firmware](#games-with-co-processor-firmware).
Then you may import it like [a regular game](#regular-games).
To play a Game Boy game in Super Game Boy mode,
load the Super Game Boy cartridge like any other game.
higan will open another
[filesystem browser](#the-filesystem-browser)
[filesystem browser](../interface/common.md#the-filesystem-browser)
to let you pick which previously-imported Game Boy game
you want to insert into the Super Game Boy.
If you press "Cancel" at this point,
higan will crash, so don't do that.
Note that only games for the original, black-and-white Game Boy
**Note:**
Only games for the original, black-and-white Game Boy
can be used with the Super Game Boy.
Some games designed for the Game Boy Color
were backward compatible with the original Game Boy
and hence the Super Game Boy;
see [Playing Game Boy Colour games in Game Boy mode][blackcarts]
see [Playing Game Boy Color games in Game Boy mode][blackcarts]
for details.
[blackcarts]: #playing-game-boy-color-games-in-game-boy-mode
[blackcarts]: ../notes.md#playing-game-boy-color-games-in-game-boy-mode
MSU-1 games
-----------
The MSU-1 is a fictional expansion chip
invented by higan's author byuu
for use with Super Famicom games,
designed to allow streaming data and audio.
invented by higan's author byuu,
designed to allow the Super Famicom
to stream data and audio.
Although the MSU-1 is not specific
to any particular storage medium,
it gives the Super Famicom similar capabilities
@@ -443,10 +493,18 @@ like the Mega Drive's Mega CD
and the PC Engine's CD-ROM²,
such as CD-quality music and full-motion video.
Although the MSU-1 was invented for higan,
it is now supported by other Super Famicom emulators too.
The [SD2SNES][sd2snes] programmable cartridge
even allows you to play MSU-1 games on a real console.
There are a number of homebrew games
that make use of the MSU-1,
and also mods for commercial Super Famicom games
that add higher-quality music and sometimes video.
One thing to be aware of
when importing an MSU-1 game
is that early firmware versions
of the [SD2SNES][sd2snes] programmable cartridge
is that early firmware versions of the SD2SNES
had a bug that caused MSU-1 music to play too quietly.
Skipping over [the full details][msu1vol],
the short version is this:
@@ -456,20 +514,20 @@ the short version is this:
- If an MSU-1 mod for a commercial game offers
"emulator" and "hardware" versions of the patch file,
it means the audio tracks are already boosted.
- Some
[third](https://www.zeldix.net/t1265-#18320)
[parties](https://www.zeldix.net/t1339-#19818)
have created replacement, non-boosted audio tracks
for the most popular MSU-1 mods.
If the mod you want to play has a replacement pack,
use it with the "hardware" version of the patch.
- Even without access to non-boosted audio tracks,
it may be that the existing audio is only slightly boosted,
so try the "hardware" version first, for best quality.
- If the audio tracks are heavily boosted,
the "hardware" patch may sound terrible,
distorting and clipping,
in which case try the "emulator" patch.
- Some
[third](https://www.zeldix.net/t1265-#18320)
[parties](https://www.zeldix.net/t1339-#19818)
have created replacement, non-boosted audio tracks
for the most popular MSU-1 mods.
If the mod you want to play has a replacement pack,
use it with the "hardware" version of the patch.
- Even without access to non-boosted audio tracks,
it may be that the existing audio is only slightly boosted,
so try the "hardware" version first, for best quality.
- If the audio tracks are heavily boosted,
the "hardware" patch may sound terrible,
distorting and clipping,
in which case try the "emulator" patch.
To import an MSU-1 game:
@@ -482,7 +540,7 @@ To import an MSU-1 game:
instead of these instructions.
2. Otherwise,
import the Super Famicom ROM with icarus,
[like a regular game](#importing-and-playing-regular-games).
[like a regular game](#regular-games).
- If this is a homebrew game with MSU-1 support,
there will probably be an ordinary ROM
whose name ends in `.sfc`,
@@ -495,7 +553,8 @@ To import an MSU-1 game:
then import the patched file.
- If there's "hardware" and "emulator" versions of the patch,
see "One thing to be aware of..." above.
3. Find the game folder in [the game library](#the-game-library)
3. Find the game folder in
[the game library](../concepts/game-library.md)
that icarus created when it imported the game.
4. Copy the MSU-1 data file into the game folder.
- This should be named `msu1.rom`
@@ -525,7 +584,7 @@ To import an MSU-1 game:
Once the game folder is set up,
playing an MSU-1 game is just like
[a regular game](#importing-and-playing-regular-games).
[a regular game](#regular-games).
[sd2snes]: https://sd2snes.de/
[flips]: http://www.romhacking.net/utilities/1040/
@@ -554,7 +613,118 @@ you will need to use a patcher to apply it yourself,
creating a new, patched copy of the game.
Then you can import and play the patched game just like
[a regular game](#importing-and-playing-regular-games).
[a regular game](#regular-games).
[rhdn]: http://www.romhacking.net/
Game Boy Advance games
----------------------
Before you can play Game Boy Advance games,
you must provide a copy of the Game Boy Advance BIOS.
Unlike game-specific firmware,
the GBA BIOS was part of the console,
not the cartridge,
so it must be installed
[into higan](../install/general.md).
Once the GBA BIOS is installed,
GBA games can be imported and played just like
[any other games](#regular-games).
Note that some GBA games
have trouble with
[in-game saves](../notes#in-game-saves-and-the-game-boy-advance).
PowerFest '94
-------------
[PowerFest '94](https://en.wikipedia.org/wiki/Nintendo_PowerFest_%2794)
was a video game competition
organised by Nintendo,
in which contestants had six minutes
to complete a challenge based on three Super Famicom games.
The PowerFest '94 cartridge
was custom-built for the competition,
and included the three base games
as well as software to run each game,
switch between them after a specific time,
extract a score,
and display the combined total at the end.
icarus cannot automatically import
dumps of the PowerFest '94 ROMs,
but if you have the files,
you can import them manually.
You will need the following files:
<table>
<thead>
<tr>
<th>Part</th>
<th>Filename</th>
<th>Size (bytes)</th>
<th>SHA256</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Scoring</th>
<td><code>program.rom</code></td>
<td>262144</td>
<td><code>2fc9dca305ce3fb2f1a476567de500d50c174fbfbabd32b1b91c3ea6a731b4a1</code></td>
</tr>
<tr>
<th scope="row">Super Mario Bros. - The Lost Levels</th>
<td><code>slot-1.rom</code></td>
<td>524288</td>
<td><code>7fd86113c5f95f794d65807bb75ab91c93c914670c27fc813ffa2ca20a48705e</code></td>
</tr>
<tr>
<th scope="row">Super Mario Kart</th>
<td><code>slot-2.rom</code></td>
<td>524288</td>
<td><code>19eb77affbf8dd068f5d79a3cf80a2084fd73237cd1ae4e47192b4422449e64a</code></td>
</tr>
<tr>
<th scope="row">Ken Griffey Jr. Presents Major League Baseball</th>
<td><code>slot-3.rom</code></td>
<td>1048576</td>
<td><code>d47bc9f9a6289c4f2e7f6bf74095f6ed36b1043a761e3e729ac9af2fc39ae062</code></td>
</tr>
</tbody>
</table>
You will also need
the usual `dsp1.program.rom` and `dsp1.data.rom`
[co-processor firmware](#games-with-co-processor-firmware) files.
**Note:** the versions of
*Super Mario Kart*
and *Ken Griffey Jr...*
in *PowerFest '94*
are not the same as the stand-alone versions of those games.
To "import" *PowerFest '94*,
collect all the files mentioned above, then:
1. Inside [the game library](../concepts/game-library.md),
create the `Super Famicom` folder
(if it does not already exist).
2. Inside the `Super Famicom` folder,
create a `PowerFest '94.sfc` folder
(the `.sfc` extension is important,
but you can choose a different base name if you want).
3. Copy the various ROM files into the `PowerFest '94.sfc` folder.
To play *PowerFest '94*,
open the Library menu,
pick the Nintendo sub-menu,
then choose the Super Famicom sub-menu item
to open a filesystem browser listing
all the Super Famicom games in the library.
Select *PowerFest '94* from the list
and click the Open button,
or just double-click the game,
and it will begin playing.

View File

@@ -1,29 +1,40 @@
Most of the consoles higan emulates
were designed for the low resolution of NTSC televisions,
and their video output is often chunky and blocky
were designed for low resolution NTSC televisions,
and their video output is chunky and blocky
by today's standards.
Shaders customise how a console's video output
Video shaders customise how a console's video output
is drawn to the computer screen,
and can apply just about any effect you can imagine.
and can clean up and smooth out the original video,
reproduce the scanlines and blurring of the original display,
or any other visual effect.
Most [drivers](drivers.md)
only support these shaders
(some only support one or the other):
The available video shaders are listed in
the "Video Shaders" sub-menu of
[the Settings menu](../interface/higan.md#the-settings-menu).
Which shaders are available depends on
the [video driver](drivers.md#video) higan is configured to use.
Most drivers only support these shaders:
- **None** draws each computer pixel
in the same colour as the nearest console pixel.
This is sometimes called "nearest neighbour scaling",
and produces crisp, blocky output.
- **Blur** draws each computer pixel
as the weighted average colour
of the four nearest console pixels.
This is sometimes called "bilinear scaling",
and hides some of the blockiness
at the expense of blurring edges.
- **None**
draws each computer pixel according to
the colour of the single nearest console pixel,
sometimes called "nearest neighbour" scaling.
This produces unnaturally crisp and blocky images.
- If you use [aspect correction or non-integral scaling][ac],
neighbouring console pixels may be drawn
with a different number of computer pixels due to rounding errors,
causing a distracting rippling effect.
- **Blur**
draws each computer pixel according to
the weighted average colour
of the four nearest console pixels,
sometimes called "bilinear" scaling.
This produces unnaturally blurry images.
However,
the OpenGL driver supports custom shaders,
in addition to the above.
[ac]: ../interface/higan-settings.md#video
In addition to those,
the OpenGL driver also supports custom shaders.
**Note:**
For technical reasons,
@@ -31,10 +42,13 @@ higan's emulation of certain consoles
can produce surprising behaviour
in certain shaders,
particularly shaders that compare each console pixel
with its neigbours.
See [Console-specific Notes](../notes.md) for details.
with its neighbours.
See [Video Shaders and TV-based consoles][vstv] for details.
# Where to get shaders
[vstv]: #video-shaders-and-tv-based-consoles
Where to get custom shaders
---------------------------
- higan includes some simple example shaders.
If your copy of higan did not come with shaders,
@@ -44,7 +58,8 @@ See [Console-specific Notes](../notes.md) for details.
contains many high-quality shaders for use with higan.
- You can write your own.
# How to install shaders
How to install custom shaders
-----------------------------
Make sure the shader you want to install
is in the correct format:
@@ -53,59 +68,55 @@ it should contain a file named `manifest.bml`,
and probably some `*.fs` or `*.vs` files.
Place the shader folder inside
the `Video Shaders` directory
the `Video Shaders` folder
of your higan installation.
If you don't have a `Video Shaders` directory,
create it beside the `*.sys` directories
If you don't have a `Video Shaders` folder,
create it beside the `*.sys` folders
like `Game Boy Advance.sys` and `Super Famicom.sys`.
- On Windows,
this is probably the directory containing `higan.exe`
this is probably the folder containing `higan.exe`
- On Linux,
this is probably `~/.local/share/higan`
Launch higan,
open the Settings menu,
and choose "Advanced ..."
to open [the Advanced tab](../interface/higan-config.md#advanced)
of the Settings dialog.
to open [the Advanced tab](../interface/higan-settings.md#advanced)
of the Settings window.
Under "Driver Selection",
make sure "Video" is set to "OpenGL".
If you changed the video driver,
If it wasn't already set that way,
you'll need to restart higan
for the change to take effect.
Open the Settings menu again,
choose the "Video Shader" submenu,
choose the "Video Shader" sub-menu,
and now the shaders you installed
should be listed at the bottom of the menu.
Load a game
(so you can see the results)
and switch between shaders
to see what they do
(so you can see the results),
switch between shaders
to see what they do,
and pick your favourite!
# Notable examples
Notable examples
----------------
The quark-shaders repository
The quark-shaders repository mentioned above
contains lots of carefully-crafted shaders,
but some are particularly noteworthy:
- **AANN** implements "anti-aliased nearest neighbour" scaling.
If the console's video is not displayed
at an exact multple of the console's native resolution,
rounding errors cause normal nearest-neighbour scaling
to draw some rows and columns wider than others,
which many people find ugly and distracting.
This is very common when
higan's aspect-ratio correction mode
is enabled.
AANN uses very slight anti-aliasing
to hide the rounding errors,
leaving the overall image as crisp as nearest-neighbour.
- **Gameboy** emulates the squarish aspect-ratio
greenish-colours
This uses anti-aliasing to hide
the rounding errors often introduced by
aspect ratio correction
and non-integral scaling,
producing an image nearly as crisp as the "None" shader,
but without the distracting ripple effect.
- **Gameboy** emulates the squarish aspect-ratio,
greenish-colours,
and limited palette
of the original Game Boy.
At larger scales,
@@ -120,7 +131,85 @@ but some are particularly noteworthy:
and shimmer
that most game players would have seen
on real televisions.
This is important because
some games depended on NTSC artifacts
Some games depend on NTSC artefacts
to display colours outside the console's official palette
or to create effects like transparency.
Video Shaders and TV-based consoles
-----------------------------------
Simple shaders
(like "None"
and the third-party "AANN" shader)
just blindly scale up the images they're given,
but sophisticated shaders
(such as the third-party "xBR" shader)
try to produce higher-quality output
by recognising particular patterns,
like taking three diagonal pixels
and turning that into a smooth diagonal line.
These shaders assume that
each pixel drawn by the game's artists
becomes a single pixel in the video output they analyze.
The hand-held consoles that higan emulates
(and also the Famicom)
can only output video at one specific resolution,
so this "one pixel equals one pixel" rule holds true,
and pattern-based shaders like "xBR" work just fine.
Unfortunately,
this is not true for most of the TV-based consoles
that higan supports.
The Super Famicom's "normal" video mode
draws 256 pixels across the width of the screen,
but the "high resolution" mode draws 512.
Since Super Famicom games can enable hi-res mode at any time
(even halfway through a frame),
higan always renders Super Famicom video output 512 pixels wide,
just in case.
This means that in "normal" mode,
each pixel drawn by the game's artists
becomes two pixels in the video output,
breaking the assumption
that pattern-based shaders are based on.
The Super Famicom has a similar issue in the vertical direction:
normally,
an NTSC-based Super Famicom draws about 240 rows of output every frame,
sometimes referred to as "240p" video.
When a game turns on "interlaced" mode,
it draws the 240 odd-numbered lines of one frame,
then the 240 even-numbered lines of the next,
and so forth.
This is sometimes referred to as "480i" video.
Although interlaced mode cannot be enabled mid-frame
like high-resolution mode,
resolution switching is still complex,
so higan always draws all 480 lines of video output.
This means for a normal, non-interlaced game,
each pixel drawn by the game's artists
becomes four pixels in the video output
(two horizontally and two vertically)
making pattern-based shaders even less useful.
It also breaks most scanline-emulation shaders,
since they typically draw a scanline
for each row of pixels in the video output.
The Mega Drive has similar problems
to the Super Famicom.
It has the same behaviour with interlacing,
but its high-resolution mode switches
from 256 pixels across to 320 pixels across.
Therefore in normal mode,
each pixel drawn by the game's artists
becomes five pixels in the video output,
while in high-resolution mode,
each pixel drawn by the game's artists
becomes four pixels in the video output
(or 10 and 8 pixels in non-interlaced mode).
The PC Engine does not support an interlaced mode,
but its horizontal resolution is much more flexible
than the Super Famicom or Mega Drive,
and so it has the same problems with shaders as those consoles.

View File

@@ -1,34 +1,38 @@
higan, the multi-system emulator
================================
higan emulates a number of classic videogame consoles of the 1980s and 1990s,
higan emulates a number of classic video-game consoles of the 1980s and 1990s,
allowing you to play classic games on a modern general-purpose computer.
To get started with higan right away,
see the [Quick Start](qs.md) section of the documentation.
About higan
-----------
As of v102,
As of v104,
higan has top-tier support for the following consoles:
- Nintendo Super Famicom/Super Nintendo Entertainment System,
including addon hardware:
including add-on hardware:
- Super Game Boy
- Sufami Turbo
- Nintendo Game Boy Advance
It also includes some level of support for these consoles:
- Satellaview addon for the Super Famicom
- Satellaview add-on for the Super Famicom
- Nintendo Famicom/Nintendo Entertainment System
- Nintendo Game Boy
- Nintendo Game Boy Color
- Sega Master System
- Sega Game Gear
- Sega Megadrive/Genesis
- Sega Mega Drive/Genesis
- NEC PC Engine/TurboGrafx 16 (but not the CD-ROM² System/TurboGrafx-CD)
- NEC SuperGrafx
- Bandai Wonderswan
- Bandai Wonderswan Color
- Bandai WonderSwan
- Bandai WonderSwan Color
**Note:** Some consoles were released under different names
in different geographic regions.
@@ -37,7 +41,7 @@ every time such a console is mentioned,
higan uses the name from the console's region of origin.
In practice,
that means Japanese names:
"Famicom" and "Super Famicom" instead of NES and SNES,
"Famicom" and "Super Famicom" instead of "NES" and "SNES",
"Mega Drive" instead of "Genesis",
"PC Engine" instead of "TurboGrafx-16".
@@ -47,22 +51,19 @@ Microsoft Windows 7 and above.
It also includes some level of support
for GNU/Linux and macOS.
If you want to install higan and try it out,
see the [Quick Start](#quick-start) section below.
higan is officially spelled with a lowercase "h", not a capital.
About this document
-------------------
This is the unofficial higan README,
This is the semi-official higan manual,
a community-maintained introduction and reference.
It may be out of date
by the time you read this,
and it may contain errors or omissions.
If you find something that's wrong,
or you have a suggestion,
see "Unofficial higan resources" below.
post a message on the official higan forum.
Official higan resources
------------------------
@@ -81,14 +82,14 @@ Unofficial higan resources
collects shaders that higan can use
to add special effects like TV scanlines to its video output,
or smarter algorithms for scaling up to modern PC resolutions.
See [Installing custom shaders][shaders] below for details.
See [Using video shaders][shaders] below for details.
- [Mercurial Magic](https://github.com/hex-usr/Mercurial-Magic/)
is a tool for converting MSU-1 games and mods into a format
higan can use.
See [Importing MSU-1 games][msu1] below for details.
See [Importing MSU-1 games][msu1] for details.
[shaders]: #installing-custom-shaders
[msu1]: #importing-msu-1-games
[shaders]: guides/shaders.md
[msu1]: guides/import.md#msu-1-games
There are also other projects
based on current or older versions of higan,
@@ -102,8 +103,15 @@ that you might want to check out.
- [BizHawk](http://tasvideos.org/BizHawk.html)
is another multi-system emulator,
specialising in the creation of
tool-assisted speedruns.
tool-assisted speed-runs.
Its Super Famicom emulation is based on bsnes v087.
- [bsnes-plus](https://github.com/devinacker/bsnes-plus)
is a fork of bsnes v073
that adds improved support for debugging Super Famicom software.
- [bsnes-mercury](https://github.com/libretro/bsnes-mercury/)
is a fork of bsnes v094
adapted to work as a
[libretro](https://www.libretro.com/) emulation core.
- [nSide](https://github.com/hex-usr/nSide)
is a fork of higan that greatly enhances
its NES emulation support,
@@ -111,7 +119,4 @@ that you might want to check out.
It also restores the "balanced" Super Famicom emulation core
that was removed from higan in v099,
which is less CPU intensive
than the current accuracy-focussed core.
- [bsnes-plus](https://github.com/devinacker/bsnes-plus)
is a fork of bsnes v073
that adds improved support for debugging Super Famicom software.
than the current accuracy-focused core.

View File

@@ -12,19 +12,20 @@ for [common functions games require][bios],
often called a "BIOS"
by analogy with the Basic Input/Output System
used in IBM PC compatibles.
Although the GBA BIOS is required
in order to emulate GBA games,
it cannot be distributed with higan
for the same legal reasons that commercial games
cannot be distributed with higan,
so you'll need to obtain a copy of the BIOS for yourself.
For the same legal reasons that commercial games
cannot be distributed with emulators,
the GBA BIOS cannot be distributed with higan,
but is required for GBA software to run.
If you have a real GBA and a flashcart,
If you have a real GBA and a flash-cart,
the Internet contains many tools
that will extract the BIOS image so it can be copied
to your desktop computer.
The correct GBA BIOS file is exactly 16384 bytes long,
and has the SHA-256 hash
fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570.
and has the SHA256 hash
`fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570`.
Once you have the correct BIOS file:
@@ -34,7 +35,7 @@ Once you have the correct BIOS file:
so you don't wind up with a file called
`bios.rom.dat`
or whatever the file's original extension was.
2. Copy the file into higan's `Game Boy Advance.sys` directory,
2. Copy the file into higan's `Game Boy Advance.sys` folder,
alongside the `manifest.bml` file that is already there.
- In Windows,
find `Game Boy Advance.sys` in the same folder
@@ -46,7 +47,7 @@ Once you have the correct BIOS file:
**Note:**
If you upgrade this version of higan to a newer version,
make sure the `bios.rom` file
winds up in the `Game Boy Advance.sys` directory
winds up in the `Game Boy Advance.sys` folder
of the new version.
[bios]: http://problemkaputt.de/gbatek.htm#biosfunctions

View File

@@ -3,7 +3,8 @@ Compiling from source on Linux
You will need a copy of the higan source-code.
If you download an official release from the higan homepage,
you will need [7-zip][7z] or a compatible tool to extract it.
you will need [7-zip](http://www.7-zip.org)
or a compatible tool to extract it.
Alternatively,
you may obtain higan source code from
[the unofficial git repo](https://gitlab.com/higan/higan/)
@@ -29,7 +30,8 @@ for the following libraries:
- OpenAL
- udev
On a Debian-derived Linux distribution,
On a Debian-derived Linux distribution
(including Ubuntu and Mint),
you can install everything you need with a command like:
sudo apt-get install build-essential libgtk2.0-dev libpulse-dev \
@@ -51,10 +53,10 @@ being installed system-wide.
3. Type `cd ~/higan-src`
(or wherever you put the higan source)
and press Enter
4. Type `make -C icarus compiler=g++` and press Enter
to build the icarus import tool
5. Type `make -C higan compiler=g++` and press Enter
4. Type `make -C higan` and press Enter
to build the main higan executable
5. Type `make -C icarus` and press Enter
to build the icarus import tool
Installing a compiled build on Linux
------------------------------------
@@ -66,10 +68,14 @@ as described in the previous section:
2. Type `cd ~/higan-src`
(or wherever you put the higan source)
and press Enter
3. Type `make -C icarus install` and press Enter
to install icarus and its game database
4. Type `make -C higan install` and press Enter
3. Type `make -C higan install` and press Enter
to install higan and its supporting files
4. Type `make -C icarus install` and press Enter
to install icarus and its game database
5. If the higan source includes a `shaders` subdirectory,
type `make -C shaders install`
to install the example
[video shaders](../guides/shaders.md).
This installs higan and its associated data files
into the `~/.local` directory hierarchy.
@@ -107,12 +113,6 @@ You will need to log out and log back in
for changes to `~/.profile` or `~/.bash_profile`
to take effect.
Before you can actually play games,
you'll need to [import them](#the-game-library)
and [configure higan](#configuring-higan).
If you want to play Game Boy Advance games,
you will need [a GBA BIOS](#installing-the-gba-bios).
Uninstalling a compiled build on Linux
--------------------------------------
@@ -123,11 +123,17 @@ as installed by the above instructions:
2. Type `cd ~/higan-src`
(or wherever you put the higan source)
and press Enter
3. Type `make -C icarus uninstall` and press Enter
4. Type `make -C higan uninstall` and press Enter
3. Type `make -C higan uninstall` and press Enter
4. Type `make -C icarus uninstall` and press Enter
To remove higan's configuration,
delete the directory `~/.config/higan` as well.
you should also delete the following directories
if they exist:
- `~/.config/higan/`
- `~/.config/hiro/`
- `~/.local/share/higan/`
- `~/.local/share/hiro/`
To remove the games imported into higan's library
(including in-game saves and save-states),

View File

@@ -1,31 +1,23 @@
Installing an official release on Windows
-----------------------------------------
Official higan releases are distributed in [7-zip][7z] archives.
You will need to install 7-zip,
or another compatible archiving tool,
Official higan releases are distributed in
[7-zip](http://www.7-zip.org/)
archives.
You will need to install 7-zip
(or another compatible archiving tool)
to install higan.
[7z]: http://www.7-zip.org/
Once you have a suitable archiving tool,
extract the contents of the higan archive into a new folder.
When you're done,
the new folder should contain `higan.exe` and `icarus.exe`
along with other assorted files and directories
along with other assorted files and folders
that describe the systems higan emulates.
You may put that folder wherever you like.
You may put that new folder wherever you like.
To run higan, open the `higan.exe` file.
Before you can actually play games,
you'll need to [import them](#the-game-library)
and [configure higan](#configuring-higan).
If you want to play Game Boy Advance games,
you will need [a GBA BIOS](#installing-the-gba-bios).
Uninstalling an official release on Windows
-------------------------------------------
@@ -37,23 +29,20 @@ To remove higan's configuration:
1. Press Win+R to open the Run dialog
2. Type `%LOCALAPPDATA%` and press Enter
to open the folder where higan's configuration data lives
3. Delete the subdirectories named `icarus` and `higan`
3. Delete the sub-folders named `icarus` and `higan`
if they exist.
You might also want to remove the games imported into higan's library
(including in-game saves and save-states):
1. Press Win+R to open the Run dialog
2. Type `%USERPROFILE%` and press Enter
to open the folder where higan keeps its game library
3. Delete the folder named `Emulation` if it exists
You might also want to remove
[higan's game library](../concepts/game-library.md#where-is-the-game-library)
(including in-game saves and save-states).
Compiling from source on Windows
--------------------------------
You will need a copy of the higan source-code.
If you download an official release from the higan homepage,
you will need [7-zip][7z] or a compatible tool to extract it.
you will need [7-zip](http://www.7-zip.org/)
or a compatible tool to extract it.
Alternatively,
you may obtain higan source code from
[the unofficial git repo](https://gitlab.com/higan/higan/)
@@ -83,25 +72,28 @@ See the higan forum
[for](https://board.byuu.org/viewtopic.php?p=41977#p41977)
[details](https://board.byuu.org/viewtopic.php?p=42253#p42253).
Once you've installed mingw-w64,
Once you've installed the compiler,
open a command-prompt window,
type `g++ --version`
then press Enter
to check it's installed correctly.
You should see a message like
g++ 1.2.3 20010101
Copyright (C) 2001 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```text
g++ 1.2.3 20010101
Copyright (C) 2001 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```
...except it should mention the version of mingw that you installed
...except it should mention the compiler version that you installed
and the corresponding dates.
If you see an error message like "command not found"
or "bad command or filename",
you may need to add mingw's "bin" folder
If you see an error message like
"'g++' is not recognized as an internal or external command,
operable program or batch file",
you may need to add the compiler's "bin" folder
to your computer's `%PATH%`.
See the mingw documentation for help with that.
See the compiler's documentation for help with that.
Once mingw is installed and available from the command prompt:
@@ -111,9 +103,9 @@ Once mingw is installed and available from the command prompt:
3. Type `cd C:\higan-src`
(or wherever you put the higan source)
and press Enter
4. Type `mingw32-make -C icarus compiler=g++` and press Enter
4. Type `mingw32-make -C icarus` and press Enter
to build the icarus import tool
5. Type `mingw32-make -C higan compiler=g++` and press Enter
5. Type `mingw32-make -C higan` and press Enter
to build the main higan executable
[tdm]: http://tdm-gcc.tdragon.net/download
@@ -130,9 +122,15 @@ Installing a compiled build on Windows
into the new folder
4. Copy `C:\higan-src\higan\out\higan.exe`
into the new folder
5. Copy all the `*.sys` directories
5. Copy all the `*.sys` folders
in `C:\higan-src\higan\systems`
into the new folder
6. If the higan source includes a `shaders` folder,
make another new folder named `Video Shaders`
inside the new folder,
and copy all the `*.shader` folders
from `C:\higan-src\shaders\`
into the `Video Shaders` folder.
The new folder should now contain
`icarus.exe`,
@@ -147,12 +145,6 @@ above.
[instwin]: #installing-an-official-release-on-windows
Before you can actually play games,
you'll need to [import them](#the-game-library)
and [configure higan](#configuring-higan).
If you want to play Game Boy Advance games,
you will need [a GBA BIOS](#installing-the-gba-bios).
Uninstalling a compiled build on Windows
----------------------------------------

View File

@@ -1,11 +1,11 @@
The Filesystem Browser
----------------------
Sometimes higan will need
to ask you to choose a file or folder.
Sometimes higan will need you
to choose a file or folder.
For this, it uses a special Filesystem Browser dialog.
Although many operating systems provide a native filesystem browser,
they do not all allow the same customizations.
they do not all allow the same customisations.
Therefore,
higan provides its own filesystem browser
that works the same way on every platform.
@@ -19,25 +19,25 @@ If you want to browse a specific path,
you may edit the contents of this box
and press Enter to switch to the new location.
The button with two blue arrows at the top-right is "Refresh".
Pressing this button will check for
added (or removed) items in the current folder,
and add (or remove) them to (or from) the list.
The ![two-blue-arrows](refresh.png) button is "Refresh".
Pressing this button will check
if anything has been added to or removed from the current folder
and update the list to match.
The button with the house at the top-right is "Home".
The ![house](home.png) button is "Home".
Pressing this button will switch to your home folder.
The button with the green up-arrow at the top right is "Parent".
The ![up-arrow](up.png) button is "Parent".
Pressing this button will
switch to the parent of the current folder.
Most of the filesystem browser lists the contents
of the current directory.
of the current folder.
Double-clicking a folder,
or selecting it and pressing Enter,
will switch to showing the contents of that directory.
will switch to showing the contents of that folder.
If the list has keyboard focus,
typing any text will jump to the first inem in the list
typing any text will jump to the first item in the list
whose name begins with the text you typed.
If a drop-down list appears in the bottom-left,
@@ -50,12 +50,12 @@ by double-clicking it,
by selecting it and pressing Enter,
or by selecting it and clicking the "Select" button in the bottom-right.
If this filesystem browser is asking for a directory,
If this filesystem browser is asking for a folder,
you can choose one
by selecting it and clicking the "Select" button in the bottom-right.
Double-clicking
or selecting and pressing Enter don't work,
they just switch to viewing that directory.
they just switch to viewing the contents of that folder.
The "Cancel" button in the bottom-right
closes the filesystem browser without selecting anything.

View File

@@ -1,40 +1,95 @@
# Synopsis
> higan [*\-\-fullscreen*] [*PATH*]
> higan [*\-\-fullscreen*] [*GAME* [*SUBGAME1* [*SUBGAME2*]]]
# Description
TODO: Put `NTSC-J|`, `NTSC-U|` or `PAL|`
at the beginning of the path
to force a region
for consoles where it can't be detected.
When launched with `--fullscreen`,
higan will automatically enter full-screen mode
when it starts.
This is not much use unless you also specify `PATH`,
higan will automatically enter fullscreen mode
when it starts,
otherwise it starts in windowed mode.
This is not much use unless you also specify `GAME`,
because you won't be able to load a game
until you exit full-screen mode
until you exit fullscreen mode
by pressing the "Toggle Fullscreen"
[hotkey](higan-config.md#hotkeys).
[hotkey](higan-settings.md#hotkeys).
When `PATH` is the path to an existing
When `GAME` is not given,
higan starts with no game loaded.
When `GAME` is the path to an existing
[game folder](../concepts/game-folders.md)
for any supported console,
that game will be loaded when higan starts.
that game will automatically be loaded
after higan starts.
When `PATH` is the path to a ROM file
When `GAME` is the path to a ROM file
for any supported console,
it will be imported into a game folder in
[the Game Library](../concepts/game-library.md),
and then loaded from there when higan starts.
and loaded from there after higan starts.
When `GAME` is of the form `REGION|PATH`
(that is,
a region code,
a vertical bar (`|`),
and a path to a game folder or ROM file)
higan will load the game at `PATH`
into the `REGION` variant of the appropriate console,
rather than detecting which variant the game expects.
This is the command-line equivalent
of choosing a region from
the drop-down in the bottom-right of the filesystem browser window
when you [load a game from the game library](../guides/import.md#regular-games).
The list of region codes differs from console to console,
so load a game from the library
and check the list
before loading it from the command-line.
When `GAME` refers to a game with
a [Satellaview](../guides/import.md#satellaview-games) memory pak slot,
`SUBGAME1` should be
the path to a game folder or ROM file
representing the memory pak to insert into the slot.
If `SUBGAME1` is not supplied,
higan will prompt for one.
`SUBGAME2` is ignored.
When `GAME` refers to
the [Super Game Boy](../guides/import.md#super-game-boy-games),
`SUBGAME1` should be
the path to a game folder or ROM file
representing a Game Boy game to insert into the slot.
If `SUBGAME1` is not supplied,
higan will prompt for one.
`SUBGAME2` is ignored.
When `GAME` refers to
the [Sufami Turbo](../guides/import.md#sufami-turbo-games),
then `SUBGAME1` should be
the path to a game folder or ROM file
representing the mini-cartridge to be inserted into
slot A of the Sufami Turbo base cartridge,
and `SUBGAME2` is the same thing for slot B.
higan will prompt for
any mini-cartridges not supplied on the command-line.
When `GAME` refers to any other game,
both `SUBGAME1` and `SUBGAME2` are ignored.
# Examples
Play a previously-imported copy of Super Mario World
in full-screen (assuming Linux defaults):
in fullscreen (assuming Linux defaults):
```sh
higan --fullscreen ~/Emulation/"Super Famicom"/"Super Mario World.sfc"
higan --fullscreen "$HOME/Emulation/Super Famicom/Super Mario World.sfc"
```
Play a previously-imported copy of Sonic the Hedgehog 3,
forcing higan to emulate a Japanese Mega Drive:
```sh
higan "NTSC-J|$HOME/Emulation/Mega Drive/Sonic the Hedgehog 3.md"
```

View File

@@ -1,298 +0,0 @@
TODO: Rename this file to "higan-settings.md"
The Settings window
appears when you choose
one of the items at the bottom of
[the Settings menu](higan.md#the-settings-menu).
It contains less-frequently-modified configuration options.
Most of these can be safely ignored,
or set once and never changed again.
This window has a tab for each main category of options:
Video
=====
This tab contains options that affect
how higan displays
the emulated console's video output.
- **Saturation**: adjusts the vibrancy of colours displayed,
where 0% makes things pure grey,
100% is normal,
and 200% is garishly brightly coloured.
- **Gamma**: adjusts how bright mid-range colours are
compared to the brightest colours,
where 100% is normal,
and 200% makes mid-range colours much darker.
- **Luminance**: adjusts the overall brightness,
where 100% is normal,
and 0% is totally black.
- **Overscan Mask**: hides parts of
the video output that would have been hidden
by the bezel around the edge of
a standard-definition television screen.
Some games (particularly on the Famicom)
displayed random glitchy output in this area,
which can be distracting.
The units are "pixels in the emulated console's standard video-mode".
For example, setting "Horizontal" to 8
will clip 8/256ths from the left and right sides
of the Super Famicom's video output,
whether the Super Famicom is in
lo-res (256px) or hi-res (512px)
mode.
- **Aspect Correction**:
(in both Windowed Mode and Fullscreen Mode)
stretches the image to match the aspect ratio
produced by the original console hardware,
but can cause a "ripple" effect,
due to rounding errors.
- **Resize Window to Viewport**:
(under "Windowed mode")
causes higan to resize its window
to fit snugly around the emulated console's video
whenever it changes size:
because a game was loaded for a different console
with a different display size or aspect ratio,
because the "Overscan Mask" controls were adjusted,
because the game switched to a different video mode,
because the user pressed the "Rotate Display" hotkey,
etc.
When this option is disabled,
the higan window stays at a fixed size,
large enough to contain the video for any supported console,
padded with black borders for all smaller video modes.
- **Resize Viewport to Window**:
(under "Fullscreen mode")
causes higan to stretch the emulated console's video output
to touch the edges of the screen.
Since most screens are not an exact multiple
of the size of all emulated consoles,
this may cause a "ripple" effect,
due to rounding errors.
When this option is disabled,
higan stretches the emulated console's video output
to the largest exact multiple
of the emulated console's video output
that is smaller than or equal to the screen size.
- TODO: Update this to match 103r11, or whatever the latest version is.
Audio
=====
This tab contains options that affect
how higan reproduces
the emulated console's audio output.
- **Device**: allows you to choose
which audio device higan sends
the emulated game's audio to.
- **Frequency**: controls the sample-rate that higan will use
when generating audio.
If your PC's audio hardware has a "native" sample-rate
and you know what it is,
pick that.
Otherwise,
44.1kHz or 48kHz should be fine.
- **Latency**: controls how much audio output higan calculates in advance.
Higher values reduce the chance of
"popping" or "glitching" noises,
but increase the delay between an action occurring on-screen
and the corresponding sound-effect being played.
- **Exclusive Mode**: appears
if the current audio driver
allows higan to take exclusive control of your PC's audio output,
so no other applications can play sounds.
This can improve audio quality,
and lower the effective audio latency.
- **Volume**: controls the overall loudness of
the emulated console's audio,
where 100% is normal volume,
and 0% is complete silence.
- **Balance**: controls the relative loudness of
the left and right speakers,
where 0% means only the left speaker produces sound,
50% means both speakers produce sound equally,
and 100% means only the right speaker produces sound.
- **Reverb**: adds a slight reverberation effect
to the emulated console's audio output,
as though the console were in a tunnel or small room.
Input
=====
This tab controls which PC inputs
are used for which emulated controllers.
The exact PC inputs that can be mapped
depend on [the input driver](#drivers).
- **Pause Emulation**: automatically pauses emulation
when the main higan window
is not the current foreground window.
- **Allow Input**: can be ticked
when "Pause Emulation" is *not* ticked,
and allows configured inputs to keep affecting higan
even when higan is running in the background.
This is particularly relevant if
you configure your PC keyboard to control higan:
if you tick this box,
and switch to a different application
leaving higan running in the background,
typing in that other application may affect
the emulated game running in higan
even though you can't see it!
- The console selector chooses which console's inputs
to display in the mapping list below.
- The port selector chooses which port of the selected console
to display in the mapping list below.
- The controller selector chooses which controller
associated with the given console and port
to display in the mapping list below.
- The mapping list includes
every button and axis on the selected controller,
and the PC inputs that are mapped to it
when it is connected to the selected port of the selected console.
- **Erase**: removes the mapping
for the selected button or axis.
- **Reset**: removes all the mappings currently in the list.
- TODO: Mention that controllers must be connected
in the console menu
before they can be used.
To map
a keyboard or gamepad button on your PC to
a controller button,
double-click the controller button in the list,
or select it and press Enter.
The window will grey out,
and a message will appear in the bottom left:
"Press a key or button to map [the button]".
Press the key or button you want to map,
and it should appear in the list
next to the controller button it is mapped to.
To map
a mouse button on your PC to
a controller button,
select the controller button in the list,
then click one of the "Mouse Left",
"Mouse Middle",
or "Mouse Right" buttons in the bottom-left of the window.
To map
a joystick axis on your PC to
a controller axis,
double-click the axis in the list,
or select it and press Enter.
The window will grey out,
and a message will appear in the bottom left:
"Press a key or button to map [the axis]".
Press the joystick in the direction you want to map,
and it should appear in the list
next to the controller button it is mapped to.
To map
a mouse axis on your PC to
a controller axis,
select the axis in the list,
then click one of the
"Mouse X-axis",
or "Mouse Y-axis"
buttons in the bottom-left of the window.
If you start mapping a button or axis,
but decide you don't want to,
you can press Escape
to exit the "Press a key or button to map..." mode
without actually mapping anything.
The "Rumble" setting
for the Game Boy Advance is treated like a button,
and can be mapped to a PC gamepad.
When the emulated Game Boy Advance
tries to use the rumble feature
of the Game Boy Player,
higan will turn on the force-feedback
of whatever gamepad the mapped button is part of.
Hotkeys
=======
This tab is like "Inputs" above,
except it contains controls for higan itself,
instead of for the emulated console.
- **Toggle Fullscreen**: puts higan into fullscreen mode,
where the menu and status bar are hidden,
and the emulated console's video output
is enlarged to cover the entire screen.
Toggling fullscreen also automatically captures the mouse.
- **Toggle Mouse Capture**: hides the usual mouse-cursor,
and captures the mouse so it cannot leave the higan window.
This is useful when the mouse is being used to emulate
a light-gun controller like the Super Scope.
- **Save Quick State**: saves the current state of the emulated console
to the currently-selected Quick State slot.
- **Load Quick State**: restores the emulated console
to the state saved in the currently-selected Quick State slot.
- **Decrement Quick State**: selects the previous Quick State slot.
The status bar will briefly display the new current slot number.
- **Increment Quick State**: selects the next Quick State slot.
The status bar will briefly display the new current slot number.
- **Pause Emulation**: pauses the emulated console
until the Pause Emulation hotkey is pressed a second time.
- **Fast Forward**: disables audio and video synchronisation
for as long as it's held down,
so emulation proceeds as quickly as possible.
If your PC struggles to hit "real time"
(60fps for most emulated consoles),
this likely won't have any effect.
- **Power Cycle**: turns the emulated console off and back on,
(a "hard reset"),
just like the "Power Cycle" menu item
in [the console menu](#the-console-menu).
- **Rotate Display**: will toggle the display
of the Game Boy Advance
and WonderSwan (Color)
between the usual landscape orientation
and a portrait orientation (90° counter-clockwise).
These consoles have games
that expect the player to hold the console
in a different way.
Advanced
========
This tab contains all the settings
that didn't fit into one of the other categories.
- **Video**: controls how higan will draw
the emulated console's video output
to the PC screen.
"None" means no video will be drawn.
See [Drivers](#drivers) for details.
- **Audio**: controls how higan will present
the emulated console's audio output.
"None" means no audio will be played.
See [Drivers](#drivers) for details.
- **Input**: controls how higan checks for input
from the PC's input devices.
"None" means the emulated console cannot be controlled.
See [Drivers](#drivers) for details.
- **Location**: selects where the [Game Library](#the-game-library)
looks for games to load.
See [Moving the Game Library](#moving-the-game-library)
for more information.
- **Ignore Manifests**: makes higan ignore the manifest file
in the a loaded game's [game folder](#why-game-folders)
in favour of asking icarus
to guess a manifest on the fly.
This means that incompatible or incorrect manifests
generated by old versions of icarus
won't cause problems,
but means you can't fix incorrect manifests
generated by the current version of icarus.
See also the "Create Manifests" option in
[the icarus Settings dialog](#the-icarus-settings-dialog).

View File

@@ -0,0 +1,373 @@
The Settings window
appears when you choose
one of the items at the bottom of
[the Settings menu](higan.md#the-settings-menu),
and contains less-frequently-modified settings.
Most of these can be safely ignored,
or set once and never changed again.
This window has a tab for each main category of options:
Video
=====
This tab contains options that affect
how higan displays
the emulated console's video output.
**Color Adjustment**
settings adjust the colour and brightness
of the emulated console's video output:
- **Saturation** adjusts the vibrancy of colours displayed,
where 0% makes things pure grey,
100% is normal,
and 200% is garishly brightly coloured.
- **Gamma** adjusts how bright mid-range colours are
compared to the brightest colours,
where 100% is normal,
and 200% makes mid-range colours much darker.
This is in addition to
any adjustment applied by
the "Colors" option
in the "Video Emulation" sub-menu
of the [Settings menu](higan.md#the-settings-menu).
- **Luminance** adjusts the overall brightness,
where 100% is normal,
and 0% is totally black.
**Overscan Mask**
removes parts of
the video output that would have been hidden
by the bezel around the edge of
a standard-definition television screen.
Some games (particularly on the Famicom)
displayed random glitchy output in this area,
which can be distracting.
- **Horizontal**
removes pixels from the left and right of the video output.
- **Vertical**
removes pixels from the top and bottom of the video output.
The units are "pixels in the emulated console's standard video-mode".
For example, setting "Horizontal" to 8
will clip 8/256ths from the left and right sides
of the Super Famicom's video output,
whether the Super Famicom is in
lo-res (256px) or hi-res (512px)
mode.
**Windowed Mode**
settings apply when higan is running
in a normal window.
- **Aspect Correction**
stretches the image to match the aspect ratio
produced by the original console hardware,
but can cause a "ripple" effect
during horizontal scrolling
due to rounding errors.
[Video shaders](../guides/shaders.md)
can reduce this effect.
- **Integral Scaling**
makes higan draw the emulated video output
at a whole-number multiple of the original size,
rather than completely filling the available space.
This means that every game pixel
uses the same number of computer pixels,
and avoids graphics looking chunky and uneven.
Note that Aspect Correction
is applied after integral scaling,
so some unevenness may be visible
even with this option enabled.
- **Adaptive Sizing**
automatically resizes the higan window
to fit snugly around the emulated video output
whenever it changes size
(because the user loaded a game for a different console,
chose a different option from
the [Video Scale sub-menu](higan.md#the-settings-menu),
toggled Aspect Correction, etc.)
When disabled,
higan generally respects manual resizing.
**Fullscreen Mode**
settings apply
when higan is running fullscreen,
because it was started with the `--fullscreen`
[command-line option](higan-cli.md)
or because the user pressed
the Toggle Fullscreen [hotkey](higan-settings.md#hotkeys).
- **Aspect Correction**
behaves the same way as in Windowed mode above.
- **Integral Scaling**
behaves the same way as in Windowed mode above.
- **Exclusive Mode**
requests exclusive access
to the computer's video output
when higan enters fullscreen mode.
This prevents other applications
or the operating system itself
from drawing anything,
and may also temporarily disable any kind of compositing,
reducing video latency.
As of v104,
only the Direct3D video driver is capable of exclusive mode;
with other drivers this option does nothing.
Audio
=====
This tab contains options that affect
how higan reproduces
the emulated console's audio output.
**Driver**
settings affect
the current [Audio driver](../guides/drivers.md).
- **Device** allows you to choose
which audio device higan sends
the emulated game's audio to,
if you have more than one.
- **Frequency** controls the sample-rate that higan will use
when generating audio.
If your PC's audio hardware has a "native" sample-rate
and you know what it is,
pick that.
Otherwise,
44.1kHz or 48kHz should be fine.
- **Latency** controls how much audio output higan calculates in advance.
Higher values reduce the chance of
"popping" or "glitching" noises,
but increase the delay between an action occurring on-screen
and the corresponding sound-effect being played.
- **Exclusive Mode** appears
if the current audio driver
allows higan to take exclusive control of your PC's audio output,
so no other applications can play sounds.
This can improve audio quality,
and lower the effective audio latency.
**Effects**
are applied to the emulated audio output
before it is sent to your computer's speakers.
- **Volume** controls the overall loudness of
the emulated console's audio,
where 100% is normal volume,
and 0% is complete silence.
- **Balance** controls the relative loudness of
the left and right speakers,
where 0% means only the left speaker produces sound,
50% means both speakers produce sound equally,
and 100% means only the right speaker produces sound.
- **Reverb** adds a slight reverberation effect
to the emulated console's audio output,
as though you were playing the game in a tunnel or small room.
Input
=====
This tab controls which PC inputs
are mapped to which emulated controllers.
The exact PC inputs that can be mapped
depend on [the input driver](../guides/drivers.md#input).
General input settings:
- **Pause Emulation** automatically pauses emulation
when the main higan window
is not the current foreground window.
- **Allow Input** can be ticked
when "Pause Emulation" is *not* ticked,
and allows configured inputs to keep affecting higan
even when higan is running in the background.
This is particularly relevant if
you configure your PC keyboard to control higan:
if you tick this box,
and switch to a different application
leaving higan running in the background,
typing in that other application may affect
the emulated game running in higan
even though you can't see it!
Choosing which of the possible controllers to configure:
- The console selector chooses which console's inputs
to display in the mapping list below.
- The port selector chooses which port of the selected console
to display in the mapping list below.
- The controller selector chooses which controller
associated with the given console and port
to display in the mapping list below.
Note that some consoles only allow particular controllers
to be used in a particular port.
For example,
the Super Scope controller for the Super Famicom
only works in Controller Port 2.
Configuring the selected controller:
- The mapping list includes
every button and axis on the selected controller,
and the PC inputs that will be mapped to it
when it is connected to the selected port of the selected console.
- **Erase** removes the mapping
for the selected button or axis.
- **Reset** removes all the mappings currently in the list.
To map
a keyboard or gamepad button on your PC to
a controller button,
double-click the controller button in the list,
or select it and press Enter.
The Settings window will grey out,
and a message will appear in the bottom left:
"Press a key or button to map [the button]".
Press the key or button you want to map,
and it should appear in the list
next to the controller button it is mapped to.
To map
a mouse button on your PC to
a controller button,
select the controller button in the list,
then click one of the "Mouse Left",
"Mouse Middle",
or "Mouse Right" buttons in the bottom-left of the Settings window.
To map
a joystick axis on your PC to
a controller axis,
double-click the axis in the list,
or select it and press Enter.
The Settings window will grey out,
and a message will appear in the bottom left:
"Press a key or button to map [the axis]".
Press the joystick in the direction you want to map,
and it should appear in the list
next to the controller axis it is mapped to.
To map
a mouse axis on your PC to
a controller axis,
select the axis in the list,
then click one of the
"Mouse X-axis",
or "Mouse Y-axis"
buttons in the bottom-left of the window.
If you start mapping a button or axis,
but decide you don't want to,
you can press Escape
to exit the "Press a key or button to map..." mode
without actually mapping anything.
**Note:**
Consoles in the Game Boy family include
a Rumble "input" which is really more of an output.
See [Rumble Compatibility for Game Boy (Color)][gbcrumble]
and [Rumble Compatibility for Game Boy Advance][gbarumble]
for details.
[gbcrumble]: ../notes.md#rumble-compatibility-for-game-boy-color
[gbarumble]: ../notes.md#rumble-compatibility-for-game-boy-advance
**Note:**
Once you've configured which computer inputs
higan should route to which controllers,
make sure the controller in question
is actually connected to the correct controller port
in [the console menu](higan.md#the-console-menu).
Hotkeys
=======
This tab is like "Inputs" above,
except it contains controls for higan itself
instead of the emulated console.
- **Toggle Fullscreen** puts higan into fullscreen mode,
where the menu and status bar are hidden,
and the emulated console's video output
is enlarged to cover the entire screen.
Toggling fullscreen also automatically captures the mouse.
- **Toggle Mouse Capture** hides the usual mouse-cursor,
and captures the mouse so it cannot leave the higan window.
This is useful when the mouse is being used to emulate
a light-gun controller like the Super Scope.
- **Save Quick State** saves the current state of the emulated console
to the currently-selected [Quick State][qstates] slot.
- **Load Quick State** restores the emulated console
to the state saved in the currently-selected [Quick State][qstates] slot.
- **Decrement Quick State** selects the previous [Quick State][qstates] slot.
The status bar will briefly display the new current slot number.
- **Increment Quick State** selects the next [Quick State][qstates] slot.
The status bar will briefly display the new current slot number.
- **Pause Emulation** pauses the emulated console
until the Pause Emulation hotkey is pressed a second time.
- **Fast Forward** disables audio and video synchronisation
for as long as it's held down,
so emulation proceeds as quickly as possible.
If your PC struggles to hit "real time"
(60fps for most emulated consoles),
this likely won't have any effect.
- **Power Cycle** turns the emulated console off and back on
(a "hard reset"),
just like the "Power Cycle" menu item
in [the console menu](higan.md#the-console-menu).
- **Rotate Display** will rotate the display
of the Game Boy Advance
and WonderSwan (Color).
See [Game Boy Advance rotation](../notes.md#game-boy-advance-rotation)
and [WonderSwan rotation](../notes.md#wonderswan-rotation)
for details.
[qstates]: ../concepts/save-states.md#quick-states
Advanced
========
This tab contains all the settings
that didn't fit into one of the other categories.
**Driver Selection**
tells higan how to
accept input,
display video,
and play sound
on this computer.
- **Video** controls how higan will draw
the emulated console's video output
to the PC screen.
"None" means no video will be drawn.
- **Audio** controls how higan will present
the emulated console's audio output.
"None" means no audio will be played.
- **Input** controls how higan checks for input
from the PC's input devices.
"None" means the emulated console cannot be controlled.
See [Choosing drivers](../guides/drivers.md)
for help choosing which drivers you should use.
**Game Library**
configures how higan interacts
with the [Game Library](../concepts/game-library.md).
- **Location** selects where higan
looks for games to load.
See [Moving the Game Library](../concepts/game-library.md#moving-the-game-library)
for more information.
- **Ignore Manifests** makes higan ignore
the [manifest](../concepts/manifests.md) file
in the loaded game's
[game folder](../concepts/game-folders.md)
in favour of asking icarus
to guess a manifest on the fly.
See [Ignoring manifests](../concepts/manifests.md#ignoring-manifests)
for details.

View File

@@ -11,7 +11,7 @@ The Cheat Editor
For some consoles,
higan supports applying temporary changes to the code of a running game.
For example,
you could disable the code that registers when the player takes damage,
you could disable the code that detects when the player takes damage,
resulting in an "invulnerability" mode.
Currently,
higan supports cheats for the following consoles:
@@ -23,6 +23,43 @@ higan supports cheats for the following consoles:
- PC Engine
- Wonder Swan
To add a new cheat,
select an unused row in the list,
then type the relevant codes in the "Code(s)" field at the bottom,
and a description in the "Description" field.
See [Cheat code formats](#cheat-code-formats)
for a description of the codes higan understands.
To enable or disable an existing cheat,
tick the checkbox in the first column of the list.
The change should take effect immediately.
To clear out an existing cheat,
select it from the list
and click the "Erase" button in the bottom right,
or just manually delete
the contents of the "Code(s)" and "Description" fields.
To clear out all existing cheats,
click the "Reset" button in the bottom right.
Changes made in the Cheat Editor are saved to disk
when the game is unloaded,
or when higan exits.
higan stores the known cheats for a particular game
in `higan/cheats.bml`
inside the game's [game folder](../concepts/game-folders.md).
If your copy of higan includes a cheat database
(a file named `cheats.bml`
in the same folder as `Super Famicom.sys`
and the other `*.sys` folders),
you can click the "Find Codes ..." button in the bottom left
to load all known cheats for the currently-running game.
Cheat code formats
------------------
A cheat code of the format `addr=data`
will cause the emulated console to obtain `data`
whenever it reads from memory address `addr`.
@@ -52,39 +89,6 @@ in Super Mario World,
you can lock the time to 999 with these codes:
`7e0f31=09+7e0f32=09+7e0f33=09`.
Changes made in the Cheat Editor are saved to disk
when the game is unloaded,
or when higan exits.
higan stores the known cheats for a particular game
in `higan/cheats.bml`
inside the corresponding game folder
in [the Game Library](#the-game-library).
If your copy of higan includes a cheat database
(a file named `cheats.bml`
in the same directory as `Super Famicom.sys`
and the other `*.sys` directories),
you can click the "Find Codes ..." button in the bottom left
to load all known cheats for the currently-running game.
To add a new cheat,
select an unused row in the list,
then type the relevant codes in the "Code(s)" field at the bottom,
and a description in the "Description" field.
To enable or disable an existing cheat,
tick the checkbox in the first column of the list.
The code should take effect immediately.
To clear out an existing cheat,
select it from the list
and click the "Erase" button in the bottom right,
or just manually delete
the contents of the "Code(s)" and "Description" fields.
To clear out all existing cheats,
click the "Reset" button in the bottom right.
The State Manager
-----------------
@@ -95,10 +99,11 @@ For more information on Manager states,
quick states,
saved games
and how they compare,
see [Save States](#save-states).
see [Save States](../concepts/save-states.md).
To create a new manager state,
or to replace an existing one,
To save the current state of the loaded game
in a new slot,
or to replace the contents of an existing slot,
select the slot in the list
then click "Save" in the bottom-left corner.
You can then type a description in the "Description" field,
@@ -111,7 +116,7 @@ and edit the "Description" field.
To load a state,
select the slot in the list
and click "Load" in the bottom-left corner,
or just double-click it.
or just double-click the slot.
To clear the state out of a slot,
select the slot in the list
@@ -123,23 +128,10 @@ click "Reset" in the bottom-right corner.
The Manifest Viewer
-------------------
As mentioned in
[Why game folders?](#why-game-folders),
a game cartridge contains
more than just the raw data of the game.
As described in
[Game Manifests](../concepts/manifests.md),
higan uses a "manifest" to
describe how the various parts of a game cartridge
are wired up together,
and the Manifest Viewer lets you examine
the configuration higan is using for the currently-running game.
For some games,
an actual cartridge has been taken apart and carefully examined
and its configuration has been recorded in icarus' database,
so the manifest icarus produces
is guaranteed accurate.
For games that do not exist in icarus' database,
icarus will make a reasonable guess.
This is enough to get the game running,
but does not necessarily reflect the original cartridge.
are wired up together.
The Manifest Viewer lets you examine
the configuration higan is using for the loaded game.

View File

@@ -1,54 +1,31 @@
When you launch higan,
When you launch higan
the main window appears,
with a menu-bar across the top,
a status-bar across the bottom,
and a large area in the middle where the game's video output appears.
and a large area in the middle that shows
the running game's video output.
The Library menu
----------------
The Library menu allows you
to import games into higan's game library,
and to load games from the library.
higan organises the games in your library
according to which console they were intended to run on.
To play a game for a particular console from your library,
click on the Library menu,
click on the console manufacturer submenu
(Nintendo for the Super Famicom,
Bandai for the WonderSwan,
etc.)
then click on the console menu item.
A window will appear listing all the games in your library
for that particular console.
Select the game you want to play
and click the Open button,
or just double-click the game,
and it will begin playing as though you'd just turned on the console.
To add a new game to your library,
choose "Load ROM File ..." from the Library menu.
A [filesystem browser](#the-filesystem-browser) will appear,
allowing you to pick any ROM image for any supported system,
with any of the most common file extensions.
It also allows loading ROM images from `.zip` archives,
if the archive contains a single ROM image.
**Note:** Some games require extra steps to import correctly;
see [the Game Library](#the-game-library) for details.
TODO: Mention the region-picker.
To add many games at once,
run icarus,
or choose "Import ROM Files ..." from the Library menu
(which just runs icarus anyway).
See [the icarus interface](#the-icarus-interface)
for more information about bulk-importing.
For more information about the higan game library,
see [The Game Library](#the-game-library) below.
Manufacturer sub-menus
allow you to play
games you've already imported
into higan's
[game library](../concepts/game-library.md).
See [Importing and playing games](../guides/import.md).
**Load ROM File ...**
opens a [filesystem browser](common.md#the-filesystem-browser)
allowing you to choose a single ROM file.
It will be imported and immediately start playing.
See [Importing and playing games](../guides/import.md).
**Import ROM Files ...**
launches the icarus importing tool,
allowing you to bulk-import many ROM files at once.
See [the icarus documentation](icarus.md).
The console menu
---------------
@@ -69,52 +46,60 @@ to the particular console being emulated.
All consoles will have some of the following items,
but few consoles have all of them.
- **Controller Port 1**
allows you
to connect different emulated controllers
to the first controller port,
if there is one.
- See [the Configuration dialog](#the-configuration-dialog)
for information about configuring
which host controller inputs are used
for the emulated controllers.
- This menu appears for the Famicom,
even though the Famicom did not support alternate controllers,
because the Famicom emulation core also emulates the NES,
which did.
- **Controller Port 2**
allows you
to connect different emulated controllers
to the second controller port,
if there is one.
- See [the Configuration dialog](#the-configuration-dialog)
for information about configuring
which host controller inputs are used
for the emulated controllers.
- This menu appears for the Famicom,
even though the Famicom did not support alternate controllers,
because the Famicom emulation core also emulates the NES,
which did.
- **Expansion Port**
allows you
to connect different emulated devices
to the console's expansion port,
if there is one.
- For the Super Famicom,
the [21fx][21fx] is a homebrew device
that allows a program running on a PC
to control a physical Super Famicom (or SNES).
This option allows the same program
to control the emulated SNES,
for development or testing.
- **Power Cycle**
restarts the loaded game
as though the emulated console were switched off and on again.
- **Unload**
stops the current game,
as though the emulated console were switched off.
You can load the same or a different game
from [the Library menu](#the-library-menu).
**Controller Port 1**
allows you
to connect different emulated controllers
to the first controller port,
if there is one.
See [higan's Input settings](higan-settings.md#input)
for information about configuring
which PC controller inputs are used
for the emulated controllers.
This menu appears for the Famicom,
even though the Famicom did not support alternate controllers,
because the Famicom emulation core also emulates the NES,
which did.
**Controller Port 2**
allows you
to connect different emulated controllers
to the second controller port,
if there is one.
See [higan's Input settings](higan-settings.md#input)
for information about configuring
which PC controller inputs are used
for the emulated controllers.
This menu appears for the Famicom,
even though the Famicom did not support alternate controllers,
because the Famicom emulation core also emulates the NES,
which did.
**Expansion Port**
allows you
to connect different emulated devices
to the console's expansion port,
if there is one.
For the Super Famicom,
the [21fx][21fx] is a homebrew device
that allows a program running on a PC
to control a physical Super Famicom (or SNES).
This option allows the same program
to control the emulated SNES,
for development or testing.
**Power Cycle**
restarts the loaded game
as though the emulated console were switched off and on again.
**Unload**
stops the current game,
as though the emulated console were switched off.
You can load a new game
from [the Library menu](#the-library-menu).
[21fx]: https://github.com/defparam/21FX
@@ -124,78 +109,79 @@ The Settings menu
The Settings menu allows you to configure things
that aren't specific to any particular console.
- **Video Scale** determines the size and shape
of the emulated console's video output
in windowed mode
(as opposed to fullscreen).
- **Video Emulation** applies various effects
to the emulated console's video output
to reproduce some behaviours
that aren't technically part of the console itself.
- "Blurring" simulates the limited horizontal resolution
of standard-definition TVs
by blurring together horizontally-adjacent pixels.
Games like Jurassic Park for the Super Famicom
**Video Scale** determines the size
of the emulated console's video output
when higan is running in windowed mode
(as opposed to fullscreen).
**Video Emulation** applies various effects
to the emulated console's video output
to reproduce some behaviours
that aren't technically part of the console itself:
- **Blurring**
simulates the limited horizontal resolution
of standard-definition TVs
by blurring together horizontally-adjacent pixels.
For hand-held consoles,
this simulates the slow response time
of the cheap LCD screens these consoles used
by blending each output frame with the previous one.
- Games like
*Jurassic Park* for the Super Famicom
or *Chikyuu Kaihou Gun ZAS* for the Game Boy
depend on this to emulate a transparency effect.
For hand-held consoles like the Game Boy Advance,
this simulates the slow response time
of the cheap LCD screens these consoles used
by blurring each output frame with the previous one.
- "Colors" simulates the way a console's display device
differs from modern computer monitor's colour reproduction.
In particular,
it simulates the slightly-different gamma correction
used by the Super Famicom,
the dim, washed out colours of the original Game Boy Advance,
and the pea-green display of the original Game Boy.
- **Video Shader** controls
how the low-resolution video output of the emulated console
is scaled up to suit modern high-resolution displays.
The availability of items in this submenu depends on
which video driver higan is using,
so see [Drivers](#drivers) for more information.
- "None" draws each output pixel according to
the colour of the single nearest input pixel,
sometimes called "nearest neighbour" scaling.
This produces unnaturally crisp and blocky images.
- "Blur" draws each output pixel by
averaging the colours of the four nearest input pixels,
sometimes called "bilinear" scaling.
This produces unnaturally blurry images.
- When using the OpenGL [driver](#drivers),
an additional item appears in this menu for
each installed Quark shader.
See [Installing custom shaders](#installing-custom-shaders)
for details.
- **Synchronize Audio**
causes higan to wait for audio playback to complete
before resuming emulation.
This should reduce popping and glitching noises,
and slows the emulation down to approximately the correct speed.
If your PC cannot emulate at full-speed,
(60fps for most consoles, 75fps for WonderSwan)
this has no noticable effect.
- **Mute Audio**
causes higan to not output sound from the emulated console.
The sound hardware is still emulated.
- **Show Status Bar**
causes higan to show or hide the status bar
at the bottom of the window.
This option has no effect in full-screen mode.
See [The status bar](#the-status-bar) for more information.
- **Video ...**
opens the Video tab of [the Configuration dialog][cfgdlg].
- **Audio ...**
opens the Audio tab of [the Configuration dialog][cfgdlg].
- **Input ...**
opens the Input tab of [the Configuration dialog][cfgdlg].
- **Hotkey ...**
opens the Hotkeys tab of [the Configuration dialog][cfgdlg].
- **Advanced ...**
opens the Advanced tab of [the Configuration dialog][cfgdlg].
- **Colors**
simulates the way a console's display device
differs from modern computer monitor's colour reproduction.
In particular,
it simulates the slightly-different gamma correction
used by the Super Famicom,
the dim, washed out colours of the original Game Boy Advance,
and the pea-green display of the original Game Boy.
**Video Shader** controls
how the low-resolution video output of the emulated console
is scaled up to suit modern high-resolution displays.
[Using video shaders](../guides/shaders.md)
describes all the options in this sub-menu.
**Synchronize Audio**
causes higan to wait for audio playback to complete
before resuming emulation.
This should reduce popping and glitching noises,
and slows the emulation down to approximately the correct speed.
If your PC cannot emulate at full-speed,
(60fps for most consoles, 75fps for WonderSwan)
this has no noticeable effect.
**Mute Audio**
causes higan to not output sound from the emulated console.
The sound hardware is still emulated.
**Show Status Bar**
causes higan to show or hide the status bar
at the bottom of the window.
This option has no effect in fullscreen mode.
See [The status bar](#the-status-bar) for more information.
**Video ...**
opens [higan's Video settings](higan-settings.md#video).
**Audio ...**
opens [higan's Audio settings](higan-settings.md#audio).
**Input ...**
opens [higan's Input settings](higan-settings.md#input).
**Hotkeys ...**
opens [higan's Hotkeys settings](higan-settings.md#hotkeys).
**Advanced ...**
opens [higan's Advanced settings](higan-settings.md#advanced).
[svsa]: #why-do-synchronize-video-and-synchronize-audio-conflict
[cfgdlg]: #the-configuration-dialog
The Tools menu
--------------
@@ -203,33 +189,45 @@ The Tools menu
The Tools menu
contains features for manipulating the emulated console.
- **Save Quick State**
stores the current state of the emulated console
into one of the quick state slots.
See [Save States](#save-states) for more information.
- **Load Quick State**
restores the emulated console to
a state previously saved to one of the quick state slots.
See [Save States](#save-states) for more information.
- **Cheat Editor**
opens [the Cheat Editor window](#the-cheat-editor)
- **State Manager**
opens [the State Manager window](#the-state-manager)
- **Manifest Viewer**
opens [the Manifest Viewer window](#the-manifest-viewer)
**Save Quick State**
stores the current state of the emulated console
into one of the quick state slots.
See [Save States](../concepts/save-states.md) for more information.
**Load Quick State**
restores the emulated console to
a state previously saved to one of the quick state slots.
See [Save States](../concepts/save-states.md) for more information.
**Cheat Editor**
opens [the Cheat Editor tab](higan-tools.md#the-cheat-editor)
of the Tools window.
**State Manager**
opens [the State Manager tab](higan-tools.md#the-state-manager)
of the Tools window.
**Manifest Viewer**
opens [the Manifest Viewer tab](higan-tools.md#the-manifest-viewer)
of the Tools window.
The Help menu
-------------
The Help menu contains information about higan itself.
- **Documentation**
loads the official higan documentation
in your web-browser.
- **About**
opens the About dialog,
which displays basic information about higan,
including the version number.
**Documentation**
loads the official higan documentation
in your web-browser.
**Credits**
loads a list of people who have contributed to higan
in your web-browser.
**About**
opens the About dialog,
which displays basic information about higan,
including the version number.
The status bar
--------------
@@ -242,7 +240,7 @@ Before any game is loaded,
the status bar displays "No cartridge loaded".
When a game is loaded and running,
the status bar displays the current emulation speeed
the status bar displays the current emulation speed
in frames-per-second.
For PAL-based consoles,
this should be around 50 FPS for "full speed" emulation,
@@ -250,15 +248,15 @@ for NTSC and most portable consoles the ideal speed is 60 FPS,
but the WonderSwan runs at 75 FPS.
If the number is too low,
you may need a faster computer,
or a faster [video driver](#drivers).
or a faster [video driver](../guides/drivers.md#video).
If the number is too high,
you may need to [Synchronize Audio](#the-settings-menu),
or you may have pressed the "turbo" [hotkey](#the-configuration-dialog).
or you may have pressed the "turbo" [hotkey](higan-settings.md#hotkeys).
The status bar displays "Paused"
if you have pressed the "pause" [hotkey](#the-configuration-dialog),
if you have pressed the "pause" [hotkey](higan-settings.md#hotkeys),
or if "When focus is lost: Pause Emulation" is ticked
in [the Input tab of the Configuration dialog](#the-configuration-dialog)
in [higan's Input settings](higan-settings.md#input)
and the main higan window is not the foreground window.
To resume emulation,
make sure the main higan window is in the foreground,
@@ -282,7 +280,7 @@ or when you press the "Load Quick State" hotkey
while the current Quick State slot has not had a save-state saved to it,
The status bar briefly displays "Power cycled"
when you choose "Power Cycle" from [the console menu](#the-console menu),
when you choose "Power Cycle" from [the console menu](#the-console-menu),
or press the "Power Cycle" hotkey.
The status bar briefly displays "Display rotation not supported"

1
docs/interface/home.png Symbolic link
View File

@@ -0,0 +1 @@
../../hiro/resource/icon/go/home.png

View File

@@ -1,8 +1,16 @@
When launching icarus,
directly or by picking "Import ROM Files ..."
from higan's [Library menu](#the-library-menu),
from higan's [Library menu](higan.md#the-library-menu),
the main icarus window appears.
This is [a filesystem browser](#the-filesystem-browser),
This window allows you to bulk-import ROM files
into [higan's game library][gamelib],
and also to access icarus' settings.
Bulk importing ROM files
------------------------
icarus' main window
is [a filesystem browser](common.md#the-filesystem-browser),
with customisations:
- The filesystem browser only lists
@@ -15,46 +23,47 @@ with customisations:
- You can un-tick all the check-boxes
by pressing "Unselect All" in the bottom-left.
Pressing "Settings ..." in the bottom-right
opens [the icarus Settings dialog](#the-icarus-settings-dialog).
Pressing "Import ..." in the bottom-right
will close the filesystem browser
then try to import all the files
whose check-boxes are ticked
into [the Game Library](#the-game-library).
icarus displays a progress dialog during the import process.
into [the Game Library][gamelib].
icarus displays a progress dialog during the import process,
and a result window if any errors occurred.
**Note:** Some games require extra steps to import correctly;
see [the Game Library](#the-game-library) for details.
see [Importing and playing games](../guides/import.md) for details.
The icarus Settings dialog
--------------------------
Pressing "Settings ..."
in the bottom-right corner of the main icarus window
opens the settings dialog.
The icarus Settings dialog contains the following settings:
- **Library Location** determines
where icarus puts the games it imports.
See [Moving the Game Library](#moving-the-game-library)
See [Moving the Game Library][movgamelib]
for details.
- **Create Manifests** causes icarus
to write out a manifest file describing
each imported game
to that game's [game folder](#whats-in-a-game-folder).
This means that higan doesn't have to regenerate
the manifest each time an imported game is loaded,
but it means that a future version of higan
with an incompatible manifest format
may be unable to play these games.
Note that higan also has an "Ignore Manifests" option
in the Advanced tab of
[its Configuration dialog](#the-configuration-dialog).
to include
[a manifest file](../concepts/manifests.md)
inside
[the game folder](../concepts/game-folders.md)
for each imported game.
See [Ignoring manifests](../concepts/manifests.md#ignoring-manifests)
for details.
- **Use Database** causes icarus to use manifest information
from its database of known-good manifests,
if it's importing a game it recognises.
For unrecognised games,
and for all games if this box is unticked,
icarus gueses the manifest data.
icarus guesses the manifest data.
This option is still relevant when "Create Manifests" is unticked:
higan uses icarus to generate a manifest when a game is loaded,
not just at import-time.
[gamelib]: ../concepts/game-library.md
[movgamelib]: ../concepts/game-library.md#moving-the-game-library

1
docs/interface/refresh.png Symbolic link
View File

@@ -0,0 +1 @@
../../hiro/resource/icon/action/refresh.png

1
docs/interface/up.png Symbolic link
View File

@@ -0,0 +1 @@
../../hiro/resource/icon/go/up.png

View File

@@ -1,105 +1,21 @@
The consoles that higan emulates
are similar in many ways,
but some of them do have particular quirks
that you should be aware of.
Video Shaders and TV-based consoles
-----------------------------------
[Video Shaders](guides/shaders.md)
customize how higan scales
the low-resolution video of the emulated console
up to the high-resolution of the computer display.
Simple shaders
(like "None"
and the third-party "AANN" shader)
just blindly scale up the images they're given,
but sophisticated shaders
(such as the third-party "xBR" shader)
try to produce higher-quality output
by recognising particular patterns of pixel,
like taking three diagonal pixels
and turning that into a smooth diagonal line.
These shaders assume that
each pixel drawn by the game's artists
becomes a single pixel in the video output they analyze.
Many of the consoles higan emulates
can only output video at one specific resolution,
so this "one pixel equals one pixel" rule holds true,
and pattern-based shaders like "xBR" work just fine.
Unfortunately,
this is not the case for the Super Famicom.
The "normal" video mode
draws 256 pixels across the width of the screen,
but the "high resolution" mode draws 512.
Since Super Famicom games can enable hi-res mode at any time
(even halfway through a frame),
higan always renders Super Famicom video output 512 pixels wide,
just in case.
This means that in "normal" mode,
each pixel drawn by the game's artists
becomes two pixels in the video output,
breaking the assumption
that pattern-based shaders are based on.
The Super Famicom has a similar issue in the vertical direction:
normally,
an NTSC-based Super Famicom draws about 240 rows of output every frame,
sometimes referred to as "240p" video.
When a game turns on "interlaced" mode,
it draws the 240 odd-numbered lines of one frame,
then the 240 even-numbered lines of the next,
and so forth.
This is sometimes referred to as "480i" video.
Although interlaced mode cannot be enabled mid-frame
like high-resolution mode,
resolution switching is still complex,
so higan always draws all 480 lines of video output.
This means for a normal, non-interlaced game,
each pixel drawn by the game's artists
becomes four pixels in the video output
(two horizontally and two vertically)
making pattern-based shaders even less useful.
It also breaks most scanline-emulation shaders,
since they typically draw a scanline
for each row of pixels in the video output.
The Mega Drive has similar problems
to the Super Famicom.
It has the same behaviour with interlacing,
but its high-resolution mode switches
from 256 pixels across to 320 pixels across.
Therefore in normal mode,
each pixel drawn by the game's artists
becomes five pixels in the video output,
while in high-resolution mode,
each pixel drawn by the game's artists
becomes four pixels in the video output
(or 10 and 8 pixels in non-interlaced mode).
The PC Engine does not support an interlaced mode,
but its horizontal resolution is much more flexible
than the Super Famicom or Mega Drive,
and so it has the same problems with shaders.
but some of them do have particular quirks of their own.
Music and Sound Effect Volume on the Mega Drive
-----------------------------------------------
The Mega Drive has two different audio-generating chips:
- the SN76489 or "PSG" chip,
- the SN76489 or "PSG" chip
inherited from the Master System,
mostly used for sound-effects
like Sonic picking up rings
- the YM2612 or "FM" chip,
mostly used for music
With two different sound sources,
it's important that they have similar volumes,
or the sound-effects will drown out the music,
or vice-versa.
it's important that they have similar volumes
or one kind of sound will drown out the other.
Sega did *not* do this,
and different hardware revisions
used different relative volumes.
@@ -107,8 +23,8 @@ used different relative volumes.
higan currently
sets the PSG volume to [125% of the FM volume][vol],
based on [a Sega Genesis model 1 VA6][va6] that byuu owns.
If you feel sound-effects in higan's Mega Drive core
are too loud or too quiet,
If you feel sound-effects in higan's Mega Drive emulation
are too loud or too quiet compared to the music,
you may be comparing it
to a Mega Drive calibrated to a different scale
(or to an emulator tweaked to match such a Mega Drive).
@@ -116,12 +32,12 @@ to a Mega Drive calibrated to a different scale
[vol]: https://board.byuu.org/viewtopic.php?p=42482#p42482
[va6]: https://board.byuu.org/viewtopic.php?p=42195#p42195
Playing Game Boy Colour games in Game Boy mode
----------------------------------------------
Playing Game Boy Color games in Game Boy mode
---------------------------------------------
Games for the original Game Boy
came in solid grey cartridges,
and only supported four-shade greyscale graphics.
and only supported four-shade grey-scale graphics.
ROM files for these games
typically have filenames ending in `.gb`.
@@ -131,14 +47,14 @@ Games that required
the extra hardware in the Game Boy Color
came in transparent cartridges,
and had a slightly different shape
to prevent them from being used in original Game Boys..
to prevent them from being used in original Game Boys.
ROM files for these games
typically have filenames ending in `.gbc`.
However,
there were also some games
that could use colour if it was available,
but would stick to greyscale if it wasn't.
but would stick to grey-scale if it wasn't.
These games came in black cartridges.
ROM files for these games
typically have filenames ending in `.gbc`
@@ -198,17 +114,9 @@ higan must guess which storage type to use
and sometimes it guesses incorrectly.
If higan guesses incorrectly for a game you want to play,
you will need to turn on
"Create manifests" in
[the Icarus settings dialog](interface/icarus.md#the-icarus-settings-dialog),
turn off
"Ignore manifests" in
[higan's Advanced settings](interface/higan-config.md#advanced),
re-import the game,
and edit `manifest.bml` in
[the game folder](concepts/game-folders.md)
to describe the correct storage type.
Try importing other GBA games to see what save types they use.
you will need to override the automatically-generated manifest.
See [Ignoring manifests](concepts/manifests.md#ignoring-manifests)
for details.
For more discussion of the GBA save type mess,
see [What's the deal with... GBA save files?][gbasaves]
@@ -226,10 +134,10 @@ included a rumble motor within the cartridge itself.
Because higan does not currently support
game-specific controller features,
to experience the rumble effect in higan
you'll need to configure the console itself:
you'll need to configure the console:
- Open
[higan's Input settings](interface/higan-config.md#input)
[higan's Input settings](interface/higan-settings.md#input)
- In the list of consoles,
select Game Boy, or Game Boy Color
depending on which console you want to use to play the game
@@ -245,16 +153,16 @@ Rumble compatibility for Game Boy Advance
The original Game Boy Advance
and the Game Boy Advance SP
did not support any kind of rumble or force-feedback system,
but the Game Boy Player addon for the Gamecube
but the Game Boy Player add-on for the GameCube
allowed Game Boy Advance games
to use the rumble feature in Gamecube controllers.
to use the rumble feature in GameCube controllers.
Because rumble is a feature of the Game Boy Player,
to experience the rumble effect in higan
you'll need to configure the console itself:
- Open
[higan's Input settings](interface/higan-config.md#input)
[higan's Input settings](interface/higan-settings.md#input)
- In the list of consoles,
select Game Boy Advance
- In the list of inputs,
@@ -283,7 +191,7 @@ as well as a bonus mode in *Dr Mario + Puzzle League*,
expect the player to physically rotate the device
so the screen is tall rather than wide.
higan supports this feature with
a Rotate [hotkey](interface/higan-config.md#hotkeys).
a Rotate [hotkey](interface/higan-settings.md#hotkeys).
When the user presses the Rotate hotkey,
the console's video output is rotated 90° anti-clockwise,
@@ -303,7 +211,7 @@ vertically or horizontally.
that requires the player to repeatedly rotate
the device as they play.
higan supports this feature with
a Rotate [hotkey](interface/higan-config.md#hotkeys).
a Rotate [hotkey](interface/higan-settings.md#hotkeys).
When the user presses the Rotate hotkey,
the console's video output is rotated 90° anti-clockwise,

View File

@@ -1,4 +1,4 @@
If this is you're first time using higan,
If this is your first time using higan,
welcome!
Here's a brief guide to getting started:
@@ -13,7 +13,7 @@ and extracting it.
[More information...](install/windows.md)
On Linux,
if your distribution doesn't include the latest version,
if your distribution doesn't already include the latest version,
you'll need to compile it yourself — but don't worry,
it's not too complex.
[More information...](install/linux.md)
@@ -25,7 +25,7 @@ Once higan's installed,
start it up.
Open the "Settings" menu,
and choose "Input ..."
to open [the Input settings](interface/higan-config.md#input).
to open [the Input settings](interface/higan-settings.md#input).
higan supports a *lot* of different controllers
for a lot of different consoles,
@@ -63,7 +63,7 @@ In the future,
if you want to play this game again,
you can choose "Load ROM File ..." as you did before,
or you can choose the appropriate console name
from [the Library menu](interface/higan.md#the-library-menu),
from the Library menu,
which will list all the games for that console
in the Game Library.
@@ -79,11 +79,11 @@ that's a Super Famicom game
so there will be a Super Famicom menu.
Open [the console menu](interface/higan.md#the-console-menu),
and if there is a submenu for a controller port,
and if there is a sub-menu for a controller port,
make sure the port is using
the controller you [set up previously](#configuring-inputs).
If you configured inputs for a Gamepad in Controller Port 1,
the Controller Port 1 submenu
the Controller Port 1 sub-menu
should be set to Gamepad.
Like a real console,
higan's controller ports
@@ -96,7 +96,7 @@ like the Game Boy and WonderSwan,
since the "controller" is always connected.
This *does* apply to the Famicom,
even though the Famicom's controllers are hard-wired,
because higan uses "Famicom"
to mean Nintendo's 8-bit home console
because higan uses the name "Famicom"
to refer to Nintendo's 8-bit home console
in all territories,
including the Nintendo Entertainment System.

14
docs/release.md Normal file
View File

@@ -0,0 +1,14 @@
Release checklist
=================
1. Commit the new release
2. Tag the commit
3. `git push --tags origin master` to push the commit and tag at the
same time.
4. Go to [the docs admin][rtd] and verify that it's building the new
version as 'stable' and under its tag name.
5. Check out the `libretro` branch.
6. Merge changes from master.
7. `git push` to make the new changes available.
[rtd]: https://readthedocs.org/projects/higan/builds/

View File

@@ -1,28 +1,38 @@
build := release
build := optimize
include ../nall/GNUmakefile
binary := application
target := tomoko
objects := libco emulator audio video resource
# console := true
flags += -I. -I..
ifeq ($(platform),windows)
ifeq ($(console),true)
link += -mconsole
else
link += -mwindows
link += $(if $(call streq,$(console),true),-mconsole,-mwindows)
ifeq ($(binary),application)
link += -mthreads -lpthread -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
link += -Wl,-enable-auto-import
link += -Wl,-enable-runtime-pseudo-reloc
else ifeq ($(binary),library)
link += -shared
endif
else ifeq ($(platform),macos)
ifeq ($(binary),application)
else ifeq ($(binary),library)
flags += -fPIC
link += -dynamiclib
endif
link += -mthreads -lpthread -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
link += -Wl,-enable-auto-import
link += -Wl,-enable-runtime-pseudo-reloc
else ifeq ($(platform),macosx)
flags += -march=native
else ifneq ($(filter $(platform),linux bsd),)
flags += -march=native -fopenmp
flags += -fopenmp
link += -fopenmp
link += -Wl,-export-dynamic
link += -lX11 -lXext
ifeq ($(binary),application)
flags += -march=native
link += -Wl,-export-dynamic
link += -lX11 -lXext
else ifeq ($(binary),library)
flags += -fPIC
link += -shared
endif
else
$(error "unsupported platform")
endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 13 KiB

84
higan/data/higan.svg Normal file
View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256mm"
height="256mm"
viewBox="0 0 256 256"
version="1.1"
id="svg8"
inkscape:version="0.92.2 (5c3e80d, 2017-08-06)"
sodipodi:docname="higan.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.5"
inkscape:cx="-264.38189"
inkscape:cy="632.78774"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1028"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-41)">
<circle
id="path10"
cx="128.0"
cy="169.0"
r="120.0"
style="stroke-width:0.25;fill:#ffc0c0;fill-opacity:1" />
<g
aria-label="火"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:254.9591217px;line-height:1.25;font-family:KaiTi;-inkscape-font-specification:KaiTi;letter-spacing:0px;word-spacing:0px;fill:#e01818;fill-opacity:1;stroke:#e01818;stroke-width:9;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="text818"
transform="translate(318.55834,64.029166)">
<path
style="fill:#e01818;fill-opacity:1;stroke:#e01818;stroke-width:9;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m -194.12628,101.7548 q 15.93495,23.90242 34.85769,43.8211 19.91869,19.91868 37.8455,30.87396 18.92275,9.95934 40.833295,16.93088 21.91055,5.9756 -2.987802,7.96747 -24.898353,1.99187 -37.845493,0 -11.95121,-0.99594 -27.88616,-21.91055 -14.93901,-20.91462 -46.8089,-66.72758 -5.9756,25.89428 -13.94307,41.82923 -7.96748,14.93901 -26.89022,30.87395 -18.92275,14.93901 -39.83737,17.92682 -19.91868,3.98373 -3.98373,-3.98374 16.93088,-6.97154 33.86176,-21.91055 17.92681,-14.93901 26.89022,-34.85769 8.9634,-20.91462 10.95527,-50.79264 2.9878,-29.878022 1.99187,-50.792637 0,-20.914616 -4.97967,-28.882088 -4.97967,-8.963407 2.9878,-5.9756048 8.96341,1.9918681 16.93088,5.9756048 8.96341,2.987802 5.9756,8.963406 -2.9878,4.979671 -5.9756,33.861759 -1.99187,27.886153 -1.99187,46.8089 z"
id="path827"
inkscape:connector-curvature="0" />
<path
style="fill:#e01818;fill-opacity:1;stroke:#e01818;stroke-width:9;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m -110.28062,50.929737 q 7.96747,6.971538 0,8.963407 -6.97154,0.995934 -22.90648,10.955274 -14.93901,8.963407 -28.88209,15.934945 -12.94714,5.975604 -1.99187,-3.983736 11.95121,-10.955275 21.91055,-21.910549 10.95528,-10.955275 10.95528,-17.926814 0,-7.967472 6.97153,-3.983736 6.97154,3.983736 13.94308,11.951209 z"
id="path825"
inkscape:connector-curvature="0" />
<path
style="fill:#e01818;fill-opacity:1;stroke:#e01818;stroke-width:9;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m -261.66505,69.757659 q -15.93494,-24.898352 0,-15.934945 15.93495,7.967472 20.91462,14.939011 4.97967,5.975604 0.99593,16.930876 -3.98373,10.95528 -21.91055,-15.934942 z"
id="path820"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -12,10 +12,10 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "104";
static const string Version = "106";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";
static const string Website = "https://byuu.org/";
//incremented only when serialization format changes
static const string SerializerVersion = "104";

View File

@@ -6,7 +6,8 @@ struct Interface {
struct Information {
string manufacturer;
string name;
bool overscan;
bool overscan = false;
bool resettable = false;
} information;
struct Medium {
@@ -37,15 +38,15 @@ struct Interface {
virtual auto manifest() -> string = 0;
virtual auto title() -> string = 0;
//video information
struct VideoResolution {
uint width;
uint height;
uint internalWidth;
uint internalHeight;
double aspectCorrection;
struct VideoInformation {
uint width = 0;
uint height = 0;
uint internalWidth = 0;
uint internalHeight = 0;
double aspectCorrection = 0;
double refreshRate = 0;
};
virtual auto videoResolution() -> VideoResolution = 0;
virtual auto videoInformation() -> VideoInformation = 0;
virtual auto videoColors() -> uint32 = 0;
virtual auto videoColor(uint32 color) -> uint64 = 0;
@@ -59,6 +60,7 @@ struct Interface {
//system interface
virtual auto connect(uint port, uint device) -> void {}
virtual auto power() -> void {}
virtual auto reset() -> void {}
virtual auto run() -> void {}
//time functions

96
higan/emulator/random.hpp Normal file
View File

@@ -0,0 +1,96 @@
#pragma once
namespace Emulator {
struct Random {
enum class Entropy : uint { None, Low, High };
auto operator()() -> uint64 {
return random();
}
auto entropy(Entropy entropy) -> void {
_entropy = entropy;
seed();
}
auto seed(maybe<uint32> seed = nothing, maybe<uint32> sequence = nothing) -> void {
if(!seed) seed = (uint32)clock();
if(!sequence) sequence = 0;
_state = 0;
_increment = sequence() << 1 | 1;
step();
_state += seed();
step();
}
auto random() -> uint64 {
if(_entropy == Entropy::None) return 0;
return (uint64)step() << 32 | (uint64)step() << 0;
}
auto bias(uint64 bias) -> uint64 {
if(_entropy == Entropy::None) return bias;
return random();
}
auto bound(uint64 bound) -> uint64 {
uint64 threshold = -bound % bound;
while(true) {
uint64 result = random();
if(result >= threshold) return result % bound;
}
}
auto array(uint8* data, uint32 size) -> void {
if(_entropy == Entropy::None) {
memory::fill(data, size);
return;
}
if(_entropy == Entropy::High) {
for(uint32 address : range(size)) {
data[address] = random();
}
return;
}
//Entropy::Low
uint lobit = random() & 3;
uint hibit = (lobit + 8 + (random() & 3)) & 15;
uint lovalue = random() & 255;
uint hivalue = random() & 255;
if((random() & 3) == 0) lovalue = 0;
if((random() & 1) == 0) hivalue = ~lovalue;
for(uint32 address : range(size)) {
uint8 value = address.bit(lobit) ? lovalue : hivalue;
if(address.bit(hibit)) value = ~value;
if((random() & 511) == 0) value.bit(random() & 7) ^= 1;
if((random() & 2047) == 0) value.bit(random() & 7) ^= 1;
data[address] = value;
}
}
auto serialize(serializer& s) -> void {
s.integer((uint&)_entropy);
s.integer(_state);
s.integer(_increment);
}
private:
auto step() -> uint32 {
uint64 state = _state;
_state = state * 6364136223846793005ull + _increment;
uint32 xorshift = (state >> 18 ^ state) >> 27;
uint32 rotate = state >> 59;
return xorshift >> rotate | xorshift << (-rotate & 31);
}
Entropy _entropy = Entropy::High;
uint64 _state;
uint64 _increment;
};
}

View File

@@ -71,7 +71,7 @@ auto APU::setSample(int16 sample) -> void {
cartridgeSample = sample;
}
auto APU::power() -> void {
auto APU::power(bool reset) -> void {
create(APU::Enter, system.frequency());
stream = Emulator::audio.createStream(1, frequency() / rate());
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 90.0);

View File

@@ -12,7 +12,7 @@ struct APU : Thread {
auto setIRQ() -> void;
auto setSample(int16 sample) -> void;
auto power() -> void;
auto power(bool reset) -> void;
auto readIO(uint16 addr) -> uint8;
auto writeIO(uint16 addr, uint8 data) -> void;

View File

@@ -24,16 +24,16 @@ auto CPU::step(uint clocks) -> void {
for(auto peripheral : peripherals) synchronize(*peripheral);
}
auto CPU::power() -> void {
auto CPU::power(bool reset) -> void {
MOS6502::BCD = 0;
MOS6502::power();
create(CPU::Enter, system.frequency());
for(auto addr : range(0x0800)) ram[addr] = 0xff;
ram[0x0008] = 0xf7;
ram[0x0009] = 0xef;
ram[0x000a] = 0xdf;
ram[0x000f] = 0xbf;
if(!reset) for(auto& data : ram) data = 0xff;
ram[0x008] = 0xf7; //todo: what is this about?
ram[0x009] = 0xef;
ram[0x00a] = 0xdf;
ram[0x00f] = 0xbf;
r.pc.byte(0) = bus.read(0xfffc);
r.pc.byte(1) = bus.read(0xfffd);

View File

@@ -6,7 +6,7 @@ struct CPU : Processor::MOS6502, Thread {
auto main() -> void;
auto step(uint clocks) -> void;
auto power() -> void;
auto power(bool reset) -> void;
//memory.cpp
auto readRAM(uint11 addr) -> uint8;
@@ -37,7 +37,7 @@ struct CPU : Processor::MOS6502, Thread {
//protected:
vector<Thread*> peripherals;
uint8 ram[0x0800];
uint8 ram[0x800];
struct IO {
bool interruptPending;

View File

@@ -8,6 +8,7 @@ Interface::Interface() {
information.manufacturer = "Nintendo";
information.name = "Famicom";
information.overscan = true;
information.resettable = true;
media.append({ID::Famicom, "Famicom", "fc"});
@@ -44,8 +45,15 @@ auto Interface::title() -> string {
return cartridge.title();
}
auto Interface::videoResolution() -> VideoResolution {
return {256, 240, 256, 240, 8.0 / 7.0};
auto Interface::videoInformation() -> VideoInformation {
VideoInformation vi;
vi.width = 256;
vi.height = 240;
vi.internalWidth = 256;
vi.internalHeight = 240;
vi.aspectCorrection = 8.0 / 7.0;
vi.refreshRate = system.frequency() / (ppu.vlines() * ppu.rate() * 341.0);
return vi;
}
auto Interface::videoColors() -> uint32 {
@@ -130,7 +138,11 @@ auto Interface::connect(uint port, uint device) -> void {
}
auto Interface::power() -> void {
system.power();
system.power(/* reset = */ false);
}
auto Interface::reset() -> void {
system.power(/* reset = */ true);
}
auto Interface::run() -> void {

View File

@@ -26,7 +26,7 @@ struct Interface : Emulator::Interface {
auto manifest() -> string override;
auto title() -> string override;
auto videoResolution() -> VideoResolution override;
auto videoInformation() -> VideoInformation override;
auto videoColors() -> uint32 override;
auto videoColor(uint32 color) -> uint64 override;
@@ -38,6 +38,7 @@ struct Interface : Emulator::Interface {
auto connect(uint port, uint device) -> void override;
auto power() -> void override;
auto reset() -> void override;
auto run() -> void override;
auto serialize() -> serializer override;

View File

@@ -54,18 +54,20 @@ auto PPU::refresh() -> void {
Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240);
}
auto PPU::power() -> void {
auto PPU::power(bool reset) -> void {
create(PPU::Enter, system.frequency());
memory::fill(&io, sizeof(IO));
memory::fill(&latch, sizeof(Latches));
io.vramIncrement = 1;
for(auto& n : ciram ) n = 0;
for(auto& n : cgram ) n = 0;
for(auto& n : oam ) n = 0;
if(!reset) {
for(auto& data : ciram ) data = 0;
for(auto& data : cgram ) data = 0;
for(auto& data : oam ) data = 0;
}
for(auto& n : buffer) n = 0;
for(auto& data : buffer) data = 0;
}
}

View File

@@ -11,7 +11,7 @@ struct PPU : Thread {
auto frame() -> void;
auto refresh() -> void;
auto power() -> void;
auto power(bool reset) -> void;
//memory.cpp
auto readCIRAM(uint11 addr) -> uint8;

View File

@@ -31,7 +31,7 @@ auto System::unserialize(serializer& s) -> bool {
if(signature != 0x31545342) return false;
if(string{version} != Emulator::SerializerVersion) return false;
power();
power(/* reset = */ false);
serializeAll(s);
return true;
}

View File

@@ -62,7 +62,7 @@ auto System::unload() -> void {
information.loaded = false;
}
auto System::power() -> void {
auto System::power(bool reset) -> void {
Emulator::video.reset();
Emulator::video.setInterface(interface);
configureVideoPalette();
@@ -73,9 +73,9 @@ auto System::power() -> void {
scheduler.reset();
cartridge.power();
cpu.power();
apu.power();
ppu.power();
cpu.power(reset);
apu.power(reset);
ppu.power(reset);
scheduler.primary(cpu);
controllerPort1.power(ID::Port::Controller1);

View File

@@ -11,7 +11,7 @@ struct System {
auto load(Emulator::Interface*) -> bool;
auto save() -> void;
auto unload() -> void;
auto power() -> void;
auto power(bool reset) -> void;
auto init() -> void;
auto term() -> void;

View File

@@ -36,8 +36,15 @@ auto Interface::title() -> string {
return cartridge.title();
}
auto Interface::videoResolution() -> VideoResolution {
return {160, 144, 160, 144, 1.0};
auto Interface::videoInformation() -> VideoInformation {
VideoInformation vi;
vi.width = 160;
vi.height = 144;
vi.internalWidth = 160;
vi.internalHeight = 144;
vi.aspectCorrection = 1.0;
vi.refreshRate = (4.0 * 1024.0 * 1024.0) / (154.0 * 456.0);
return vi;
}
auto Interface::loaded() -> bool {

View File

@@ -23,7 +23,7 @@ struct Interface : Emulator::Interface {
auto manifest() -> string override;
auto title() -> string override;
auto videoResolution() -> VideoResolution override;
auto videoInformation() -> VideoInformation override;
auto loaded() -> bool override;
auto sha256() -> string override;

View File

@@ -24,6 +24,7 @@ auto CPU::main() -> void {
Thread::step(16);
synchronize(ppu);
synchronize(apu);
synchronize(player);
}
context.stopped = false;
}
@@ -61,6 +62,7 @@ auto CPU::step(uint clocks) -> void {
Thread::step(clocks);
synchronize(ppu);
synchronize(apu);
synchronize(player);
}
auto CPU::power() -> void {

View File

@@ -36,10 +36,6 @@ namespace GameBoyAdvance {
inline auto synchronize(Thread& thread) -> void {
if(clock() >= thread.clock()) scheduler.resume(thread);
}
inline auto step(uint clocks) -> void {
_clock += clocks;
}
};
#include <gba/memory/memory.hpp>

View File

@@ -39,12 +39,19 @@ auto Interface::title() -> string {
return cartridge.title();
}
auto Interface::videoResolution() -> VideoResolution {
if(!settings.rotateLeft) {
return {240, 160, 240, 160, 1.0};
} else {
return {160, 240, 160, 240, 1.0};
auto Interface::videoInformation() -> VideoInformation {
VideoInformation vi;
vi.width = 240;
vi.height = 160;
vi.internalWidth = 240;
vi.internalHeight = 160;
vi.aspectCorrection = 1.0;
vi.refreshRate = system.frequency() / (228.0 * 1232.0);
if(settings.rotateLeft) {
swap(vi.width, vi.height);
swap(vi.internalWidth, vi.internalHeight);
}
return vi;
}
auto Interface::videoColors() -> uint32 {

View File

@@ -23,7 +23,7 @@ struct Interface : Emulator::Interface {
auto manifest() -> string override;
auto title() -> string override;
auto videoResolution() -> VideoResolution override;
auto videoInformation() -> VideoInformation override;
auto videoColors() -> uint32 override;
auto videoColor(uint32 color) -> uint64 override;

View File

@@ -7,7 +7,26 @@ namespace GameBoyAdvance {
Player player;
#include "serialization.cpp"
auto Player::Enter() -> void {
while(true) scheduler.synchronize(), player.main();
}
auto Player::main() -> void {
if(status.timeout && !--status.timeout) {
platform->inputRumble(0, 0, 10, false);
}
step(1);
}
auto Player::step(uint clocks) -> void {
Thread::step(clocks);
synchronize(cpu);
}
auto Player::power() -> void {
create(Player::Enter, 1'000.0);
status.enable = false;
status.rumble = false;
@@ -17,9 +36,12 @@ auto Player::power() -> void {
status.packet = 0;
status.send = 0;
status.recv = 0;
status.timeout = 0;
}
auto Player::frame() -> void {
//todo: this is not a very performant way of detecting the GBP logo ...
uint32 hash = Hash::CRC32(ppu.output, 240 * 160 * sizeof(uint32)).value();
status.logoDetected = (hash == 0x7776eb55);
@@ -101,6 +123,7 @@ auto Player::write(uint2 addr, uint8 byte) -> void {
if(addr == 3 && status.packet == 15) {
status.rumble = (status.recv & 0xff) == 0x26; //on = 0x26, off = 0x04
platform->inputRumble(0, 0, 10, status.rumble);
if(status.rumble) status.timeout = 500; //stop rumble manually after 500ms
}
}

View File

@@ -1,4 +1,18 @@
struct Player {
struct Player : Thread {
static auto Enter() -> void;
auto main() -> void;
auto step(uint clocks) -> void;
auto power() -> void;
auto frame() -> void;
auto keyinput() -> maybe<uint16>;
auto read() -> maybe<uint32>;
auto write(uint2 addr, uint8 byte) -> void;
auto serialize(serializer& s) -> void;
private:
struct Status {
bool enable;
bool rumble;
@@ -9,16 +23,9 @@ struct Player {
uint packet;
uint32 send;
uint32 recv;
uint timeout;
} status;
auto power() -> void;
auto frame() -> void;
auto keyinput() -> maybe<uint16>;
auto read() -> maybe<uint32>;
auto write(uint2 addr, uint8 byte) -> void;
auto serialize(serializer& s) -> void;
};
extern Player player;

View File

@@ -8,4 +8,6 @@ auto Player::serialize(serializer& s) -> void {
s.integer(status.packet);
s.integer(status.send);
s.integer(status.recv);
s.integer(status.timeout);
}

View File

@@ -72,6 +72,7 @@ auto System::runToSave() -> void {
scheduler.synchronize(cpu);
scheduler.synchronize(ppu);
scheduler.synchronize(apu);
scheduler.synchronize(player);
}
}

View File

@@ -52,11 +52,13 @@ auto APU::enable(bool value) -> void {
state.enabled = value;
}
auto APU::power() -> void {
auto APU::power(bool reset) -> void {
Z80::bus = this;
Z80::power();
bus->grant(false);
create(APU::Enter, system.frequency() / 15.0);
if(!reset) memory::fill(ram, sizeof ram);
state = {};
}

View File

@@ -8,7 +8,7 @@ struct APU : Processor::Z80, Processor::Z80::Bus, Thread {
auto synchronizing() const -> bool override;
auto enable(bool) -> void;
auto power() -> void;
auto power(bool reset) -> void;
auto reset() -> void;
auto setNMI(bool value) -> void;

View File

@@ -80,11 +80,13 @@ auto CPU::load(Markup::Node node) -> bool {
return true;
}
auto CPU::power() -> void {
auto CPU::power(bool reset) -> void {
M68K::bus = this;
M68K::power();
create(CPU::Enter, system.frequency() / 7.0);
if(!reset) memory::fill(ram, sizeof ram);
io = {};
io.version = tmssEnable;
io.romEnable = !tmssEnable;

View File

@@ -19,7 +19,7 @@ struct CPU : Processor::M68K, Processor::M68K::Bus, Thread {
auto lower(Interrupt) -> void;
auto load(Markup::Node) -> bool;
auto power() -> void;
auto power(bool reset) -> void;
//bus.cpp
auto readByte(uint24 address) -> uint16 override;

View File

@@ -8,6 +8,7 @@ Interface::Interface() {
information.manufacturer = "Sega";
information.name = "Mega Drive";
information.overscan = true;
information.resettable = true;
media.append({ID::MegaDrive, "Mega Drive", "md"});
@@ -64,22 +65,36 @@ auto Interface::title() -> string {
return cartridge.title();
}
auto Interface::videoResolution() -> VideoResolution {
return {320, 240, 1280, 480, 1.0};
auto Interface::videoInformation() -> VideoInformation {
VideoInformation vi;
vi.width = 320;
vi.height = 240;
vi.internalWidth = 1280;
vi.internalHeight = 480;
vi.aspectCorrection = 1.0;
vi.refreshRate = (system.frequency() / 2.0) / (vdp.frameHeight() * 1710.0);
return vi;
}
auto Interface::videoColors() -> uint32 {
return 1 << 9;
return 3 * (1 << 9);
}
auto Interface::videoColor(uint32 color) -> uint64 {
uint R = color.bits(0,2);
uint G = color.bits(3,5);
uint B = color.bits(6,8);
uint R = color.bits(0, 2);
uint G = color.bits(3, 5);
uint B = color.bits(6, 8);
uint M = color.bits(9,10);
uint64 r = image::normalize(R, 3, 16);
uint64 g = image::normalize(G, 3, 16);
uint64 b = image::normalize(B, 3, 16);
uint lookup[3][8] = {
{ 0, 29, 52, 70, 87, 101, 116, 130}, //shadow
{ 0, 52, 87, 116, 144, 172, 206, 255}, //normal
{130, 144, 158, 172, 187, 206, 228, 255}, //highlight
};
uint64 r = image::normalize(lookup[M][R], 8, 16);
uint64 g = image::normalize(lookup[M][G], 8, 16);
uint64 b = image::normalize(lookup[M][B], 8, 16);
return r << 32 | g << 16 | b << 0;
}
@@ -108,7 +123,11 @@ auto Interface::connect(uint port, uint device) -> void {
}
auto Interface::power() -> void {
system.power();
system.power(/* reset = */ false);
}
auto Interface::reset() -> void {
system.power(/* reset = */ true);
}
auto Interface::run() -> void {

View File

@@ -27,7 +27,7 @@ struct Interface : Emulator::Interface {
auto manifest() -> string override;
auto title() -> string override;
auto videoResolution() -> VideoResolution override;
auto videoInformation() -> VideoInformation override;
auto videoColors() -> uint32 override;
auto videoColor(uint32 color) -> uint64 override;
@@ -38,6 +38,7 @@ struct Interface : Emulator::Interface {
auto connect(uint port, uint device) -> void override;
auto power() -> void override;
auto reset() -> void override;
auto run() -> void override;
auto serialize() -> serializer override;

View File

@@ -34,7 +34,7 @@ auto PSG::step(uint clocks) -> void {
synchronize(apu);
}
auto PSG::power() -> void {
auto PSG::power(bool reset) -> void {
create(PSG::Enter, system.frequency() / 15.0);
stream = Emulator::audio.createStream(1, frequency() / 16.0);
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);

View File

@@ -7,7 +7,7 @@ struct PSG : Thread {
auto main() -> void;
auto step(uint clocks) -> void;
auto power() -> void;
auto power(bool reset) -> void;
//io.cpp
auto write(uint8 data) -> void;

View File

@@ -48,7 +48,7 @@ auto System::unserialize(serializer& s) -> bool {
if(signature != 0x31545342) return false;
if(string{version} != Emulator::SerializerVersion) return false;
power();
power(/* reset = */ false);
serializeAll(s);
return true;
}

View File

@@ -61,7 +61,7 @@ auto System::unload() -> void {
cartridge.unload();
}
auto System::power() -> void {
auto System::power(bool reset) -> void {
Emulator::video.reset();
Emulator::video.setInterface(interface);
Emulator::video.setPalette();
@@ -71,11 +71,11 @@ auto System::power() -> void {
scheduler.reset();
cartridge.power();
cpu.power();
apu.power();
vdp.power();
psg.power();
ym2612.power();
cpu.power(reset);
apu.power(reset);
vdp.power(reset);
psg.power(reset);
ym2612.power(reset);
scheduler.primary(cpu);
controllerPort1.power(ID::Port::Controller1);

View File

@@ -15,7 +15,7 @@ struct System {
auto load(Emulator::Interface*, maybe<Region> = nothing) -> bool;
auto save() -> void;
auto unload() -> void;
auto power() -> void;
auto power(bool reset) -> void;
//serialization.cpp
auto serializeInit() -> void;

View File

@@ -16,7 +16,7 @@ auto VDP::Background::updateHorizontalScroll(uint y) -> void {
state.horizontalScroll = vdp.vram.read(address).bits(0,9);
}
auto VDP::Background::updateVerticalScroll(uint x, uint y) -> void {
auto VDP::Background::updateVerticalScroll(uint x) -> void {
if(id == ID::Window) return;
auto address = (x >> 4 & 0 - io.verticalScrollMode) << 1;
@@ -45,38 +45,36 @@ auto VDP::Background::scanline(uint y) -> void {
}
auto VDP::Background::run(uint x, uint y) -> void {
updateVerticalScroll(x, y);
updateVerticalScroll(x);
output.priority = 0;
output.color = 0;
bool interlace = vdp.io.interlaceMode == 3;
if(interlace) y = y << 1 | vdp.state.field;
x -= state.horizontalScroll;
y += state.verticalScroll;
uint width = nametableWidth();
uint height = nametableHeight();
uint tileX = x >> 3 & width - 1;
uint tileY = y >> 3 & height - 1;
uint tileX = x >> 3 & nametableWidth() - 1;
uint tileY = y >> 3 + interlace & nametableHeight() - 1;
auto address = nametableAddress();
address += (tileY * width + tileX) & 0x0fff;
address += (tileY * nametableWidth() + tileX) & 0x0fff;
uint pixelX = x & 7;
uint pixelY = y & 7 + interlace * 8;
uint16 tileAttributes = vdp.vram.read(address);
uint15 tileAddress = tileAttributes.bits(0,10) << 4;
uint pixelX = (x & 7) ^ (tileAttributes.bit(11) ? 7 : 0);
uint pixelY = (y & 7) ^ (tileAttributes.bit(12) ? 7 : 0);
uint15 tileAddress = tileAttributes.bits(0,10) << 4 + interlace;
if(tileAttributes.bit(11)) pixelX ^= 7;
if(tileAttributes.bit(12)) pixelY ^= 7 + interlace * 8;
tileAddress += pixelY << 1 | pixelX >> 2;
uint16 tileData = vdp.vram.read(tileAddress);
uint4 color = tileData >> (((pixelX & 3) ^ 3) << 2);
if(color) {
output.color = tileAttributes.bits(13,14) << 4 | color;
output.priority = tileAttributes.bit(15);
}
output.color = color ? tileAttributes.bits(13,14) << 4 | color : 0;
output.priority = tileAttributes.bit(15);
}
auto VDP::Background::power() -> void {
memory::fill(&io, sizeof(IO));
memory::fill(&state, sizeof(State));
io = {};
state = {};
}

View File

@@ -13,7 +13,12 @@ auto VDP::read(uint24 addr) -> uint16 {
//counter
case 0xc00008: case 0xc0000a: case 0xc0000c: case 0xc0000e: {
return state.vcounter << 8 | (state.hdot >> 1) << 0;
auto vcounter = state.vcounter;
if(io.interlaceMode.bit(0)) {
if(io.interlaceMode.bit(1)) vcounter <<= 1;
vcounter.bit(0) = vcounter.bit(8);
}
return vcounter << 8 | (state.hdot >> 1) << 0;
}
}
@@ -113,12 +118,23 @@ auto VDP::writeDataPort(uint16 data) -> void {
auto VDP::readControlPort() -> uint16 {
io.commandPending = false;
uint16 result = 0b0011'0100'0000'0000;
result |= 1 << 9; //FIFO empty
result |= (state.vcounter >= screenHeight()) << 3; //vertical blank
result |= (state.hcounter >= 1280) << 2; //horizontal blank
result |= io.command.bit(5) << 1; //DMA active
result |= Region::PAL() << 0;
uint16 result;
result.bit( 0) = Region::PAL();
result.bit( 1) = io.command.bit(5); //DMA active
result.bit( 2) = state.hcounter >= 1280; //horizontal blank
result.bit( 3) = state.vcounter >= screenHeight(); //vertical blank
result.bit( 4) = io.interlaceMode.bit(0) && state.field;
result.bit( 5) = 0; //SCOL
result.bit( 6) = 0; //SOVR
result.bit( 7) = io.vblankIRQ;
result.bit( 8) = 0; //FIFO full
result.bit( 9) = 1; //FIFO empty
result.bit(10) = 1; //constants (bits 10-15)
result.bit(11) = 0;
result.bit(12) = 1;
result.bit(13) = 1;
result.bit(14) = 0;
result.bit(15) = 0;
return result;
}

View File

@@ -1,15 +1,4 @@
auto VDP::frame() -> void {
latch.overscan = io.overscan;
}
auto VDP::scanline() -> void {
state.hdot = 0;
state.hcounter = 0;
if(++state.vcounter >= frameHeight()) state.vcounter = 0;
if(state.vcounter == 0) frame();
latch.displayWidth = io.displayWidth;
if(state.vcounter < screenHeight()) {
planeA.scanline(state.vcounter);
window.scanline(state.vcounter);
@@ -31,22 +20,45 @@ auto VDP::run() -> void {
planeB.run(state.hdot, state.vcounter);
sprite.run(state.hdot, state.vcounter);
auto output = io.backgroundColor;
if(auto color = planeB.output.color) output = color;
if(auto color = planeA.output.color) output = color;
if(auto color = sprite.output.color) output = color;
if(planeB.output.priority) if(auto color = planeB.output.color) output = color;
if(planeA.output.priority) if(auto color = planeA.output.color) output = color;
if(sprite.output.priority) if(auto color = sprite.output.color) output = color;
Pixel g = {io.backgroundColor, 0};
Pixel a = planeA.output;
Pixel b = planeB.output;
Pixel s = sprite.output;
outputPixel(cram.read(output));
state.hdot++;
auto& bg = a.above() || a.color && !b.above() ? a : b.color ? b : g;
auto& fg = s.above() || s.color && !b.above() && !a.above() ? s : bg;
if(!io.shadowHighlightEnable) {
auto color = cram.read(fg.color);
outputPixel(1 << 9 | color);
} else {
uint mode = a.priority || b.priority; //0 = shadow, 1 = normal, 2 = highlight
if(&fg == &s) switch(s.color) {
case 0x0e:
case 0x1e:
case 0x2e: mode = 1; break;
case 0x3e: mode += 1; fg = bg; break;
case 0x3f: mode = 0; fg = bg; break;
default: mode |= s.priority; break;
}
auto color = cram.read(fg.color);
outputPixel(mode << 9 | color);
}
}
auto VDP::outputPixel(uint9 color) -> void {
for(auto n : range(pixelWidth())) {
state.output[ 0 + n] = color;
state.output[1280 + n] = color;
auto VDP::outputPixel(uint32 color) -> void {
uint32* field[2] = {&state.output[0], &state.output[1280]};
if(!io.interlaceMode.bit(0)) {
for(auto n : range(pixelWidth())) {
field[0][n] = color;
field[1][n] = color;
}
} else {
for(auto n : range(pixelWidth())) {
field[state.field][n] = color;
}
}
state.output += pixelWidth();
}

View File

@@ -11,6 +11,7 @@ auto VDP::serialize(serializer& s) -> void {
vsram.serialize(s);
cram.serialize(s);
s.integer(io.vblankIRQ);
s.integer(io.command);
s.integer(io.address);
s.integer(io.commandPending);
@@ -43,6 +44,7 @@ auto VDP::serialize(serializer& s) -> void {
s.integer(state.hdot);
s.integer(state.hcounter);
s.integer(state.vcounter);
s.integer(state.field);
}
auto VDP::DMA::serialize(serializer& s) -> void {
@@ -73,6 +75,19 @@ auto VDP::Background::serialize(serializer& s) -> void {
s.integer(output.priority);
}
auto VDP::Object::serialize(serializer& s) -> void {
s.integer(x);
s.integer(y);
s.integer(tileWidth);
s.integer(tileHeight);
s.integer(horizontalFlip);
s.integer(verticalFlip);
s.integer(palette);
s.integer(priority);
s.integer(address);
s.integer(link);
}
auto VDP::Sprite::serialize(serializer& s) -> void {
s.integer(io.attributeAddress);
s.integer(io.nametableAddressBase);
@@ -80,8 +95,8 @@ auto VDP::Sprite::serialize(serializer& s) -> void {
s.integer(output.color);
s.integer(output.priority);
//todo: serialize oam
//todo: serialize objects
for(uint n : range(80)) oam[n].serialize(s);
for(uint n : range(20)) objects[n].serialize(s);
}
auto VDP::VRAM::serialize(serializer& s) -> void {

View File

@@ -1,3 +1,11 @@
auto VDP::Object::width() const -> uint {
return 1 + tileWidth << 3;
}
auto VDP::Object::height() const -> uint {
return 1 + tileHeight << 3 + (vdp.io.interlaceMode == 3);
}
auto VDP::Sprite::write(uint9 address, uint16 data) -> void {
if(address > 320) return;
@@ -5,19 +13,19 @@ auto VDP::Sprite::write(uint9 address, uint16 data) -> void {
switch(address.bits(0,1)) {
case 0: {
object.y = data.bits(0,8);
object.y = data.bits(0,9);
break;
}
case 1: {
object.link = data.bits(0,6);
object.height = 1 + data.bits(8,9) << 3;
object.width = 1 + data.bits(10,11) << 3;
object.tileHeight = data.bits(8,9);
object.tileWidth = data.bits(10,11);
break;
}
case 2: {
object.address = data.bits(0,10) << 4;
object.address = data.bits(0,10);
object.horizontalFlip = data.bit(11);
object.verticalFlip = data.bit(12);
object.palette = data.bits(13,14);
@@ -34,6 +42,10 @@ auto VDP::Sprite::write(uint9 address, uint16 data) -> void {
}
auto VDP::Sprite::scanline(uint y) -> void {
bool interlace = vdp.io.interlaceMode == 3;
y += 128;
if(interlace) y = y << 1 | vdp.state.field;
objects.reset();
uint7 link = 0;
@@ -43,46 +55,51 @@ auto VDP::Sprite::scanline(uint y) -> void {
auto& object = oam[link];
link = object.link;
if(128 + y < object.y) continue;
if(128 + y >= object.y + object.height) continue;
if(y < object.y) continue;
if(y >= object.y + object.height()) continue;
if(object.x == 0) break;
objects.append(object);
tiles += object.width >> 3;
tiles += object.width() >> 3;
} while(link && link < 80 && objects.size() < 20 && tiles < 40 && ++count < 80);
}
auto VDP::Sprite::run(uint x, uint y) -> void {
bool interlace = vdp.io.interlaceMode == 3;
x += 128;
y += 128;
if(interlace) y = y << 1 | vdp.state.field;
output.priority = 0;
output.color = 0;
for(auto& o : objects) {
if(128 + x < o.x) continue;
if(128 + x >= o.x + o.width) continue;
for(auto& object : objects) {
if(x < object.x) continue;
if(x >= object.x + object.width()) continue;
uint objectX = 128 + x - o.x;
uint objectY = 128 + y - o.y;
if(o.horizontalFlip) objectX = (o.width - 1) - objectX;
if(o.verticalFlip) objectY = (o.height - 1) - objectY;
uint objectX = x - object.x;
uint objectY = y - object.y;
if(object.horizontalFlip) objectX = (object.width() - 1) - objectX;
if(object.verticalFlip) objectY = (object.height() - 1) - objectY;
uint tileX = objectX >> 3;
uint tileY = objectY >> 3;
uint tileNumber = tileX * (o.height >> 3) + tileY;
uint15 tileAddress = o.address + (tileNumber << 4);
uint tileY = objectY >> 3 + interlace;
uint tileNumber = tileX * (object.height() >> 3 + interlace) + tileY;
uint15 tileAddress = object.address + tileNumber << 4 + interlace;
uint pixelX = objectX & 7;
uint pixelY = objectY & 7;
uint pixelY = objectY & 7 + interlace * 8;
tileAddress += pixelY << 1 | pixelX >> 2;
uint16 tileData = vdp.vram.read(tileAddress);
uint4 color = tileData >> (((pixelX & 3) ^ 3) << 2);
if(color) {
output.color = o.palette << 4 | color;
output.priority = o.priority;
break;
}
if(!color) continue;
output.color = object.palette << 4 | color;
output.priority = object.priority;
break;
}
}
auto VDP::Sprite::power() -> void {
memory::fill(&io, sizeof(IO));
io = {};
}

View File

@@ -23,11 +23,13 @@ auto VDP::main() -> void {
if(state.vcounter == 0) {
latch.horizontalInterruptCounter = io.horizontalInterruptCounter;
io.vblankIRQ = false;
cpu.lower(CPU::Interrupt::VerticalBlank);
}
if(state.vcounter == screenHeight()) {
if(io.verticalBlankInterruptEnable) {
io.vblankIRQ = true;
cpu.raise(CPU::Interrupt::VerticalBlank);
}
//todo: should only stay high for ~2573/2 clocks
@@ -37,6 +39,7 @@ auto VDP::main() -> void {
if(state.vcounter < screenHeight()) {
while(state.hcounter < 1280) {
run();
state.hdot++;
step(pixelWidth());
}
@@ -51,6 +54,15 @@ auto VDP::main() -> void {
} else {
step(1710);
}
state.hdot = 0;
state.hcounter = 0;
if(++state.vcounter >= frameHeight()) {
state.vcounter = 0;
state.field ^= 1;
latch.overscan = io.overscan;
}
latch.displayWidth = io.displayWidth;
}
auto VDP::step(uint clocks) -> void {
@@ -69,14 +81,20 @@ auto VDP::refresh() -> void {
Emulator::video.refresh(data, 1280 * sizeof(uint32), 1280, 480);
}
auto VDP::power() -> void {
auto VDP::power(bool reset) -> void {
create(VDP::Enter, system.frequency() / 2.0);
output = buffer + 16 * 1280; //overscan offset
memory::fill(&io, sizeof(IO));
memory::fill(&latch, sizeof(Latch));
memory::fill(&state, sizeof(State));
if(!reset) {
for(auto& data : vram.memory) data = 0;
for(auto& data : vsram.memory) data = 0;
for(auto& data : cram.memory) data = 0;
}
io = {};
latch = {};
state = {};
planeA.power();
window.power();

View File

@@ -6,7 +6,7 @@ struct VDP : Thread {
auto step(uint clocks) -> void;
auto refresh() -> void;
auto power() -> void;
auto power(bool reset) -> void;
//io.cpp
auto read(uint24 addr) -> uint16;
@@ -41,10 +41,17 @@ struct VDP : Thread {
} dma;
//render.cpp
auto frame() -> void;
auto scanline() -> void;
auto run() -> void;
auto outputPixel(uint9 color) -> void;
auto outputPixel(uint32 color) -> void;
struct Pixel {
inline auto above() const -> bool { return priority == 1 && color; }
inline auto below() const -> bool { return priority == 0 && color; }
uint6 color;
uint1 priority;
};
struct Background {
enum class ID : uint { PlaneA, Window, PlaneB } id;
@@ -53,7 +60,7 @@ struct VDP : Thread {
auto isWindowed(uint x, uint y) -> bool;
auto updateHorizontalScroll(uint y) -> void;
auto updateVerticalScroll(uint x, uint y) -> void;
auto updateVerticalScroll(uint x) -> void;
auto nametableAddress() -> uint15;
auto nametableWidth() -> uint;
@@ -89,15 +96,32 @@ struct VDP : Thread {
uint10 verticalScroll;
} state;
struct Output {
uint6 color;
uint1 priority;
} output;
Pixel output;
};
Background planeA{Background::ID::PlaneA};
Background window{Background::ID::Window};
Background planeB{Background::ID::PlaneB};
struct Object {
//sprite.cpp
inline auto width() const -> uint;
inline auto height() const -> uint;
//serialization.cpp
auto serialize(serializer&) -> void;
uint9 x;
uint10 y;
uint2 tileWidth;
uint2 tileHeight;
uint1 horizontalFlip;
uint1 verticalFlip;
uint2 palette;
uint1 priority;
uint11 address;
uint7 link;
};
struct Sprite {
//sprite.cpp
auto write(uint9 addr, uint16 data) -> void;
@@ -114,23 +138,7 @@ struct VDP : Thread {
uint1 nametableAddressBase;
} io;
struct Object {
uint9 x;
uint9 y;
uint width;
uint height;
bool horizontalFlip;
bool verticalFlip;
uint2 palette;
uint1 priority;
uint15 address;
uint7 link;
};
struct Output {
uint6 color;
uint1 priority;
} output;
Pixel output;
array<Object, 80> oam;
array<Object, 20> objects;
@@ -158,7 +166,6 @@ private:
//serialization.cpp
auto serialize(serializer&) -> void;
private:
uint16 memory[32768];
} vram;
@@ -171,7 +178,6 @@ private:
//serialization.cpp
auto serialize(serializer&) -> void;
private:
uint10 memory[40];
} vsram;
@@ -184,11 +190,13 @@ private:
//serialization.cpp
auto serialize(serializer&) -> void;
private:
uint9 memory[64];
} cram;
struct IO {
//status
uint1 vblankIRQ; //true after VIRQ triggers; cleared at start of next frame
//command
uint6 command;
uint16 address;
@@ -243,13 +251,16 @@ private:
struct State {
uint32* output = nullptr;
uint hdot;
uint hcounter;
uint vcounter;
uint16 hdot;
uint16 hcounter;
uint16 vcounter;
uint1 field;
} state;
uint32 buffer[1280 * 512];
uint32* output = nullptr;
friend class Interface;
};
extern VDP vdp;

View File

@@ -154,7 +154,7 @@ auto YM2612::step(uint clocks) -> void {
synchronize(apu);
}
auto YM2612::power() -> void {
auto YM2612::power(bool reset) -> void {
create(YM2612::Enter, system.frequency() / 7.0);
stream = Emulator::audio.createStream(2, frequency() / 144.0);
stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0);

View File

@@ -8,7 +8,7 @@ struct YM2612 : Thread {
auto sample() -> void;
auto step(uint clocks) -> void;
auto power() -> void;
auto power(bool reset) -> void;
//io.cpp
auto readStatus() -> uint8;

View File

@@ -17,7 +17,7 @@ auto Cartridge::load() -> bool {
}
if(Model::GameGear()) {
if(auto loaded = platform->load(ID::GameGear, "Game Gear", "gg")) {
if(auto loaded = platform->load(ID::GameGear, "Game Gear", "gg", {"NTSC"})) {
information.pathID = loaded.pathID();
} else return false;
}

View File

@@ -21,8 +21,15 @@ GameGearInterface::GameGearInterface() {
ports.append(move(hardware));
}
auto GameGearInterface::videoResolution() -> VideoResolution {
return {160, 144, 160, 144, 1.0};
auto GameGearInterface::videoInformation() -> VideoInformation {
VideoInformation vi;
vi.width = 160;
vi.height = 144;
vi.internalWidth = 160;
vi.internalHeight = 144;
vi.aspectCorrection = 1.0;
vi.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
return vi;
}
auto GameGearInterface::videoColors() -> uint32 {

View File

@@ -50,7 +50,7 @@ struct MasterSystemInterface : Interface {
MasterSystemInterface();
auto videoResolution() -> VideoResolution override;
auto videoInformation() -> VideoInformation override;
auto videoColors() -> uint32 override;
auto videoColor(uint32 color) -> uint64 override;
@@ -64,7 +64,7 @@ struct GameGearInterface : Interface {
GameGearInterface();
auto videoResolution() -> VideoResolution override;
auto videoInformation() -> VideoInformation override;
auto videoColors() -> uint32 override;
auto videoColor(uint32 color) -> uint64 override;

View File

@@ -36,8 +36,16 @@ MasterSystemInterface::MasterSystemInterface() {
ports.append(move(hardware));
}
auto MasterSystemInterface::videoResolution() -> VideoResolution {
return {256, 240, 256, 240, 8.0 / 7.0};
auto MasterSystemInterface::videoInformation() -> VideoInformation {
VideoInformation vi;
vi.width = 256;
vi.height = 240;
vi.internalWidth = 256;
vi.internalHeight = 240;
vi.aspectCorrection = 8.0 / 7.0;
if(Region::NTSC()) vi.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
if(Region::PAL()) vi.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
return vi;
}
auto MasterSystemInterface::videoColors() -> uint32 {

View File

@@ -48,6 +48,8 @@ auto VDP::Background::run() -> void {
output.color.bit(1) = vdp.vram[patternAddress + 1].bit(index);
output.color.bit(2) = vdp.vram[patternAddress + 2].bit(index);
output.color.bit(3) = vdp.vram[patternAddress + 3].bit(index);
if(output.color == 0) output.priority = 0;
}
auto VDP::Background::power() -> void {

View File

@@ -38,13 +38,14 @@ auto VDP::main() -> void {
sprite.run();
step(2);
uint12 color = palette(io.backdropColor);
if(background.output.color && (background.output.priority || !sprite.output.color)) {
color = palette(background.output.palette << 4 | background.output.color);
} else if(sprite.output.color) {
color = palette(16 | sprite.output.color);
uint12 color = palette(16 | io.backdropColor);
if(!io.leftClip || x >= 8) {
if(background.output.priority || !sprite.output.color) {
color = palette(background.output.palette << 4 | background.output.color);
} else if(sprite.output.color) {
color = palette(16 | sprite.output.color);
}
}
if(x <= 7 && io.leftClip) color = palette(io.backdropColor);
if(!io.displayEnable) color = 0;
*screen++ = color;
}

View File

@@ -39,8 +39,15 @@ auto Interface::title() -> string {
return cartridge.title();
}
auto Interface::videoResolution() -> VideoResolution {
return {280, 240, 1120, 240, 8.0 / 7.0};
auto Interface::videoInformation() -> VideoInformation {
VideoInformation vi;
vi.width = 280;
vi.height = 240;
vi.internalWidth = 1120;
vi.internalHeight = 240;
vi.aspectCorrection = 8.0 / 7.0;
vi.refreshRate = (system.colorburst() * 6.0) / (262.0 * 1365.0);
return vi;
}
auto Interface::videoColors() -> uint32 {

View File

@@ -23,7 +23,7 @@ struct Interface : Emulator::Interface {
auto manifest() -> string override;
auto title() -> string override;
auto videoResolution() -> VideoResolution override;
auto videoInformation() -> VideoInformation override;
auto videoColors() -> uint32 override;
auto videoColor(uint32 color) -> uint64 override;

View File

@@ -65,6 +65,13 @@ struct HuC6280 {
auto instructionAbsoluteWrite(uint8, uint8 = 0) -> void;
auto instructionBlockMove(bp) -> void;
auto instructionBranch(bool) -> void;
auto instructionBranchIfBitReset(uint3) -> void;
auto instructionBranchIfBitSet(uint3) -> void;
auto instructionBranchSubroutine() -> void;
auto instructionBreak() -> void;
auto instructionCallAbsolute() -> void;
auto instructionChangeSpeedLow() -> void;
auto instructionChangeSpeedHigh() -> void;
auto instructionClear(uint8&) -> void;
auto instructionClear(bool&) -> void;
auto instructionImmediate(fp, uint8&) -> void;
@@ -73,38 +80,30 @@ struct HuC6280 {
auto instructionIndirectWrite(uint8, uint8 = 0) -> void;
auto instructionIndirectYRead(fp, uint8&) -> void;
auto instructionIndirectYWrite(uint8) -> void;
auto instructionJumpAbsolute() -> void;
auto instructionJumpIndirect(uint8 = 0) -> void;
auto instructionMemory(fp) -> void;
auto instructionNoOperation() -> void;
auto instructionPull(uint8&) -> void;
auto instructionPullP() -> void;
auto instructionPush(uint8) -> void;
auto instructionResetMemoryBit(uint3) -> void;
auto instructionReturnInterrupt() -> void;
auto instructionReturnSubroutine() -> void;
auto instructionSet(bool&) -> void;
auto instructionSetMemoryBit(uint3) -> void;
auto instructionStoreImplied(uint2) -> void;
auto instructionSwap(uint8&, uint8&) -> void;
auto instructionTestAbsolute(uint8 = 0) -> void;
auto instructionTestZeroPage(uint8 = 0) -> void;
auto instructionTransfer(uint8&, uint8&) -> void;
auto instructionTransferAccumulatorToMPR() -> void;
auto instructionTransferMPRToAccumulator() -> void;
auto instructionTransferXS() -> void;
auto instructionZeroPageModify(fp, uint8 = 0) -> void;
auto instructionZeroPageRead(fp, uint8&, uint8 = 0) -> void;
auto instructionZeroPageWrite(uint8, uint8 = 0) -> void;
auto instructionBBR(uint3) -> void;
auto instructionBBS(uint3) -> void;
auto instructionBRK() -> void;
auto instructionBSR() -> void;
auto instructionCSL() -> void;
auto instructionCSH() -> void;
auto instructionJMPAbsolute() -> void;
auto instructionJMPIndirect(uint8 = 0) -> void;
auto instructionJSR() -> void;
auto instructionNOP() -> void;
auto instructionPLP() -> void;
auto instructionRMB(uint3) -> void;
auto instructionRTI() -> void;
auto instructionRTS() -> void;
auto instructionSMB(uint3) -> void;
auto instructionST(uint2) -> void;
auto instructionTAM() -> void;
auto instructionTMA() -> void;
auto instructionTSTAbsolute(uint8 = 0) -> void;
auto instructionTSTZeroPage(uint8 = 0) -> void;
auto instructionTXS() -> void;
//disassembler.cpp
auto disassemble(uint16 pc) -> string;

View File

@@ -28,118 +28,118 @@ auto HuC6280::instruction() -> void {
#define U
switch(code) {
op(0x00, BRK)
op(0x00, Break)
op(0x01, IndirectRead, fp(ORA), A, X)
op(0x02, Swap, X, Y)
op(0x03, ST, 0)
op(0x03, StoreImplied, 0)
op(0x04, ZeroPageModify, fp(TSB))
op(0x05, ZeroPageRead, fp(ORA), A)
op(0x06, ZeroPageModify, fp(ASL))
op(0x07, RMB, 0)
op(0x07, ResetMemoryBit, 0)
op(0x08, Push, P)
op(0x09, Immediate, fp(ORA), A)
op(0x0a, Implied, fp(ASL), A)
U op(0x0b, NOP)
U op(0x0b, NoOperation)
op(0x0c, AbsoluteModify, fp(TSB))
op(0x0d, AbsoluteRead, fp(ORA), A)
op(0x0e, AbsoluteModify, fp(ASL))
op(0x0f, BBR, 0)
op(0x0f, BranchIfBitReset, 0)
op(0x10, Branch, N == 0)
op(0x11, IndirectYRead, fp(ORA), A)
op(0x12, IndirectRead, fp(ORA), A)
op(0x13, ST, 1)
op(0x13, StoreImplied, 1)
op(0x14, ZeroPageModify, fp(TRB))
op(0x15, ZeroPageRead, fp(ORA), A, X)
op(0x16, ZeroPageModify, fp(ASL), X)
op(0x17, RMB, 1)
op(0x17, ResetMemoryBit, 1)
op(0x18, Clear, C)
op(0x19, AbsoluteRead, fp(ORA), A, Y)
op(0x1a, Implied, fp(INC), A)
U op(0x1b, NOP)
U op(0x1b, NoOperation)
op(0x1c, AbsoluteModify, fp(TRB))
op(0x1d, AbsoluteRead, fp(ORA), A, X)
op(0x1e, AbsoluteModify, fp(ASL), X)
op(0x1f, BBR, 1)
op(0x20, JSR)
op(0x1f, BranchIfBitReset, 1)
op(0x20, CallAbsolute)
op(0x21, IndirectRead, fp(AND), A, X)
op(0x22, Swap, A, X)
op(0x23, ST, 2)
op(0x23, StoreImplied, 2)
op(0x24, ZeroPageRead, fp(BIT), A)
op(0x25, ZeroPageRead, fp(AND), A)
op(0x26, ZeroPageModify, fp(ROL))
op(0x27, RMB, 2)
op(0x28, PLP)
op(0x27, ResetMemoryBit, 2)
op(0x28, PullP)
op(0x29, Immediate, fp(AND), A)
op(0x2a, Implied, fp(ROL), A)
U op(0x2b, NOP)
U op(0x2b, NoOperation)
op(0x2c, AbsoluteRead, fp(BIT), A)
op(0x2d, AbsoluteRead, fp(AND), A)
op(0x2e, AbsoluteModify, fp(ROL))
op(0x2f, BBR, 2)
op(0x2f, BranchIfBitReset, 2)
op(0x30, Branch, N == 1)
op(0x31, IndirectYRead, fp(AND), A)
op(0x32, IndirectRead, fp(AND), A)
U op(0x33, NOP)
U op(0x33, NoOperation)
op(0x34, ZeroPageRead, fp(BIT), A, X)
op(0x35, ZeroPageRead, fp(AND), A, X)
op(0x36, ZeroPageModify, fp(ROL), X)
op(0x37, RMB, 3)
op(0x37, ResetMemoryBit, 3)
op(0x38, Set, C)
op(0x39, AbsoluteRead, fp(AND), A, Y)
op(0x3a, Implied, fp(DEC), A)
U op(0x3b, NOP)
U op(0x3b, NoOperation)
op(0x3c, AbsoluteRead, fp(BIT), A, X)
op(0x3d, AbsoluteRead, fp(AND), A, X)
op(0x3e, AbsoluteModify, fp(ROL), X)
op(0x3f, BBR, 3)
op(0x40, RTI)
op(0x3f, BranchIfBitReset, 3)
op(0x40, ReturnInterrupt)
op(0x41, IndirectRead, fp(EOR), A, X)
op(0x42, Swap, A, Y)
op(0x43, TMA)
op(0x44, BSR)
op(0x43, TransferMPRToAccumulator)
op(0x44, BranchSubroutine)
op(0x45, ZeroPageRead, fp(EOR), A)
op(0x46, ZeroPageModify, fp(LSR))
op(0x47, RMB, 4)
op(0x47, ResetMemoryBit, 4)
op(0x48, Push, A)
op(0x49, Immediate, fp(EOR), A)
op(0x4a, Implied, fp(LSR), A)
U op(0x4b, NOP)
op(0x4c, JMPAbsolute)
U op(0x4b, NoOperation)
op(0x4c, JumpAbsolute)
op(0x4d, AbsoluteRead, fp(EOR), A)
op(0x4e, AbsoluteModify, fp(LSR))
op(0x4f, BBR, 4)
op(0x4f, BranchIfBitReset, 4)
op(0x50, Branch, V == 0)
op(0x51, IndirectYRead, fp(EOR), A)
op(0x52, IndirectRead, fp(EOR), A)
op(0x53, TAM)
op(0x54, CSL)
op(0x53, TransferAccumulatorToMPR)
op(0x54, ChangeSpeedLow)
op(0x55, ZeroPageRead, fp(EOR), A, X)
op(0x56, ZeroPageModify, fp(LSR), X)
op(0x57, RMB, 5)
op(0x57, ResetMemoryBit, 5)
op(0x58, Clear, I)
op(0x59, AbsoluteRead, fp(EOR), A, Y)
op(0x5a, Push, Y)
U op(0x5b, NOP)
U op(0x5c, NOP)
U op(0x5b, NoOperation)
U op(0x5c, NoOperation)
op(0x5d, AbsoluteRead, fp(EOR), A, X)
op(0x5e, AbsoluteModify, fp(LSR), X)
op(0x5f, BBR, 5)
op(0x60, RTS)
op(0x5f, BranchIfBitReset, 5)
op(0x60, ReturnSubroutine)
op(0x61, IndirectRead, fp(ADC), A, X)
op(0x62, Clear, A)
U op(0x63, NOP)
U op(0x63, NoOperation)
op(0x64, ZeroPageWrite, 0)
op(0x65, ZeroPageRead, fp(ADC), A)
op(0x66, ZeroPageModify, fp(ROR))
op(0x67, RMB, 6)
op(0x67, ResetMemoryBit, 6)
op(0x68, Pull, A)
op(0x69, Immediate, fp(ADC), A)
op(0x6a, Implied, fp(ROR), A)
U op(0x6b, NOP)
op(0x6c, JMPIndirect)
U op(0x6b, NoOperation)
op(0x6c, JumpIndirect)
op(0x6d, AbsoluteRead, fp(ADC), A)
op(0x6e, AbsoluteModify, fp(ROR))
op(0x6f, BBR, 6)
op(0x6f, BranchIfBitReset, 6)
op(0x70, Branch, V == 1)
op(0x71, IndirectYRead, fp(ADC), A)
op(0x72, IndirectRead, fp(ADC), A)
@@ -147,79 +147,79 @@ U op(0x6b, NOP)
op(0x74, ZeroPageWrite, 0, X)
op(0x75, ZeroPageRead, fp(ADC), A, X)
op(0x76, ZeroPageModify, fp(ROR), X)
op(0x77, RMB, 7)
op(0x77, ResetMemoryBit, 7)
op(0x78, Set, I)
op(0x79, AbsoluteRead, fp(ADC), A, Y)
op(0x7a, Pull, Y)
U op(0x7b, NOP)
op(0x7c, JMPIndirect, X)
U op(0x7b, NoOperation)
op(0x7c, JumpIndirect, X)
op(0x7d, AbsoluteRead, fp(ADC), A, X)
op(0x7e, AbsoluteModify, fp(ROR), X)
op(0x7f, BBR, 7)
op(0x7f, BranchIfBitReset, 7)
op(0x80, Branch, 1)
op(0x81, IndirectWrite, A, X)
op(0x82, Clear, X)
op(0x83, TSTZeroPage)
op(0x83, TestZeroPage)
op(0x84, ZeroPageWrite, Y)
op(0x85, ZeroPageWrite, A)
op(0x86, ZeroPageWrite, X)
op(0x87, SMB, 0)
op(0x87, SetMemoryBit, 0)
op(0x88, Implied, fp(DEC), Y)
op(0x89, Immediate, fp(BIT), A)
op(0x8a, Transfer, X, A)
U op(0x8b, NOP)
U op(0x8b, NoOperation)
op(0x8c, AbsoluteWrite, Y)
op(0x8d, AbsoluteWrite, A)
op(0x8e, AbsoluteWrite, X)
op(0x8f, BBS, 0)
op(0x8f, BranchIfBitSet, 0)
op(0x90, Branch, C == 0)
op(0x91, IndirectYWrite, A)
op(0x92, IndirectWrite, A)
op(0x93, TSTAbsolute)
op(0x93, TestAbsolute)
op(0x94, ZeroPageWrite, Y, X)
op(0x95, ZeroPageWrite, A, X)
op(0x96, ZeroPageWrite, X, Y)
op(0x97, SMB, 1)
op(0x97, SetMemoryBit, 1)
op(0x98, Transfer, Y, A)
op(0x99, AbsoluteWrite, A, Y)
op(0x9a, TXS)
U op(0x9b, NOP)
op(0x9a, TransferXS)
U op(0x9b, NoOperation)
op(0x9c, AbsoluteWrite, 0)
op(0x9d, AbsoluteWrite, A, X)
op(0x9e, AbsoluteWrite, 0, X)
op(0x9f, BBS, 1)
op(0x9f, BranchIfBitSet, 1)
op(0xa0, Immediate, fp(LD), Y)
op(0xa1, IndirectRead, fp(LD), A, X)
op(0xa2, Immediate, fp(LD), X)
op(0xa3, TSTZeroPage, X)
op(0xa3, TestZeroPage, X)
op(0xa4, ZeroPageRead, fp(LD), Y)
op(0xa5, ZeroPageRead, fp(LD), A)
op(0xa6, ZeroPageRead, fp(LD), X)
op(0xa7, SMB, 2)
op(0xa7, SetMemoryBit, 2)
op(0xa8, Transfer, A, Y)
op(0xa9, Immediate, fp(LD), A)
op(0xaa, Transfer, A, X)
U op(0xab, NOP)
U op(0xab, NoOperation)
op(0xac, AbsoluteRead, fp(LD), Y)
op(0xad, AbsoluteRead, fp(LD), A)
op(0xae, AbsoluteRead, fp(LD), X)
op(0xaf, BBS, 2)
op(0xaf, BranchIfBitSet, 2)
op(0xb0, Branch, C == 1)
op(0xb1, IndirectYRead, fp(LD), A)
op(0xb2, IndirectRead, fp(LD), A)
op(0xb3, TSTAbsolute, X)
op(0xb3, TestAbsolute, X)
op(0xb4, ZeroPageRead, fp(LD), Y, X)
op(0xb5, ZeroPageRead, fp(LD), A, X)
op(0xb6, ZeroPageRead, fp(LD), X, Y)
op(0xb7, SMB, 3)
op(0xb7, SetMemoryBit, 3)
op(0xb8, Clear, V)
op(0xb9, AbsoluteRead, fp(LD), A, Y)
op(0xba, Transfer, S, X)
U op(0xbb, NOP)
U op(0xbb, NoOperation)
op(0xbc, AbsoluteRead, fp(LD), Y, X)
op(0xbd, AbsoluteRead, fp(LD), A, X)
op(0xbe, AbsoluteRead, fp(LD), X, Y)
op(0xbf, BBS, 3)
op(0xbf, BranchIfBitSet, 3)
op(0xc0, Immediate, fp(CPY), Y)
op(0xc1, IndirectRead, fp(CMP), A, X)
op(0xc2, Clear, Y)
@@ -227,47 +227,47 @@ U op(0xbb, NOP)
op(0xc4, ZeroPageRead, fp(CPY), Y)
op(0xc5, ZeroPageRead, fp(CMP), A)
op(0xc6, ZeroPageModify, fp(DEC))
op(0xc7, SMB, 4)
op(0xc7, SetMemoryBit, 4)
op(0xc8, Implied, fp(INC), Y)
op(0xc9, Immediate, fp(CMP), A)
op(0xca, Implied, fp(DEC), X)
U op(0xcb, NOP)
U op(0xcb, NoOperation)
op(0xcc, AbsoluteRead, fp(CPY), Y)
op(0xcd, AbsoluteRead, fp(CMP), A)
op(0xce, AbsoluteModify, fp(DEC))
op(0xcf, BBS, 4)
op(0xcf, BranchIfBitSet, 4)
op(0xd0, Branch, Z == 0)
op(0xd1, IndirectYRead, fp(CMP), A)
op(0xd2, IndirectRead, fp(CMP), A)
op(0xd3, BlockMove, fp(TIN))
op(0xd4, CSH)
op(0xd4, ChangeSpeedHigh)
op(0xd5, ZeroPageRead, fp(CMP), A, X)
op(0xd6, ZeroPageModify, fp(DEC), X)
op(0xd7, SMB, 5)
op(0xd7, SetMemoryBit, 5)
op(0xd8, Clear, D)
op(0xd9, AbsoluteRead, fp(CMP), A, Y)
op(0xda, Push, X)
U op(0xdb, NOP)
U op(0xdc, NOP)
U op(0xdb, NoOperation)
U op(0xdc, NoOperation)
op(0xdd, AbsoluteRead, fp(CMP), A, X)
op(0xde, AbsoluteModify, fp(DEC), X)
op(0xdf, BBS, 5)
op(0xdf, BranchIfBitSet, 5)
op(0xe0, Immediate, fp(CPX), X)
op(0xe1, IndirectRead, fp(SBC), A, X)
U op(0xe2, NOP)
U op(0xe2, NoOperation)
op(0xe3, BlockMove, fp(TIA))
op(0xe4, ZeroPageRead, fp(CPX), X)
op(0xe5, ZeroPageRead, fp(SBC), A)
op(0xe6, ZeroPageModify, fp(INC))
op(0xe7, SMB, 6)
op(0xe7, SetMemoryBit, 6)
op(0xe8, Implied, fp(INC), X)
op(0xe9, Immediate, fp(SBC), A)
op(0xea, NOP)
U op(0xeb, NOP)
op(0xea, NoOperation)
U op(0xeb, NoOperation)
op(0xec, AbsoluteRead, fp(CPX), X)
op(0xed, AbsoluteRead, fp(SBC), A)
op(0xee, AbsoluteModify, fp(INC))
op(0xef, BBS, 6)
op(0xef, BranchIfBitSet, 6)
op(0xf0, Branch, Z == 1)
op(0xf1, IndirectYRead, fp(SBC), A)
op(0xf2, IndirectRead, fp(SBC), A)
@@ -275,15 +275,15 @@ U op(0xeb, NOP)
op(0xf4, Set, T)
op(0xf5, ZeroPageRead, fp(SBC), A, X)
op(0xf6, ZeroPageModify, fp(INC), X)
op(0xf7, SMB, 7)
op(0xf7, SetMemoryBit, 7)
op(0xf8, Set, D)
op(0xf9, AbsoluteRead, fp(SBC), A, Y)
op(0xfa, Pull, X)
U op(0xfb, NOP)
U op(0xfc, NOP)
U op(0xfb, NoOperation)
U op(0xfc, NoOperation)
op(0xfd, AbsoluteRead, fp(SBC), A, X)
op(0xfe, AbsoluteModify, fp(INC), X)
op(0xff, BBS, 7)
op(0xff, BranchIfBitSet, 7)
}
#undef U
}

View File

@@ -62,6 +62,72 @@ auto HuC6280::instructionBranch(bool take) -> void {
}
}
auto HuC6280::instructionBranchIfBitReset(uint3 index) -> void {
auto zeropage = operand();
auto displacement = operand();
io();
io();
L auto data = load8(zeropage);
if(data.bit(index) == 0) {
PC += (int8)displacement;
}
}
auto HuC6280::instructionBranchIfBitSet(uint3 index) -> void {
auto zeropage = operand();
auto displacement = operand();
io();
io();
L auto data = load8(zeropage);
if(data.bit(index) == 1) {
PC += (int8)displacement;
}
}
auto HuC6280::instructionBranchSubroutine() -> void {
auto displacement = operand();
io();
io();
io();
io();
push((PC - 1) >> 8);
L push((PC - 1) >> 0);
PC += (int8)displacement;
}
auto HuC6280::instructionBreak() -> void {
operand();
io();
push(PC >> 8);
push(PC >> 0);
uint8 p = P;
push(p | 0x10); //B flag set on push
D = 0;
I = 1;
PC.byte(0) = load16(0xfff6);
L PC.byte(1) = load16(0xfff7);
}
auto HuC6280::instructionCallAbsolute() -> void {
uint16 address = operand();
address |= operand() << 8;
io();
io();
push((PC - 1) >> 8);
L push((PC - 1) >> 0);
PC = address;
}
auto HuC6280::instructionChangeSpeedLow() -> void {
L io();
r.cs = 4;
}
auto HuC6280::instructionChangeSpeedHigh() -> void {
L io();
r.cs = 1;
}
auto HuC6280::instructionClear(uint8& data) -> void {
L io();
data = 0;
@@ -115,6 +181,22 @@ auto HuC6280::instructionIndirectYWrite(uint8 data) -> void {
L store16(absolute + Y, data);
}
auto HuC6280::instructionJumpAbsolute() -> void {
uint16 address = operand();
address |= operand() << 8;
L io();
PC = address;
}
auto HuC6280::instructionJumpIndirect(uint8 index) -> void {
uint16 address = operand();
address |= operand() << 8;
io();
io();
PC.byte(0) = load16(address + index + 0);
L PC.byte(1) = load16(address + index + 1);
}
auto HuC6280::instructionMemory(fp alu) -> void {
auto a = A;
A = ALU(load8(X));
@@ -122,6 +204,10 @@ L store8(X, A);
A = a;
}
auto HuC6280::instructionNoOperation() -> void {
L io();
}
auto HuC6280::instructionPull(uint8& data) -> void {
io();
io();
@@ -130,22 +216,99 @@ L data = pull();
N = data.bit(7);
}
auto HuC6280::instructionPullP() -> void {
io();
io();
L P = pull();
}
auto HuC6280::instructionPush(uint8 data) -> void {
io();
L push(data);
}
auto HuC6280::instructionResetMemoryBit(uint3 index) -> void {
auto zeropage = operand();
io();
io();
io();
auto data = load8(zeropage);
data.bit(index) = 0;
L store8(zeropage, data);
}
auto HuC6280::instructionReturnInterrupt() -> void {
io();
io();
io();
P = pull();
PC.byte(0) = pull();
L PC.byte(1) = pull();
}
auto HuC6280::instructionReturnSubroutine() -> void {
io();
io();
io();
PC.byte(0) = pull();
PC.byte(1) = pull();
L io();
PC++;
}
auto HuC6280::instructionSet(bool& flag) -> void {
L io();
flag = 1;
}
auto HuC6280::instructionSetMemoryBit(uint3 index) -> void {
auto zeropage = operand();
io();
io();
io();
auto data = load8(zeropage);
data.bit(index) = 1;
L store8(zeropage, data);
}
auto HuC6280::instructionStoreImplied(uint2 index) -> void {
auto data = operand();
io();
io();
L store(index, data);
}
auto HuC6280::instructionSwap(uint8& lhs, uint8& rhs) -> void {
io();
L io();
swap(lhs, rhs);
}
auto HuC6280::instructionTestAbsolute(uint8 index) -> void {
auto mask = operand();
uint16 absolute = operand();
absolute |= operand() << 8;
io();
io();
io();
L uint8 data = load16(absolute + index);
Z = (data & mask) == 0;
V = data.bit(6);
N = data.bit(7);
}
auto HuC6280::instructionTestZeroPage(uint8 index) -> void {
auto mask = operand();
auto zeropage = operand();
io();
io();
io();
L uint8 data = load8(zeropage + index);
Z = (data & mask) == 0;
V = data.bit(6);
N = data.bit(7);
}
auto HuC6280::instructionTransfer(uint8& source, uint8& target) -> void {
L io();
target = source;
@@ -153,6 +316,30 @@ L io();
N = target.bit(7);
}
auto HuC6280::instructionTransferAccumulatorToMPR() -> void {
auto mask = operand();
io();
io();
L io();
for(uint index : range(8)) {
if(mask.bit(index)) r.mpr[index] = A;
}
}
auto HuC6280::instructionTransferMPRToAccumulator() -> void {
auto mask = operand();
io();
L io();
for(uint index : range(8)) {
if(mask.bit(index)) { A = r.mpr[index]; break; }
}
}
auto HuC6280::instructionTransferXS() -> void {
L io();
S = X;
}
auto HuC6280::instructionZeroPageModify(fp alu, uint8 index) -> void {
auto zeropage = operand();
io();
@@ -172,192 +359,3 @@ auto HuC6280::instructionZeroPageWrite(uint8 data, uint8 index) -> void {
io();
L store8(zeropage + index, data);
}
//
auto HuC6280::instructionBBR(uint3 index) -> void {
auto zeropage = operand();
auto displacement = operand();
io();
io();
L auto data = load8(zeropage);
if(data.bit(index) == 0) {
PC += (int8)displacement;
}
}
auto HuC6280::instructionBBS(uint3 index) -> void {
auto zeropage = operand();
auto displacement = operand();
io();
io();
L auto data = load8(zeropage);
if(data.bit(index) == 1) {
PC += (int8)displacement;
}
}
auto HuC6280::instructionBRK() -> void {
operand();
io();
push(PC >> 8);
push(PC >> 0);
uint8 p = P;
push(p | 0x10); //B flag set on push
D = 0;
I = 1;
PC.byte(0) = load16(0xfff6);
L PC.byte(1) = load16(0xfff7);
}
auto HuC6280::instructionBSR() -> void {
auto displacement = operand();
io();
io();
io();
io();
push((PC - 1) >> 8);
L push((PC - 1) >> 0);
PC += (int8)displacement;
}
auto HuC6280::instructionCSL() -> void {
L io();
r.cs = 4;
}
auto HuC6280::instructionCSH() -> void {
L io();
r.cs = 1;
}
auto HuC6280::instructionJMPAbsolute() -> void {
uint16 address = operand();
address |= operand() << 8;
L io();
PC = address;
}
auto HuC6280::instructionJMPIndirect(uint8 index) -> void {
uint16 address = operand();
address |= operand() << 8;
io();
io();
PC.byte(0) = load16(address + index + 0);
L PC.byte(1) = load16(address + index + 1);
}
auto HuC6280::instructionJSR() -> void {
uint16 address = operand();
address |= operand() << 8;
io();
io();
push((PC - 1) >> 8);
L push((PC - 1) >> 0);
PC = address;
}
auto HuC6280::instructionNOP() -> void {
L io();
}
auto HuC6280::instructionPLP() -> void {
io();
io();
L P = pull();
}
auto HuC6280::instructionRMB(uint3 index) -> void {
auto zeropage = operand();
io();
io();
io();
auto data = load8(zeropage);
data.bit(index) = 0;
L store8(zeropage, data);
}
auto HuC6280::instructionRTI() -> void {
io();
io();
io();
P = pull();
PC.byte(0) = pull();
L PC.byte(1) = pull();
}
auto HuC6280::instructionRTS() -> void {
io();
io();
io();
PC.byte(0) = pull();
PC.byte(1) = pull();
L io();
PC++;
}
auto HuC6280::instructionSMB(uint3 index) -> void {
auto zeropage = operand();
io();
io();
io();
auto data = load8(zeropage);
data.bit(index) = 1;
L store8(zeropage, data);
}
auto HuC6280::instructionST(uint2 index) -> void {
auto data = operand();
io();
io();
L store(index, data);
}
auto HuC6280::instructionTAM() -> void {
auto mask = operand();
io();
io();
L io();
for(uint index : range(8)) {
if(mask.bit(index)) r.mpr[index] = A;
}
}
auto HuC6280::instructionTMA() -> void {
auto mask = operand();
io();
L io();
for(uint index : range(8)) {
if(mask.bit(index)) { A = r.mpr[index]; break; }
}
}
auto HuC6280::instructionTSTAbsolute(uint8 index) -> void {
auto mask = operand();
uint16 absolute = operand();
absolute |= operand() << 8;
io();
io();
io();
L uint8 data = load16(absolute + index);
Z = (data & mask) == 0;
V = data.bit(6);
N = data.bit(7);
}
auto HuC6280::instructionTSTZeroPage(uint8 index) -> void {
auto mask = operand();
auto zeropage = operand();
io();
io();
io();
L uint8 data = load8(zeropage + index);
Z = (data & mask) == 0;
V = data.bit(6);
N = data.bit(7);
}
auto HuC6280::instructionTXS() -> void {
L io();
S = X;
}

View File

@@ -43,6 +43,8 @@ template<uint Size> auto M68K::_immediate() -> string {
}
template<uint Size> auto M68K::_address(EffectiveAddress& ea) -> string {
if(ea.mode == 7) return {"$", hex((int16)_readPC<Word>(), 6L)};
if(ea.mode == 8) return {"$", hex(_readPC<Long>(), 6L)};
if(ea.mode == 9) return {"$", hex(_pc + (int16)_readPC(), 6L)};
return "???";
}
@@ -291,7 +293,9 @@ template<uint Size> auto M68K::disassembleEXT(DataRegister with) -> string {
return {"ext", _suffix<Size>(), " ", _dataRegister(with)};
}
auto M68K::disassembleILLEGAL() -> string {
auto M68K::disassembleILLEGAL(uint16 code) -> string {
if(code.bits(12,15) == 0xa) return {"linea $", hex(code.bits(0,11), 3L)};
if(code.bits(12,15) == 0xf) return {"linef $", hex(code.bits(0,11), 3L)};
return {"illegal "};
}

View File

@@ -68,7 +68,7 @@ template<uint Size> auto M68K::fetch(EffectiveAddress& ea) -> uint32 {
return 0;
}
template<uint Size, bool Hold> auto M68K::read(EffectiveAddress& ea) -> uint32 {
template<uint Size, bool hold> auto M68K::read(EffectiveAddress& ea) -> uint32 {
ea.address = fetch<Size>(ea);
switch(ea.mode) {
@@ -86,14 +86,16 @@ template<uint Size, bool Hold> auto M68K::read(EffectiveAddress& ea) -> uint32 {
}
case AddressRegisterIndirectWithPostIncrement: {
auto address = ea.address + (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
auto data = read<Size>(ea.address);
if(!Hold) write(AddressRegister{ea.reg}, ea.address += bytes<Size>());
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
return data;
}
case AddressRegisterIndirectWithPreDecrement: {
auto data = read<Size>(ea.address - bytes<Size>());
if(!Hold) write(AddressRegister{ea.reg}, ea.address -= bytes<Size>());
auto address = ea.address - (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
auto data = read<Size>(address);
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
return data;
}
@@ -130,7 +132,7 @@ template<uint Size, bool Hold> auto M68K::read(EffectiveAddress& ea) -> uint32 {
return 0;
}
template<uint Size, bool Hold> auto M68K::write(EffectiveAddress& ea, uint32 data) -> void {
template<uint Size, bool hold> auto M68K::write(EffectiveAddress& ea, uint32 data) -> void {
ea.address = fetch<Size>(ea);
switch(ea.mode) {
@@ -148,14 +150,16 @@ template<uint Size, bool Hold> auto M68K::write(EffectiveAddress& ea, uint32 dat
}
case AddressRegisterIndirectWithPostIncrement: {
auto address = ea.address + (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
write<Size>(ea.address, data);
if(!Hold) write(AddressRegister{ea.reg}, ea.address += bytes<Size>());
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
return;
}
case AddressRegisterIndirectWithPreDecrement: {
write<Size, Reverse>(ea.address - bytes<Size>(), data);
if(!Hold) write(AddressRegister{ea.reg}, ea.address -= bytes<Size>());
auto address = ea.address - (ea.reg == 7 && Size == Byte ? bytes<Word>() : bytes<Size>());
write<Size, Reverse>(address, data);
if(!hold) write(AddressRegister{ea.reg}, ea.address = address);
return;
}

View File

@@ -538,7 +538,7 @@ M68K::M68K() {
//ILLEGAL
{ auto opcode = pattern("0100 1010 1111 1100");
bind(opcode, ILLEGAL);
bind(opcode, ILLEGAL, opcode);
}
//JMP
@@ -1257,7 +1257,7 @@ M68K::M68K() {
//ILLEGAL
for(uint16 opcode : range(65536)) {
if(instructionTable[opcode]) continue;
bind(opcode, ILLEGAL);
bind(opcode, ILLEGAL, opcode);
}
#undef bind

View File

@@ -79,13 +79,13 @@ auto M68K::instructionABCD(EffectiveAddress with, EffectiveAddress from) -> void
r.x = r.c;
}
template<uint Size, bool Extend> auto M68K::ADD(uint32 source, uint32 target) -> uint32 {
template<uint Size, bool extend> auto M68K::ADD(uint32 source, uint32 target) -> uint32 {
auto result = (uint64)source + target;
if(Extend) result += r.x;
if(extend) result += r.x;
r.c = sign<Size>(result >> 1) < 0;
r.v = sign<Size>(~(target ^ source) & (target ^ result)) < 0;
r.z = clip<Size>(result) ? 0 : (Extend ? r.z : 1);
r.z = clip<Size>(result) ? 0 : (extend ? r.z : 1);
r.n = sign<Size>(result) < 0;
r.x = r.c;
@@ -521,10 +521,10 @@ template<> auto M68K::instructionEXT<Long>(DataRegister with) -> void {
r.n = sign<Long>(result) < 0;
}
auto M68K::instructionILLEGAL() -> void {
auto M68K::instructionILLEGAL(uint16 code) -> void {
r.pc -= 2;
if(opcode >> 12 == 0xa) return exception(Exception::Illegal, Vector::IllegalLineA);
if(opcode >> 12 == 0xf) return exception(Exception::Illegal, Vector::IllegalLineF);
if(code.bits(12,15) == 0xa) return exception(Exception::Illegal, Vector::IllegalLineA);
if(code.bits(12,15) == 0xf) return exception(Exception::Illegal, Vector::IllegalLineF);
return exception(Exception::Illegal, Vector::Illegal);
}
@@ -1059,13 +1059,13 @@ auto M68K::instructionSTOP() -> void {
r.stop = true;
}
template<uint Size, bool Extend> auto M68K::SUB(uint32 source, uint32 target) -> uint32 {
template<uint Size, bool extend> auto M68K::SUB(uint32 source, uint32 target) -> uint32 {
auto result = (uint64)target - source;
if(Extend) result -= r.x;
if(extend) result -= r.x;
r.c = sign<Size>(result >> 1) < 0;
r.v = sign<Size>((target ^ source) & (target ^ result)) < 0;
r.z = clip<Size>(result) ? 0 : (Extend ? r.z : 1);
r.z = clip<Size>(result) ? 0 : (extend ? r.z : 1);
r.n = sign<Size>(result) < 0;
r.x = r.c;

View File

@@ -45,10 +45,12 @@ auto M68K::exception(uint exception, uint vector, uint priority) -> void {
auto pc = r.pc;
auto sr = readSR();
if(!r.s) swap(r.a[7], r.sp);
r.i = priority;
r.s = 1;
r.t = 0;
if(exception != Exception::Illegal) {
if(!r.s) swap(r.a[7], r.sp);
r.i = priority;
r.s = 1;
r.t = 0;
}
push<Long>(pc);
push<Word>(sr);

View File

@@ -102,8 +102,8 @@ struct M68K {
};
template<uint Size> auto fetch(EffectiveAddress& ea) -> uint32;
template<uint Size, bool Hold = 0> auto read(EffectiveAddress& ea) -> uint32;
template<uint Size, bool Hold = 0> auto write(EffectiveAddress& ea, uint32 data) -> void;
template<uint Size, bool hold = 0> auto read(EffectiveAddress& ea) -> uint32;
template<uint Size, bool hold = 0> auto write(EffectiveAddress& ea, uint32 data) -> void;
//instruction.cpp
auto instruction() -> void;
@@ -120,7 +120,7 @@ struct M68K {
template<uint Size> auto sign(uint32 data) -> int32;
auto instructionABCD(EffectiveAddress with, EffectiveAddress from) -> void;
template<uint Size, bool Extend = false> auto ADD(uint32 source, uint32 target) -> uint32;
template<uint Size, bool extend = false> auto ADD(uint32 source, uint32 target) -> uint32;
template<uint Size> auto instructionADD(EffectiveAddress from, DataRegister with) -> void;
template<uint Size> auto instructionADD(DataRegister from, EffectiveAddress with) -> void;
template<uint Size> auto instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void;
@@ -171,7 +171,7 @@ struct M68K {
auto instructionEXG(AddressRegister x, AddressRegister y) -> void;
auto instructionEXG(DataRegister x, AddressRegister y) -> void;
template<uint Size> auto instructionEXT(DataRegister with) -> void;
auto instructionILLEGAL() -> void;
auto instructionILLEGAL(uint16 code) -> void;
auto instructionJMP(EffectiveAddress target) -> void;
auto instructionJSR(EffectiveAddress target) -> void;
auto instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void;
@@ -233,7 +233,7 @@ struct M68K {
auto instructionSBCD(EffectiveAddress with, EffectiveAddress from) -> void;
auto instructionSCC(uint4 condition, EffectiveAddress to) -> void;
auto instructionSTOP() -> void;
template<uint Size, bool Extend = false> auto SUB(uint32 source, uint32 target) -> uint32;
template<uint Size, bool extend = false> auto SUB(uint32 source, uint32 target) -> uint32;
template<uint Size> auto instructionSUB(EffectiveAddress source, DataRegister target) -> void;
template<uint Size> auto instructionSUB(DataRegister source, EffectiveAddress target) -> void;
template<uint Size> auto instructionSUBA(AddressRegister to, EffectiveAddress from) -> void;
@@ -326,7 +326,7 @@ private:
auto disassembleEXG(AddressRegister x, AddressRegister y) -> string;
auto disassembleEXG(DataRegister x, AddressRegister y) -> string;
template<uint Size> auto disassembleEXT(DataRegister with) -> string;
auto disassembleILLEGAL() -> string;
auto disassembleILLEGAL(uint16 code) -> string;
auto disassembleJMP(EffectiveAddress target) -> string;
auto disassembleJSR(EffectiveAddress target) -> string;
auto disassembleLEA(AddressRegister ar, EffectiveAddress ea) -> string;

View File

@@ -18,11 +18,11 @@ auto MOS6502::instruction() -> void {
auto code = opcode();
switch(code) {
op(0x00, BRK)
op(0x00, Break)
op(0x01, IndirectXRead, fp(ORA), A)
op(0x05, ZeroPageRead, fp(ORA), A)
op(0x06, ZeroPageModify, fp(ASL))
op(0x08, PHP)
op(0x08, PushP)
op(0x09, Immediate, fp(ORA), A)
op(0x0a, Implied, fp(ASL), A)
op(0x0d, AbsoluteRead, fp(ORA), A)
@@ -35,12 +35,12 @@ auto MOS6502::instruction() -> void {
op(0x19, AbsoluteRead, fp(ORA), A, Y)
op(0x1d, AbsoluteRead, fp(ORA), A, X)
op(0x1e, AbsoluteModify, fp(ASL), X)
op(0x20, JSRAbsolute)
op(0x20, CallAbsolute)
op(0x21, IndirectXRead, fp(AND), A)
op(0x24, ZeroPageRead, fp(BIT), A)
op(0x25, ZeroPageRead, fp(AND), A)
op(0x26, ZeroPageModify, fp(ROL))
op(0x28, PLP)
op(0x28, PullP)
op(0x29, Immediate, fp(AND), A)
op(0x2a, Implied, fp(ROL), A)
op(0x2c, AbsoluteRead, fp(BIT), A)
@@ -54,14 +54,14 @@ auto MOS6502::instruction() -> void {
op(0x39, AbsoluteRead, fp(AND), A, Y)
op(0x3d, AbsoluteRead, fp(AND), A, X)
op(0x3e, AbsoluteModify, fp(ROL), X)
op(0x40, RTI)
op(0x40, ReturnInterrupt)
op(0x41, IndirectXRead, fp(EOR), A)
op(0x45, ZeroPageRead, fp(EOR), A)
op(0x46, ZeroPageModify, fp(LSR))
op(0x48, Push, A)
op(0x49, Immediate, fp(EOR), A)
op(0x4a, Implied, fp(LSR), A)
op(0x4c, JMPAbsolute)
op(0x4c, JumpAbsolute)
op(0x4d, AbsoluteRead, fp(EOR), A)
op(0x4e, AbsoluteModify, fp(LSR))
op(0x50, Branch, V == 0)
@@ -72,14 +72,14 @@ auto MOS6502::instruction() -> void {
op(0x59, AbsoluteRead, fp(EOR), A, Y)
op(0x5d, AbsoluteRead, fp(EOR), A, X)
op(0x5e, AbsoluteModify, fp(LSR), X)
op(0x60, RTS)
op(0x60, ReturnSubroutine)
op(0x61, IndirectXRead, fp(ADC), A)
op(0x65, ZeroPageRead, fp(ADC), A)
op(0x66, ZeroPageModify, fp(ROR))
op(0x68, Pull, A)
op(0x69, Immediate, fp(ADC), A)
op(0x6a, Implied, fp(ROR), A)
op(0x6c, JMPIndirect)
op(0x6c, JumpIndirect)
op(0x6d, AbsoluteRead, fp(ADC), A)
op(0x6e, AbsoluteModify, fp(ROR))
op(0x70, Branch, V == 1)
@@ -157,7 +157,7 @@ auto MOS6502::instruction() -> void {
op(0xe6, ZeroPageModify, fp(INC))
op(0xe8, Implied, fp(INC), X)
op(0xe9, Immediate, fp(SBC), A)
op(0xea, NOP)
op(0xea, NoOperation)
op(0xec, AbsoluteRead, fp(CPX), X)
op(0xed, AbsoluteRead, fp(SBC), A)
op(0xee, AbsoluteModify, fp(INC))
@@ -172,7 +172,7 @@ auto MOS6502::instruction() -> void {
}
//unimplemented instruction
return instructionNOP();
return instructionNoOperation();
}
#undef op

View File

@@ -52,6 +52,28 @@ auto MOS6502::instructionBranch(bool take) -> void {
}
}
auto MOS6502::instructionBreak() -> void {
operand();
push(PCH);
push(PCL);
uint16 vector = 0xfffe;
nmi(vector);
push(P | 0x30);
I = 1;
PCL = read(vector++);
L PCH = read(vector++);
}
auto MOS6502::instructionCallAbsolute() -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
idle();
PC--;
push(PCH);
L push(PCL);
PC = absolute;
}
auto MOS6502::instructionClear(bool& flag) -> void {
L idle();
flag = 0;
@@ -98,6 +120,25 @@ auto MOS6502::instructionIndirectYWrite(uint8& data) -> void {
L write(absolute + Y, data);
}
auto MOS6502::instructionJumpAbsolute() -> void {
uint16 absolute = operand();
L absolute |= operand() << 8;
PC = absolute;
}
auto MOS6502::instructionJumpIndirect() -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
uint16 pc = read(absolute);
absolute.byte(0)++; //MOS6502: $00ff wraps here to $0000; not $0100
L pc |= read(absolute) << 8;
PC = pc;
}
auto MOS6502::instructionNoOperation() -> void {
L idle();
}
auto MOS6502::instructionPull(uint8& data) -> void {
idle();
idle();
@@ -106,11 +147,39 @@ L data = pull();
N = data.bit(7);
}
auto MOS6502::instructionPullP() -> void {
idle();
idle();
L P = pull();
}
auto MOS6502::instructionPush(uint8& data) -> void {
idle();
L push(data);
}
auto MOS6502::instructionPushP() -> void {
idle();
L push(P | 0x30);
}
auto MOS6502::instructionReturnInterrupt() -> void {
idle();
idle();
P = pull();
PCL = pull();
L PCH = pull();
}
auto MOS6502::instructionReturnSubroutine() -> void {
idle();
idle();
PCL = pull();
PCH = pull();
L idle();
PC++;
}
auto MOS6502::instructionSet(bool& flag) -> void {
L idle();
flag = 1;
@@ -160,74 +229,3 @@ auto MOS6502::instructionZeroPageWrite(uint8& data, uint8 index) -> void {
read(zeroPage);
L store(zeroPage + index, data);
}
//
auto MOS6502::instructionBRK() -> void {
operand();
push(PCH);
push(PCL);
uint16 vector = 0xfffe;
nmi(vector);
push(P | 0x30);
I = 1;
PCL = read(vector++);
L PCH = read(vector++);
}
auto MOS6502::instructionJMPAbsolute() -> void {
uint16 absolute = operand();
L absolute |= operand() << 8;
PC = absolute;
}
auto MOS6502::instructionJMPIndirect() -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
uint16 pc = read(absolute);
absolute.byte(0)++; //MOS6502: $00ff wraps here to $0000; not $0100
L pc |= read(absolute) << 8;
PC = pc;
}
auto MOS6502::instructionJSRAbsolute() -> void {
uint16 absolute = operand();
absolute |= operand() << 8;
idle();
PC--;
push(PCH);
L push(PCL);
PC = absolute;
}
auto MOS6502::instructionNOP() -> void {
L idle();
}
auto MOS6502::instructionPHP() -> void {
idle();
L push(P | 0x30);
}
auto MOS6502::instructionPLP() -> void {
idle();
idle();
L P = pull();
}
auto MOS6502::instructionRTI() -> void {
idle();
idle();
P = pull();
PCL = pull();
L PCH = pull();
}
auto MOS6502::instructionRTS() -> void {
idle();
idle();
PCL = pull();
PCH = pull();
L idle();
PC++;
}

Some files were not shown because too many files have changed in this diff Show More