Compare commits

...
749 Commits
Author SHA1 Message Date
Luke Usher 8e62cd8162 ares: bump version number to v133 2023-07-21 09:13:51 +01:00
Giovanni Bajo 8b45d04288 n64: correct implementation of out of bounds RDRAM reads and writes 2023-07-21 09:02:43 +01:00
NoxyMe c94c7a9b85 Added My vision Core 2023-07-20 19:22:50 +01:00
Luke Usher ee6a7fe78d desktop-ui: fix an issue where the game browser would crash the emulator if medium::create failed 2023-07-19 13:36:04 +01:00
Luke Usher d3a71803ed mame2bml: mame machine list uses hex without a prefix for offset 2023-07-19 13:36:04 +01:00
Luke Usher 1e5eed8f21 mia: fix indentation of loadRoms 2023-07-19 13:36:04 +01:00
Luke Usher 697b3b6503 mame2bml: add support for extracting databases from machine lists (mame --listxml) 2023-07-19 13:36:04 +01:00
Giovanni Bajo 7812cc1818 n64: implement accurate PI DMA timings
The previous formula was a decent approximation, but it looks like 6105
antipiracy protection requires a better one (in addition to better RSP
timings that already went in).

Fixes #129 (Jet Force Gemini and Mickey Speedway USA)
2023-07-19 13:31:48 +01:00
Luke Usher 499c964986 mia: split arcade rom loading from neo-geo.cpp into generic mame.cpp 2023-07-19 10:10:40 +01:00
Giovanni Bajo 49fac42e69 n64: remove debug printf 2023-07-18 17:54:28 +01:00
invertego 2b746cd26c n64: implement rsp su pipeline stalls
Implement pipeline stall conditions for the RSP's scalar unit (SU).
Tested against real hardware with a random instruction stream generator.

Vector unit (VU) timing, including dual issue with the SU, is not yet
implemented.
2023-07-18 16:47:13 +01:00
Luke Usher dafb57010c cli: support loading multiple roms at once and surpressing file dialogs 2023-07-17 20:26:06 +01:00
remutro cab7096e0f Update weave label text, address additional ways weave & supersampling could be manipulated 2023-07-17 09:46:26 +01:00
remutro a3d6392e1c actually disable supersampling setting, not just the control 2023-07-17 09:46:26 +01:00
remutro b4221bcaaf weave default true, disable supersampling when weave enabled 2023-07-17 09:46:26 +01:00
SpookyIluha feab2746da Add weave deinterlacing support to N64
When an interlaced output is made by the game, an N64 emulator right now only allows "Bob" deinterlacing, this commit also adds a "Weave" deinterlace option
2023-07-14 13:39:04 +01:00
Luke Usher eccd72d17f msx2: add some entries to game database 2023-07-14 10:55:18 +01:00
Luke Usher d3228ea52d msx2: minor background tweaks 2023-07-14 10:55:18 +01:00
remutro bff8a1413f Use nall print instead of printf, adjust message 2023-07-14 09:50:38 +01:00
remutro d6f216928c Don't silently fail loading a rom if it is too small 2023-07-14 09:50:38 +01:00
Luke Usher 92099bec6f msx: stub just enough of the RTC for MSX2 bios to boot, remove c-bios.
Implementation of RTC will be fleshed out further in the future.
2023-07-13 22:19:02 +01:00
Luke Usher 1b148ab9cb msx2: fix serialization of v9938 2023-07-13 22:15:42 +01:00
Luke Usher d3e7ced3b4 msx2: vscroll + text1 + graphics5 2023-07-13 22:14:52 +01:00
Luke Usher 9cf118a72f msx2: fix mode2 sprite rendering 2023-07-13 20:48:20 +01:00
Luke Usher cc81fd1015 hiro: use modern file browser dialog on Windows
This is supported on Vista+, meaning that Hiro no longer supports Windows XP
2023-06-29 13:14:16 +01:00
remutro da45ad792b Update GTK info and app terminal options 2023-06-29 12:00:33 +01:00
Luke Usher 8feff4afa3 build: default to gtk3 on linux
gtk2 is aging now and not available out of the box on many current distros
2023-06-29 11:30:25 +01:00
Alexandre Detiste 104e4bd66d make cross-building somewhat easier
part of this:
  https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=866070
2023-06-28 16:54:05 +01:00
Seth Junot 5f891de18a Fix: replace deprecated CGDisplayIOServicePort on macOS
This patch resolves a deprecation warning raised at compile time on macOS.
Note the replacement functions have been available since macOS 10.4.
2023-06-28 16:51:33 +01:00
invertego 83b43e8405 libchdr: redo fseeko/ftello fix 2023-06-27 10:31:12 +01:00
Luke Usher 682fc36ac7 spec: minor tweaks to TZXFile loading - fixed Jet Pac 2023-06-25 13:47:18 +01:00
noabody d7fd2ccba8 correct for case sensitive file system 2023-06-24 17:54:54 +01:00
Luke Usher 66e01e02cc spec: add support for .tap and .tzx format tapes
This uses code extracted from https://github.com/MrReeMachine/TzxTool
2023-06-23 18:27:01 +01:00
Luke Usher 76cf49834a msx: preliminary support for loading cassette tapes
like all of these computers, loading cassette tape games is awkward,
requiring the user to know what format data the tape contains.

The following basic commands are used to load cassette tapes:

Binary Data: `BLOAD"CAS:",R`
Tokenized Basic: `CLOAD`
ASCII `RUN"CAS:"`
2023-06-23 13:53:19 +01:00
Luke Usher f8f1729cbe n64: fix tlb after cache implementation 2023-06-23 12:28:34 +01:00
Luke Usher 181570e50d n64: add cache to speed up the lookup of the 4 most active pages 2023-06-23 12:28:34 +01:00
Luke Usher 878419da0e n64: avoid unnecessary pbase writes in devirtualizeFast and hint as alwaysinline 2023-06-23 12:28:33 +01:00
Luke Usher fbaf7d8118 n64: use devirtualizeFast for faster lookups of cached code blocks 2023-06-23 12:28:33 +01:00
Luke Usher 345a7cb89f n64: clear devirtualize cache on TLB changes rather than memory writes 2023-06-23 12:28:33 +01:00
Giovanni Bajo 2650062d70 n64: implement correct audio frequency for PAL consoles
Fixes #1120
2023-06-23 12:26:08 +01:00
Jeff Linahan 2b0c91e3c3 sfc: bank -> page 2023-06-23 12:16:56 +01:00
Jeff Linahan 15bb0e0593 sfc: noise linear feedback shift register state constructed with or not xor 2023-06-23 12:16:56 +01:00
Alexandre Detiste 2e472e8401 fix FTFBS with GCC-13
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1037580
2023-06-21 14:35:09 +01:00
Luke Usher 53af7cbbcc n64: mask pbase to fix incorrect offsets 2023-06-20 21:52:23 +01:00
Luke Usher bafa58534a ci: package ares-windows build 2023-06-20 09:05:17 +01:00
Luke Usher 495803ea63 n64: remove erroneous devirtualize cache writes in non-fast variant
This was causing data accesses to overwrite the cached recompiler block mapping
2023-06-19 22:07:29 +01:00
Luke Usher 7f09b67df9 n64: speed up recompiler icache lookup
This introduces a faster version of tlb.Load which omits exception and debug checks in
instructionEpilogue; as it is assumed these checks are handled sufficiently by the recompiler
instruction fetch phase before execution.

Additionally, this also introduces a simple cache that caches the virtual to physical mapping
for a single 4k page; this prevents per-instruction lookups within recompiled block; and is
cleared when the TLB is written to, so should never become stale.
2023-06-19 21:56:40 +01:00
Luke Usher 8ddd630850 build: default to ares-windows builds
These have tested as higher performance than other builds as of late
2023-06-19 21:53:30 +01:00
Luke Usher 5f9804fb65 n64: remove MAME RDP
It is too slow to be usable with the rest of ares,

Now that macOS can run Parallel-RDP with MoltenVK, there is little reason
to keep this around.

We can just say that Vulkan is *required* for the N64 core going forward.
2023-06-15 20:23:14 +01:00
Luke Usher e142c3be5a n64: slight performance boost by moving exit logic to components rather than system
This reduces the total number of function calls made in each loop of system->run()

n64: add fast variant of devirtualize; fix remaining task from PR #1069
2023-06-15 19:52:22 +01:00
Luke Usher 6e367916da n64: add fast variant of devirtualize; fix remaining task from PR #1069 2023-06-15 19:52:12 +01:00
Adrian Siekierka c4863ef672 v30mz: improve timing accuracy
Still not perfect, but a little closer here and there.
2023-06-11 09:45:26 +01:00
Luke Usher ad978f3daf mia: fix location of game database on posix systems 2023-06-02 20:12:09 +01:00
kev4cards fbdd42beb6 n64: add epsilon to axis values
prior to casting to s8
2023-06-01 10:42:16 +01:00
kev4cards a349770472 n64: change linear response
to scale according to cardinalMax, rename startCardinalMax and others for better clarity, and reformulate startCardinalMax based on new response equation.
2023-06-01 10:42:16 +01:00
Jeff Linahan 08c00d186a sfc: master volume -> main volume 2023-06-01 10:42:06 +01:00
Luke Usher 4c3786b067 a26: fix reset of tia audio for real this time 2023-05-25 10:23:27 +01:00
Luke Usher a8f3e353cd a26: fix reset of tia audio 2023-05-25 10:22:06 +01:00
Luke Usher 98dc6faefb a26: better vertical resolution handling 2023-05-25 10:19:14 +01:00
Luke Usher 41157ad555 thirdparty: fix build after libchdr update 2023-05-22 23:02:55 +01:00
Luke Usher 43cfbd629c Merge commit '3e9ce82ccbad370ac0da38a7cdf0e2f98b62239c' 2023-05-22 22:39:36 +01:00
Luke Usher 3e9ce82ccb Squashed 'thirdparty/libchdr/' changes from a20e04c12..54bfb871c
54bfb871c Merge pull request #99 from scribam/dr_libs
5cd76b97e Revert "deps: add dr_libs as a header-only library"
903f2f5cc Merge pull request #93 from scribam/deps
1ccead153 deps: add dr_libs as a header-only library
3c6e0e47a deps: add zlib-1.2.13
8e04476eb deps: remove zlib 1.2.11 and zlib 1.2.12
468490000 Merge pull request #97 from scribam/github-workflows
b2996c832 Add basic GitHub Actions
688759416 Merge pull request #96 from scribam/malloc
10c340c5a Check mem alloc failures triggered by invalid chd
37a5c0f3c Merge pull request #94 from scribam/auxv
026969b6d Merge pull request #95 from scribam/division
179f02553 Avoid division by zero
5f3927dc3 Declare hardware capabilities for the Nintendo Switch and PlayStation Vita
fec8ab942 Merge pull request #89 from jpd002/huff_codec
4ddae00e5 Merge pull request #91 from flyinghead/master
de740535f Avoid huffman tree buffer overrun in huffman_import_tree_rle
571507743 Add support for 'huff' codec.

git-subtree-dir: thirdparty/libchdr
git-subtree-split: 54bfb871ccae31903b95a8feb7f2bf7121f304be
2023-05-22 22:39:36 +01:00
Luke Usher 71d5a59c19 Merge commit '509d749663ed8811c3b0b6e32130833fb5ffff76' 2023-05-22 22:39:31 +01:00
Luke Usher 509d749663 Squashed 'thirdparty/sljit/' changes from 4f7d8ec54..51538f102
51538f102 documentation: refactor registers and function signatures (#169)
47ed75d0b Improve copy between float and general regs on x86-32
91798631a Fix uint to float conversion on x86, ppc, mips
6a8dc94e0 Implement unsigned to float conversion on ppc, mips
61736a11a Implement unsigned to float conversion on s390x
ec6d52516 Implement unsigned to float conversion on x86, arm, riscv
f368bb254 arm64: use MOV instead of ORR for readability (#166)
07a556181 arm64: implement atomics using CAS for CPUs with LSE (#164)
1a4d5f229 Improve atomic operation constraints (#165)
b7fed8e11 x86: correctly detect mode32 for atomic_store (#163)
a0e16b14f arm64: avoid undefined behaviour with signed shifts (#161)
7f2886127 Implement operations on s390x
c54325fee Improve atomic instructions
3499aba93 Set armv6 as the minimum arm version
53d5a2252 Implement set f32/f64 on x86, arm, riscv, ppc, mips
03bb5347f Improve atomic operations
b91921e24 Increase max stack to 1 Mbyte
af4ca5da5 Add atomic instructions (#157)
e37ec3253 macos: allow runtime detection if target is older than BigSur (#127)
5ed7e00a1 Remove functions for unsupported architecture
fa1881b57 Implement operations on s390x
cf5a17b77 Implement fselect operation on x86
e5c75cd73 Implement rev.u32 and rev.s32 on x86, arm, riscv, ppc, mips
d1f287bec Implement select, rev.u16 and rev.s16 on s390x
7efd60de8 Implement rev.u16 and rev.s16 on x86, arm, riscv, ppc, mips
63e307e4a Implement select operation on x86, arm, riscv, ppc, mips
3cc2b0fb2 Improve floating point comparison

git-subtree-dir: thirdparty/sljit
git-subtree-split: 51538f102dd342a6246e98acafc00ceebbab4618
2023-05-22 22:39:31 +01:00
Luke Usher bf9caa706c Merge commit '8bac0decbe7b265594b3589b1542766f69fae1ba' 2023-05-22 22:39:21 +01:00
Luke Usher 8bac0decbe Squashed 'ares/n64/vulkan/parallel-rdp/' changes from 3abd43776..8da2be35a
8da2be35a Update to d95cf9b09c31e1b239eb7e90255e048ffa184360.
141d253c4 Update to 85363ec733561ab545103888f440dec500cbb96a.
101d5a2bb Update to 7375ad2d83f744cf0236ad181f23b3d4b6903857.

git-subtree-dir: ares/n64/vulkan/parallel-rdp
git-subtree-split: 8da2be35abbbf503a485993c717e4917a1560324
2023-05-22 22:39:20 +01:00
Tim Allen 4e73783cc1 mia: Extend the Super Famicom LOROM-RAM#A memory map.
Although Nintendo made many different cartridge circuit boards with different
memory mappings, ROMs do not indicate which specific board they are intended
to work with. Super Famicom emulators traditionally group mutually-compatible
mappings together and use heuristics to guess which family of mappings the
game expects.

There's one family of mappings that maps ROM data to the top half ($8000-$FFFF)
of memory banks in the Super Famicom address space. For historical reasons,
this family is called "LoROM" and has three main variants:

1. ROM only, mapped to the top half of every possible bank.
   The boards database calls this "LOROM".
2. ROM mapped to the top half of every possible bank,
   RAM mapped to the bottom half of banks 70-7d,f0-ff.
   The boards database calls this "LOROM-RAM"
3. ROM mapped to the top half of low-numbered banks,
   RAM mapped to both halves of banks 70-7d,f0-ff.
   The boards database calls this "LOROM-RAM#A"

The largest official game that used variant 3 was 1MiB, so a common heuristic
is "if the ROM is 2MiB or less, use variant 3, otherwise use variant 2".
2MiB is used as the threshold instead of 1MiB, perhaps so somebody can expand a
commercial ROM that uses variant 3 without having to rework it to suit a
different mapping.

Since v107 or so, higan (and by extension, ares) has implemented variant 3 by
mapping ROM to banks 00-3f,80-bf, which exactly fits a 2MiB ROM. However,
other emulators like Mesen, snes9x and higan v106 implement it by mapping ROM
to banks 00-6f,80-ef, all the space that is left after the RAM is mapped.

This doesn't affect any verified games in the `Super Famicom.bml` database,
since those have specific, accurate memory maps. It also won't affect
well-written games that only read from memory addresses they have populated.
However, homebrew games and ROM hacks that have never existed on a real circuit
board depend on these heuristics across all devices that read Super Famicom
ROMs, including software emulators, flash-carts, and FPGA implementations, so
ares should match what other emulators do.
2023-05-22 13:20:10 +01:00
Tim Allen 257a6db658 Regenerate mia resources to include updated board data.
In commit 93e89446e2, the board database was
updated without mia's resource file being rebuilt.
2023-05-22 13:20:10 +01:00
aquova e02938c23f Add support for IPS patching
Adds support for patching ROMs on the fly with a corresponding IPS patch
file. Functions in a similar manner to the pre-existing BPS support. If
a *.ips file is found with the same name as the ROM, it attempts to
apply the patch. If both a BPS and IPS file are found, the BPS patch
takes priority. This patch implements the IPS format as described here:
https://zerosoft.zophar.net/ips.php
2023-05-21 14:19:49 +01:00
encoded-byte f0fe40d5da fc: slightly adjust fds output level
make clear where the magic number comes from
2023-05-12 15:39:27 +00:00
encoded-byte 990fd4e21c fc: fix fds sound pitch
modulator output needs to be updated after changing speed / gain
2023-05-12 15:39:27 +00:00
encoded-byte 6769031bfb fc: fix fds sound enable address 2023-05-12 15:39:27 +00:00
Luke Usher 013b4f2645 gb: stop instruction resets div to 0 2023-05-09 19:03:40 +01:00
Luke Usher 75821d404b gba: implement upper bounds for background fetch, fixes Monster Gate 2023-05-06 21:48:40 +01:00
invertego 0311d1ca56 libchdr: instruct glibc to declare fseeko/ftello 2023-05-05 06:14:25 +00:00
invertego 6a7898396a nall: add needed #include <stdexcept> 2023-05-03 07:15:06 +00:00
kev4cards a4dbeb45d1 n64: increase initial circle radius
to encircle octagon fully
2023-04-30 08:14:56 +00:00
sdebian d13715d8bb Adds fallback for situations where a single montior is detected but it is not
primary.
2023-04-29 21:51:06 +00:00
encoded-byte 03bfe5a3ab fc: support for mmc3 multicards 2023-04-25 15:59:07 +00:00
Luke Usher 9b32ef7faa pc-engine: don't hard code multitap, allow multitap selection
Note that this still has an issue where infinitely nesting multitaps
can cause ui issues, but it's functionally complete.
2023-04-24 10:58:00 +01:00
invertego c05d7b2070 pce: fix off-by-one error for scanline interrupts 2023-04-24 08:24:29 +00:00
Giovanni Bajo 239a902a77 n64: fix BADVADDR in TLB miss exception raised by SWR
SWL/SWR do not raise address errors (it's their whole reason of
being), but they can still raise TLB misses if they access an unmapped
memory area. In that case, the COP0 BADVADDR register is expected to
contain *exactly* the address passed to them.

This happened to be true (by luck) for SWL but not for SWR: SWR in fact
needs to write *before* the address passed to it, so the opcode itself
was adjusting the address before calling the memory function.

Fixed by passing the misaligned address to CPU::write and telling it
to skip address errors. It's not pretty: the code in CPU::write/read is
a bit of a mess and it would require some refactoring but that's for
another day.

Verified on real hardware by adding a new test to n64-systemtest, which
is has been submitted upstream (https://github.com/lemmy-64/n64-systemtest/pull/50).
2023-04-23 10:40:53 +00:00
Luke Usher b7da32113f chd: fix an incorrect assumption that the first track will always be data for game media 2023-04-21 21:57:21 +01:00
Luke Usher cbc3acada1 chd: fix an issue where mia would read from the start of a disc rather than the first data sector 2023-04-21 21:56:29 +01:00
TascoDLX 75e17ca213 m68000: fix instruction timings & cycle order 2023-04-17 06:38:44 +00:00
TascoDLX 0d376ddb24 m68000: fix privilege violation behavior 2023-04-17 06:38:44 +00:00
TascoDLX cff8b55310 z80: fix undocumented instructions & flags behavior 2023-04-17 06:38:44 +00:00
invertego acff6a93ad fc: support ave nina-03/06 boards 2023-04-15 13:27:22 +00:00
Luke Usher fdea53cad4 6502: fix nes/fc initial state/reset tests 2023-04-14 22:59:13 +01:00
Luke Usher ca03794534 sh2: make timers update at correct frequency with recompiler 2023-04-14 20:25:34 +01:00
Luke Usher 4c646c539e sh2: fix typo in WDT frequency table (2096 -> 4096) 2023-04-14 11:36:13 +01:00
invertego 7c74821b78 sh2: boost sync on pending interrupt
Interrupts are deferred when the CPU is in a branch delay slot. If the
recompiler repeatedly exits the code cache in a delay slot (much more
likely with "min cycles between syncs" optimization active) then
interrupts will be deferred indefinitely.

This is now avoided by resetting the "cycles until sync" count when
interrupts are deferred due to a branch delay slot.

An alternate and possibly more robust solution would be to single step
the next instruction with the interpreter. One side effect would be the
generation of more compiled blocks.
2023-04-13 07:39:52 +00:00
invertego 019ceea8d6 readme: mention lld requirement with clang 2023-04-10 07:50:14 +00:00
Luke Usher 33a406701e fc: implement submapper types for VRC2/VRC4; pass VRC2/4 test roms 2023-04-09 10:24:03 +01:00
Giovanni Bajo 9bfa1fe7ce n64: fix cache line selection
VR4300 icache/dcache use both the virtual address and the physical
address: the former one is used to select the cacheline (just like
the key to a hashtable), while the latter is used to check that the
cacheline contains the correct line of memory and not another one
that happens to have the same hash key.

So any access to the cache requires both addresses. This commit makes
this explicit, and make sure to call the functions correctly.

The only exception where we leave a FIXME is the icache.step call
in the recompiler, as we can't possibly devirtualize the PC for each
opcode. This will have to be fixed in another way.
2023-04-09 06:59:00 +00:00
invertego 21c24b31ad pce: prevent destruction of bram on non-CD load
With PC Engine, ares always emulates the presence of CD-ROM drive so
games can use its backup RAM for save data. However, it was not properly
loading the backup RAM file when loading a non-CD game, causing the file
to be subsequently filled with FFs on save.
2023-04-09 06:05:22 +00:00
invertego 98b3c8ef7b pce: fix bram size detection in BIOS
The BIOS format procedure detects the size of backup RAM by sweeping
bank $f7 while writing zero and reading back the result. It stops when
the read back value is nonzero, proving that the 2 KiB backup RAM is not
intended to be mirrored across the 8 KiB address range. With this
corrected in ares the BIOS writes the correct header indicating the end
of the backup RAM is at 0x8800 rather than 0xA000.
2023-04-09 06:05:22 +00:00
invertego f514327594 pce: zero bram when formatting
The BIOS format procedure does this and Rondo of Blood relies upon it.
2023-04-09 06:05:22 +00:00
minneyar 4c3b7b636f Add "Reset System" hotkey
This adds a hotkey that can be used to reset the active system.

Although this is similar to the existing "Reload Current Game" hotkey, it does have a functional difference, since a soft reset can result in the state of a system being slightly different than a cold boot.  It also does not result in resizing the emulator window and is slightly faster due to not needing to reload various resources.
2023-04-07 06:39:53 +00:00
TascoDLX 2c867d37e6 ng: bump serializer version for ym fix 2023-04-06 21:25:03 +00:00
TascoDLX 901cfd7e52 md: bump serializer version for ym2612 fix 2023-04-06 21:25:03 +00:00
TascoDLX 7565591cf8 ym2612: include crossover distortion 2023-04-06 21:25:03 +00:00
TascoDLX 6502327ad2 ym2612: delay operators due to pipelining 2023-04-06 21:25:03 +00:00
invertego d5cba61203 sh2: mirror cache control register 2023-04-03 09:34:15 +00:00
TascoDLX 3ae339ae14 sn76489: fix freq counters & output 2023-03-31 08:25:09 +00:00
Luke Usher 26d63dd04a desktop-ui: fix an issue where the game browser would sometimes load the wrong title 2023-03-30 13:30:07 +01:00
Luke Usher f9d54ebbb0 desktop-ui: add game browser for arcade roms
This makes arcade systems with strict rom requirements, such as neo geo much easier to manage
2023-03-30 13:25:47 +01:00
invertego 1508f6b488 nall: split main.cpp into separate translation unit
When using nall as a header-only library it was possible to opt out of
nall taking over main() by simply not including main.hpp. There was no
mechanism to opt out when building nall as a separate translation unit
because nall.cpp unconditionally pulled in main.cpp. Now, users of nall
must specifically opt in by including main.cpp in their build (though
header-only users still only need to include main.hpp).
2023-03-30 06:43:04 +00:00
invertego 146bc3764d sh2: fix hashing max size blocks 2023-03-30 06:42:10 +00:00
invertego 4cfa728413 sh2: fold cached interpreter into recompiler 2023-03-29 06:37:34 +00:00
invertego 600964d722 sh2: reuse previously recompiled blocks 2023-03-29 06:37:34 +00:00
invertego 241f0e9a36 sh2: precise recompiler block invalidation
- Update dirty bit field on invalidate so overlapping blocks can be lazily evicted
- Track "generation" to allow entire cached memory area to be lazily evicted
- Invalidate appropriate cache line/memory area on cache purge
2023-03-29 06:37:34 +00:00
Luke Usher 462afe89f8 md: undo reduce vdp sync when emulating 32x
While a significant performance increase, it broke Metal Head and some other titles; not worth the trade off.
2023-03-28 14:27:18 +01:00
TascoDLX 7e237528b4 md: bump serializer version 2023-03-27 14:10:04 +00:00
TascoDLX 076d73fafb mcd: handle empty drive state 2023-03-27 14:10:04 +00:00
TascoDLX 9ab140b289 md: latch vdp window params 2023-03-27 14:10:04 +00:00
TascoDLX 4418470316 md: allow invalid link to terminate sprite list 2023-03-27 14:10:04 +00:00
TascoDLX fda7c79b51 m32x: sync to fix vdp render issue 2023-03-27 14:10:04 +00:00
Luke Usher 4713fb37cc mia: add database entries for two more games with bad header information 2023-03-24 11:33:41 +00:00
Jeff Linahan 84b5222332 removed auto-generated qt.moc 2023-03-24 10:06:56 +00:00
Jeff Linahan f11ad490cd discord invite link 2023-03-22 17:48:20 +00:00
invertego 4b2b00a834 nall: use llvm's lld linker with clang
Using lld is required to support advanced scenarios like incremental
ThinLTO and PDB symbol output. macOS has its own linker (ld64) and we
can continue to use that there.
2023-03-20 10:38:37 +00:00
invertego 608556e0a9 nall: remove c++20 diagnostic for gcc
This diagnostic is unrecognized until GCC 12 and even then it doesn't
seem to actually do anything. We can rely on Clang for coverage here.
2023-03-20 10:38:37 +00:00
remutro f2ca7a973c Feature: undo last save or load state 2023-03-20 10:38:26 +00:00
remutro be869f9772 don't rely on extended header for region if present 2023-03-16 16:07:56 +00:00
remutro 5a4d333734 include make file changes 2023-03-15 11:10:12 +00:00
remutro 81692a076c Fix previous RTC properly as well as GDB symbol generation on Windows 2023-03-15 11:10:12 +00:00
Luke Usher b6350b3c0f md: (performance) reduce vdp sync when emulating 32x 2023-03-14 13:57:09 +00:00
invertego 0734768955 mia: respect iNES 2.0 NTSC timing setting
If the iNES 2.0 header specifies NTSC timing, ares should not emulate a
PAL console even if the user region setting is "prefer Europe".

This change also embeds the iNES header in manifests to simplify user
bug reporting.
2023-03-14 09:28:14 +00:00
Luke Usher 4aa3b27de2 build: remove msvc/msbuild for now
While I am happy we did the work to support this, having multiple
build systems does make it harder for contributions to be made

We can restore msbuild CI tests once (if) we eventually switch
to cmake.
2023-03-13 20:56:59 +00:00
invertego 89b3e5a20b build: a couple minor makefile fixes
Apply -march tuning for x86 (not just x86-64) and correctly pass
the ThinLTO cache path through the non-CL Clang frontend on Windows.

The move to CMake can't come soon enough.
2023-03-13 18:17:41 +00:00
invertego 65a3d38a2a build: enable clang ThinLTO
With ThinLTO and an incremental LTO cache, incremental link time (with
LTO, of course) goes down from tens of seconds to less than a second.

For whatever reason, ThinLTO needs libco's co_swap_function to have
external linkage. Who am I to argue?
2023-03-13 15:38:39 +00:00
invertego aa9c641083 mcd: always allocate cartridge slot
When booting the MD core from a CD a board is allocated on demand in
Cartridge::power(), and this is critical for Mega CD 32X games to
function. However, it also puts the cartridge into an inconsistent state
in which allocate() was never called and therefore catridge.node is
null, causing disconnect() and save() to be short-circuited. This means
the board never gets cleaned up, which also means it never gets
recreated in power() on subsequent loads. One consequence is that
loading a MCD game followed by a MCD 32X game will cause the 32X to not
actually be connected.

Given that all of these system configurations contain a cartridge slot,
it follows that one should always be allocated. This implies
cartridge.node will always be non-null so it cannot be used to determine
if a cartridge is actually connected. This change corrects one such
usage.
2023-03-13 15:38:11 +00:00
invertego b178d3d51a build: support 32-bit x86, arm 2023-03-13 11:21:26 +00:00
invertego 32bfb2ed08 ci: add builds for make+cl and msbuild 2023-03-13 11:21:26 +00:00
invertego 7f7cc868c4 build: add vs project + solution for desktop-ui 2023-03-13 11:21:26 +00:00
invertego 334101d599 build: support arm64 msvc build 2023-03-13 11:21:26 +00:00
invertego 65e6d0a397 nall: implement platform.hpp macros for msvc 2023-03-13 11:21:26 +00:00
invertego fff03a3d56 nall: assume sse4.1 support building with msvc
MSVC does not define architectural levels in between /arch:SSE2 and
/arch:AVX. For now, let's just assume SSE4.1 support.
2023-03-13 11:21:26 +00:00
invertego bbbd621130 n64: do not require __builtin_clz
Use MSVC intrinsic as an alternative when possible, otherwise fall back
to standard C++.
2023-03-13 11:21:26 +00:00
invertego fc50ad03ae md, n64: do not require __int128 extension
Avoid hard dependency on __int128 type suppport. For extended
multiplication, use MSVC intrinsics as an alternative when possible.
If neither are supported, fall back on the u128 type defined in
nall/arithmetic.hpp (which incidentally also works when building as
32-bit).
2023-03-13 11:21:26 +00:00
invertego b7a1fe926a a26: avoid narrowing conversion in default member initializer
MSVC applies the same narrowing rules to these as it does to list
initializers, and while I don't know if that's justified by the standard
it's easy to avoid narrowing conversions. In this case, basically every
other core already defines System::frequency as a double so the a26 core
was the odd one out.
2023-03-13 11:21:26 +00:00
invertego c4588ee4f4 libco: fix section overrides with msvc
MSVC doesn't seem to support string literal concatenation in a
__declspec attribute, but that's fine because we only care about adding
to the .text section. It also requires an explicit pragma to define the
.text section before it can be referenced. Clang is fine with or without
these changes.
2023-03-13 11:21:26 +00:00
invertego 21d5bf4183 nall: msvc build fix for Node::sort
MSVC doesn't think the lambda in the default parameter has access to the
members it reads from. I'm not sure if's right but it's easily avoided.
2023-03-13 11:21:26 +00:00
invertego e38b7e586d nall: add move constructors to BitField/Range
MSVC wants these to compile certain experessions, and while I'm not 100%
sure if it technically should require them, I see no reason for these
classes not to have any.
2023-03-13 11:21:26 +00:00
invertego e01d5c1866 build: rearrange calling convention overrides
MSVC is more strict about the ordering of these than GCC/Clang.
2023-03-13 11:21:26 +00:00
invertego 4e96e39ab2 build: add makefile support for cl, clang-cl 2023-03-13 11:21:26 +00:00
invertego 9fce98f7d7 build: avoid narrowing conversions in initialization lists
Narrowing conversions in initialization lists are disallowed by the
standard, but nall was supressing this diagnostic (which is actually
an error by default). MSVC doesn't let you supress errors so easily, so
we'd do well to abide by the standard and perform explicit casts as
needed. For nall::shared_pointer::create() we can simply avoid the
uniform initialization syntax to bypass these extra rules, which is the
same strategy taken by implementations of std::make_shared().
2023-03-13 11:21:26 +00:00
invertego 91c0844f19 build: avoid use of GNU case range extension 2023-03-13 11:21:26 +00:00
invertego b872687145 build: avoid use of operator name keywords 2023-03-13 11:21:26 +00:00
invertego 8914915b31 build: avoid use of variable length arrays
Variable length arrays are a C language feature (one of many, actually)
that does not exist in any version of the C++ standard. GCC supports
them in C++ with improvised semantics defined by no standards body, and
Clang follows suit for compatiblity with GCC.
2023-03-13 11:21:26 +00:00
invertego 188171b49d build: avoid use of GNU statement expression extension 2023-03-13 11:21:26 +00:00
invertego 4befb14e47 build: avoid use of non-standard escape character '\e'
Unfortunately there's no way to enable warnings for this without turning
on a bunch of others (with -Wpedantic).
2023-03-13 11:21:26 +00:00
invertego 42118b22e4 build: avoid use of c++20 extensions
We are already specifying `-std=c++17`, but apparently GCC and Clang
treat that as more of suggestion than a command...
2023-03-13 11:21:26 +00:00
remutro 8af10a6816 Add missing cast resulting in truncated timestamp 2023-03-13 09:19:16 +00:00
remutro 6dd3fdca68 Don't use rom hash to allow for homebrew 2023-03-13 09:18:31 +00:00
remutro 56a848b59d Fix save for Sonic 3 & Knuckles 2023-03-13 09:18:31 +00:00
Giovanni Bajo ac06c41145 desktop-ui: add CLI options to manage settings
Now a setting can be changed from command line using --setting.
The list of settings can be dumped with --dump-all-settings, so that
it is easy to find out how a certain setting is exactly spelled.
2023-03-12 22:39:43 +00:00
invertego 267b6e0f21 n64: make out-of-range shift deterministic in MAME RDP
Matches the SSE and VMX implementation.

Fixes obvious rendering artefacts with the N64 RDP on AArch64 targets.
2023-03-12 22:39:31 +00:00
remutro 164775e4a7 force PAL region for Alisia Dragoon (E) 2023-03-10 13:26:09 +00:00
Luke Usher c2004f6ad5 ruby: remove ghost Direct3D 11.0 driver 2023-03-08 19:30:34 +00:00
Luke Usher 832a2ada10 ares: bump version to v132 2023-03-08 10:06:59 +00:00
TascoDLX 383d2db303 md: fix vdp port mirroring 2023-03-07 23:02:26 +00:00
TascoDLX 358985e8c1 md: fix realtec mapper 2023-03-07 23:02:26 +00:00
remutro 41b6147ca7 add shader command line option to help 2023-03-07 18:46:44 +00:00
TascoDLX 6868f1bf1d mcd: fix cdc counter register 2023-03-06 10:54:35 +00:00
TascoDLX 4d43b2ce1f mcd: fix timer update 2023-03-06 10:54:35 +00:00
TascoDLX c41666fee6 mcd: implement peripheral reset 2023-03-06 10:54:35 +00:00
TascoDLX 768a4724af mcd: avoid early pcm address update 2023-03-06 10:54:35 +00:00
TascoDLX 2ed64ef858 md: fix sync logic 2023-03-06 10:54:35 +00:00
remutro b269647a9f console option, we never knew you 2023-03-06 10:53:26 +00:00
remutro db97949965 Updates based on feedback 2023-03-06 10:53:26 +00:00
remutro 81a67475dd add option for building cores 2023-03-06 10:53:26 +00:00
remutro 92211c78ec Updated build instructions 2023-03-06 10:53:26 +00:00
invertego 1359f36703 md: add realtec mapper support 2023-03-06 10:52:31 +00:00
invertego ae9c3ae728 desktop-ui: improve terminal support on windows
Previously, terminal (console) support on Windows required opting in at
compile time. Now, the runtime behavior is largely the same regardless
of how ares is compiled.

- ares will attach to the terminal of the parent process (if present) by
  default and redirect any unset stdio streams.
- If the --terminal argument is provided, ares will always create a new
  terminal window and stdio will be redirected to it.
- Otherwise, if stdio handles were already valid on launch they will be
  left alone (to support redirection to/from files).
2023-03-04 20:41:24 +00:00
Giovanni Bajo d61664e724 n64: complete generation of address errors
This also handles the fetch and devirtualize case, that cover also
the situation where the CPU jumps to a misaligned PC.
2023-03-03 19:08:48 +00:00
Giovanni Bajo ec21b9f44c n64: fix PC address at exception
Use always a 64-bit address (even if the context is 32-bit: it gets
sign-extended there anyway).
2023-03-03 19:08:48 +00:00
remutro 6822628135 Resetting the screen isn't necessary 2023-03-01 09:13:24 +00:00
remutro 0a6147c177 Fix for Peter Lemon's CPU reset test 2023-03-01 09:13:24 +00:00
invertego 9b521dd87b desktop-ui: optimize for x86-64-v2 in non-local builds
This is a more generic way of declaring an Intel Nehalem -like set of
ISA extensions in newer versions of GCC (11) and Clang (12).
2023-02-28 15:43:24 +00:00
invertego e4fee670ad desktop-ui: check for SSE4.2 support in non-local builds
By default, builds are "local", meaning they are optimized specifically
for the host machine. For non-local builds such as our CI builds, we
enforce a minimum CPU spec to allow the compiler to use instructions
beyond the base AMD64 ISA. ares may also make use of SSE4 instructions
via intrinsics in the N64 core. On AMD64, the capabilities of the host
CPU are now checked at runtime and an error message will be displayed to
inform users if their machine does not meet the CPU requirements of that
build.
2023-02-28 15:43:24 +00:00
invertego 3a6113846f ci: simplify mingw arm64 build setup
- Because clangarm64 is now a default enabled package source, there is
  no need to edit pacman.conf.
- Because there is no need to edit pacman.conf, there is no need to sync
  the package database.
- Because there is no need to sync the package database, there is no
  need to update the initial set of installed packages to prevent
  version mismatches.
- Install the "clang" package in favor of the "toolchain" package group
  as none of the extra packages are needed by ares.
2023-02-28 10:25:43 +00:00
invertego a0c7b3bf6a ruby: in wasapi driver, force silence in channels after first 2
The other audio drivers in ares read exactly two samples from the buffer
passed to output(), but the WASAPI driver was reading the number of
channels supported by the device. ares only ever passes in two samples
so ruby was reading beyond the extent of the array. This caused garbage
to be piped through and resulted in silence on certain systems and build
configurations (likely because of NaNs).
2023-02-28 10:25:19 +00:00
TascoDLX 11003eb5f1 mcd: handle subcpu wordram access when unavailable 2023-02-26 09:48:36 +00:00
TascoDLX dadf0d4228 mcd: fix subcpu reset behaviors 2023-02-26 09:48:36 +00:00
invertego 4fede70705 nall: stop defining NOMINMAX in makefile
This was only needed for parallel-rdp and that's been fixed upstream
which is now causing redefinition warnings. It's still defined by nall
headers so most of ares is unaffected either way.
2023-02-26 08:03:58 +00:00
TascoDLX b984bb52e9 md: implement io latch behavior & serial registers 2023-02-25 20:23:42 +00:00
TascoDLX b6bdd06c4e mcd: protect against illegal memory access 2023-02-25 20:23:42 +00:00
TascoDLX c57130a4bf mcd: fix various gate array registers 2023-02-25 20:23:42 +00:00
invertego 7a9a99f62c mcd: add missing cdc irq serialization 2023-02-24 08:02:30 +00:00
invertego 8156a7b760 sh2: elide runtime delay slot check when possible 2023-02-24 08:01:53 +00:00
invertego ff5c8acd9a sh2: implement illegal slot exceptions in recompiler 2023-02-24 08:01:53 +00:00
invertego 6584f6e691 sh2: fix illegal slot exceptions in interpreter
When in a delay slot, instructions that modify PC should immediately
trigger an illegal slot instruction exception. This exception is not
predicated on the branch condition (in the case of BF/S or BT/S) of the
instruction in the slot. Furthermore, it should trigger before any side
effects of the instruction are observed.
2023-02-24 08:01:53 +00:00
Luke Usher 662c1f7b66 desktop-ui: disable color bleed by default 2023-02-23 14:52:40 +00:00
invertego 4b70e4e891 mcd/32x: default to single gamepad for Corpse Killer (E) 2023-02-23 10:22:12 +00:00
Luke Usher 2e6531a036 ps1: rename sio acknowledgeInputLevel to ackknowledgeAsserted, fix io.readWord 2023-02-21 15:20:18 +00:00
Luke Usher a79a9f0fbf nall: support mode1/2048 tracks in CHD files 2023-02-20 19:32:26 +00:00
Adrian Siekierka 326616f936 ws: fix APU not emitting channel 2 output when only voice enabled 2023-02-20 17:29:20 +00:00
Adrian Siekierka d213010a72 ws: add stub KARNAK emulation 2023-02-20 17:29:20 +00:00
invertego 8b80201d16 ps1: automatically format memory cards 2023-02-20 17:28:50 +00:00
invertego c23d842a90 ps1: actually persist memory cards to disk 2023-02-20 17:28:50 +00:00
TascoDLX 8b93f57293 mcd: bypass cdd tracking command to support v1 bios 2023-02-19 17:33:51 +00:00
remutro a0f46b4dac fix ws save states 2023-02-16 15:41:23 +00:00
Giovanni Bajo d4f9caee65 n64: improve boot timeout handling
Raise the timeout to make Start Wars: Shadows of the Empire boot again.
Also improve simulation of CPU halt; the real PIF does toggle the NMI
line but it does so extremely quickly. We don't emulate PIF that often,
so it's more accurate to simply keep the NMI line asserted forever,
as the final effect on the CPU is the same.
2023-02-16 09:36:50 +00:00
Luke Usher 5e48762c48 desktop-ui: base multiplayer from actual framebuffer size
Previously, it was just based on a base size of 320x240.
2023-02-15 22:38:38 +00:00
Luke Usher 0ba4f49e04 desktop-ui: remove multiplier debug print 2023-02-15 22:31:53 +00:00
Luke Usher cc8cf2539f desktop-ui: fix rounding issues in multiplier calculation 2023-02-15 22:18:55 +00:00
Luke Usher 663e341584 ruby: rename Direct3D driver to Direct3D9
Allows for development of Direct3D11/12 drivers in future
2023-02-15 22:18:54 +00:00
invertego b4f6912d68 hiro: fix macOS open/save panels allowing all file types 2023-02-15 11:33:31 +00:00
Luke Usher 9f6a1548d1 desktop-ui: rework scaling settings
The multiplier scale settings are now radio buttons, allowing the
user to see which option is selected.

Available scale sizes are no longer bound by the current monitor
size, avoiding the situation where a selected option disappears
when moving a portable configuration to a different computer,
instead, the actual resizing code prevents the window from growing
larger than the display size.

The window resizing logic now avoids un-maximizing the window, if
the user has manually done so, even when adaptive sizing is
enabled.

Scale options have been renamed to better describe their function
and two new scaling modes have been added:

"Center" has been renamed to "Scale (Integer)"
"Scale" has been renamed to "Scale (Best Fit)"

New setting: "Pixel Perfect" which will always display a 1x scale
image in the center of the display, regardless of the window size

New setting: "Scale (Fixed)" which will always display an image
matching the users selected scale factor (1x, 2x, etc) regardless
of screen size.
2023-02-15 11:08:53 +00:00
Luke Usher 2e8ac93a42 a26: fix scale (thanks FitzRoyX) 2023-02-15 09:27:40 +00:00
Luke Usher 41b0a55af3 ng: fix overscan and scale (thanks FitzRoyX) 2023-02-15 09:27:27 +00:00
Luke Usher a6d4fd7c3e ng: fix issue where adpcm-a steps may be processed late 2023-02-14 18:31:51 +00:00
Luke Usher 99d711497e Revert "Radio the scale settings and allow 1x #945"
This reverts pull-request #945 as it made ares rather frustrating
to use in non-1x situations for most users.

A more robust scaling solution will be worked on soon.
2023-02-14 15:01:05 +00:00
Giovanni Bajo 518666b18a n64: increase boot timeout in PIF HLE
Allow Turok to boot again. This probably points to a problem in our
CPU timings, but the boot timeout number is made up anyway and doesn't
really help anyone to keep it short, so bump it.

Thanks to kev4cards for the analysis
2023-02-13 09:36:36 +00:00
Giovanni Bajo 6d6c058d25 n64: fix savestates by serializing cic object 2023-02-13 09:36:36 +00:00
Giovanni Bajo 48e7bdc3b4 n64: add more support for 64DD on PIF HLE 2023-02-13 09:36:36 +00:00
Giovanni Bajo c46abdf02e n64: improve support for 64DD 2023-02-13 09:36:36 +00:00
Giovanni Bajo 0cbac7df02 n64: avoid usage of localtime_r 2023-02-13 09:36:36 +00:00
Giovanni Bajo 9355fc2228 n64: add savefile for RTC and detect Animal Forest 2023-02-13 09:36:36 +00:00
Giovanni Bajo 08b48cec4c n64: add support for joybus RTC 2023-02-13 09:36:36 +00:00
Giovanni Bajo 0480285fa7 gamepad: improve accuracy of controller pak and rumble pak emulation
Controller paks only accept writes in range 0-7FFF (without mirroring),
and return 0 when reading out of range.

Rumble paks return the ID only in range 0x8000-???? (TBC)
and accept writes only in range 0xC000-???? (TBC).

Fixes Milo's Astro Lanes saves, and Goldeneye initial rumbling.
2023-02-13 09:36:36 +00:00
Giovanni Bajo 7770327d3c n64: fix an off-by-one causing buffer overflow 2023-02-13 09:36:36 +00:00
Giovanni Bajo e57e77cb11 n64: complete PIF serializer 2023-02-13 09:36:36 +00:00
Giovanni Bajo 4c73d18494 n64: fix seed prefix on the wire (which is not random at all) 2023-02-13 09:36:36 +00:00
Giovanni Bajo 1918c912c5 n64: increase the HLE steps as it shouldn't matter much anyway 2023-02-13 09:36:36 +00:00
Giovanni Bajo e6912d4514 n64: change PIF/CIC fifo queue to be bit-based instead of "frame-based" 2023-02-13 09:36:36 +00:00
Giovanni Bajo 12dbcb1b40 n64: emulate dummy challenge algo on non-6105 CICs 2023-02-13 09:36:36 +00:00
Giovanni Bajo 45a4f1a366 n64: move 6105 challenge code from PIF to CIC (where it belongs) 2023-02-13 09:36:36 +00:00
Giovanni Bajo a51a52263a n64: correct some more details around the osinfo byte in PIF-RAM 2023-02-13 09:36:36 +00:00
Giovanni Bajo b395886327 n64: fix a couple of bugs in PIF HLE 2023-02-13 09:36:36 +00:00
Giovanni Bajo 95215dec1d n64: add accuracy option to activate region lock 2023-02-13 09:36:36 +00:00
Giovanni Bajo b697623c13 n64: in PIF HLT, move Rn state check to the top and mark it likely 2023-02-13 09:36:36 +00:00
Giovanni Bajo d965cc8f13 n64: boot timeout fix 2023-02-13 09:36:36 +00:00
Giovanni Bajo 00de20af93 n64: rewrite PIF HLE emulation to be very accurate to the SM5 firmware 2023-02-13 09:36:36 +00:00
Giovanni Bajo 8097ae3ae5 n64: add NMI emulation to the CPU 2023-02-13 09:36:36 +00:00
invertego a63d20c0d1 ares: support disconnecting controller from emulated device
Selecting "nothing" for a controller port from the UI only consistently
blocked input from the host, and it did not reliably do the extra work
required to actually disconnect the controller from the perspective of
the emulated device.

This was handled only by the MD and N64 cores, but now all cores are
standardized on the disconnection method originally implemented for MD.
2023-02-13 09:30:29 +00:00
Adrian Siekierka 5c05e80c48 ws: fix rtc typo 2023-02-11 19:24:37 +00:00
Luke Usher f9b5a8a3a6 nall: add bcd encode/decode 2023-02-10 19:40:46 +00:00
Adrian Siekierka 5db4443529 ws: rewrite RTC emulation 2023-02-10 18:37:39 +00:00
Giovanni Bajo 2f27d00d60 n64: unbreak 64dd after recent changes
It got broken in the large refactoring in ad16c4a6
2023-02-08 17:48:33 +00:00
Adrian Siekierka c03099fa51 nall, sh2, n64: update to latest sljit 2023-02-07 21:26:32 +00:00
Luke Usher ba3b00cd05 Squashed 'thirdparty/sljit/' changes from 4b8798e4d2..4f7d8ec545
4f7d8ec545 Improve code generation on x86
09cad66bc0 Change tmp1 to ebx on x86-32
2de5e04919 Allow negated comparison
5040a3caa1 Test84 fix
1811f1dcea Rework sljit_emit_shift_into on s390x
ba08667852 Rework sljit_emit_shift_into on x86, arm, ppc, riscv, mips
95d2d320ed Add define for masked shifts
dc79333621 Implement fcopy on ppc, mips
c9e58a4806 Implement fcopy on s390x
03f68fea46 Implement fcopy on x86, arm, riscv
ac6c7b307f Implement byte reverse on ppc
f4d1b06e9d Implement byte reverse on s390x
5ed842e093 Implement byte reverse on x68, arm, mips, riscv
fba2206b40 freebsd: implement system specific execallocator (#155)
0a0ab41d03 test: update test15 for 4 arguments (#149)
1942237bda config: really improve autodetection for arm (#153)
7de0fee9a7 Move allocators to separate files (#151)
7de1a4356d On x86_32, check for virtual registers in conversions to and from floating point (#152)
c2f9c138a6 riscv: disable FPU when using soft-float ABI (#147)
3b89155a25 config: improve autodetection for ARM (#145)
0a313731b9 Implement new features on s390x
26213dadc4 Introduce op_dst
faecd2b12f Implement sljit_get_return_address
8b491d0ade Replace not with xor
88e0dcf360 Add allocator data getters

git-subtree-dir: thirdparty/sljit
git-subtree-split: 4f7d8ec545f58ebe93a08f137fcb9a6dd2bb170f
2023-02-07 21:25:29 +00:00
Luke Usher 9ccab8b676 Merge commit 'ba3b00cd057bbf4ecb1915aea6debde2461a5a6e' 2023-02-07 21:25:29 +00:00
Luke Usher 188bda9259 Squashed 'ares/n64/vulkan/parallel-rdp/' changes from 4c3129f71a..3abd437761
3abd437761 Update to 7d75aa31e42da166a00604fdfcc29fa26bd3543c.
c6f79549e7 Update to 65f4f4da2ec11cf3485318dbb4ccd41d35d72a36.

git-subtree-dir: ares/n64/vulkan/parallel-rdp
git-subtree-split: 3abd4377618cce89ad8aea524dc2f93a5d7637dd
2023-02-07 21:24:49 +00:00
Luke Usher d749af17db Merge commit '188bda9259346020e60d262eb5bd917cc694a5f0' 2023-02-07 21:24:49 +00:00
Adrian Siekierka 539cd5cc15 ws: implement PTS-0101 flash chip emulation 2023-02-05 22:31:08 +00:00
Adrian Siekierka 1ad25e180c ws: fix line compare interrupt not being emitted for line 0 2023-02-05 20:36:46 +00:00
invertego 5220b1483e sfc: fix debugger memory view for cx4, sa1, superfx 2023-02-04 12:30:27 +00:00
kev4cards 6869bbb971 n64: Do not use maximum dead-zone value in scaling
The maximum dead-zone value should be set to 0 like all other numbers in the dead-zone.
2023-02-04 08:18:45 +00:00
remutro 458e4f6ca5 Memory paks for N64 don't exist 2023-02-04 08:18:18 +00:00
Adrian Siekierka e9bcabf693 ws: fix IRQ, PPU timer emulation edge cases 2023-02-03 09:47:12 +00:00
remutro a1adfbba22 Misc fixes to N64 Mia DB 2023-02-03 09:47:01 +00:00
Giovanni Bajo 1d8dc20148 n64: unbreak isviewer after recent change
A few mistakes prevented ISViewer from working after ad16c4a67
2023-02-02 18:27:25 +00:00
Giovanni Bajo 7f9346e5ec n64: add approximate timings on PI and RCP reads 2023-02-01 08:21:27 +00:00
Giovanni Bajo ad16c4a67a n64: large refactoring to introduce timing in memory handlers
This very boring commit should basically produce no changes. It just
make sure all devices can now step the CPU while the I/O is in
progress, if needed.
2023-02-01 08:21:27 +00:00
Giovanni Bajo 21c985b3da n64: implement correct timing for SI (PIF) direct word writes 2023-02-01 08:21:27 +00:00
Giovanni Bajo cb01795df6 n64: initial estimation of PIF timings
Numbers are based on this test ROM:
https://github.com/rasky/n64-systembench

There are still many other cases to handle but this should provide
the initial framework for further experimentation with PIF timings.
2023-02-01 08:21:27 +00:00
FitzRoyX ec87c304fa Update presentation.cpp 2023-02-01 08:20:08 +00:00
FitzRoyX 8eb2ff3eab Update lspc.hpp 2023-02-01 08:20:08 +00:00
FitzRoyX de24f56cba Update lspc.cpp 2023-02-01 08:20:08 +00:00
FitzRoyX 90b0b19bf5 Update tia.cpp 2023-02-01 08:20:08 +00:00
FitzRoyX 142ae1be99 Update lspc.cpp 2023-02-01 08:20:08 +00:00
FitzRoyX e57c241424 Update presentation.cpp 2023-02-01 08:20:08 +00:00
FitzRoyX 1888b2934b Update presentation.hpp 2023-02-01 08:20:08 +00:00
FitzRoyX 3af6f1bf59 Update settings.hpp 2023-02-01 08:20:08 +00:00
FitzRoyX f088cfc31c Update settings.cpp 2023-02-01 08:20:08 +00:00
invertego 3eff1d2efb ruby: fix hang on loading rom from command line
Fix a regression introduced by my last change. The pattern of checking
ready() at the top doesn't work for clear() because it's called from
iniatialize(). This was obscured by the fact that other code calls
clear() again after initialization *unless* you are loading a ROM
directly from the command line.
2023-02-01 08:18:53 +00:00
invertego 88c347fdaa ruby: fix wasapi and xaudio2 crashes
The WASAPI driver should now gracefully handle machines that don't have
any available output devices. The XAudio2 driver probably still won't,
but more importantly it won't crash machines that don't have a specific
DirectX redist from 2008 (!). It needs a rework but for now I'm leaving
it a little better than I found it.
2023-01-28 23:45:24 +00:00
remutro 8f69189429 Fix save info for International Track & Field 2000 2023-01-28 23:44:51 +00:00
Luke Usher 95ed00c0d2 ng: implement mslugx protection asic 2023-01-27 14:56:38 +00:00
Luke Usher 463c52afe6 ng: add support for jockey-gp board type
The rom viewer debug window is a casualty of moving
to the board system, but as NES/Master System and
others with multiple board types don't have it,
it's not a big loss.
2023-01-27 13:27:31 +00:00
FitzRoyX e39a4d979d Update neo-geo-crypt.hpp 2023-01-27 10:09:55 +00:00
Luke Usher 6092f2bcff ng: coin inputs are active low 2023-01-26 13:44:05 +00:00
Luke Usher 7bafe50098 ng: fix unibios MVS/AES detection 2023-01-26 13:42:32 +00:00
Luke Usher fe50e29827 ng: fix horizontal scaling 2023-01-26 10:20:22 +00:00
Luke Usher d862eeaf79 mia: default neo-geo to english language bios + allow non-zipped bios
Allows for people to select a bios version manually if required (eg: unibios)
2023-01-25 21:44:24 +00:00
Luke Usher f08e7c66b3 ym2610: implement status/sample end registers and masking 2023-01-24 13:26:15 +00:00
Luke Usher 7d1d5d1e68 mia: fix case sensitivity in neo-geo rom loading 2023-01-23 12:12:50 +00:00
Luke Usher f333f28cea mia: add support for neo-cmc encryption (type 42 and type 50) 2023-01-23 10:09:12 +00:00
Luke Usher a370a0eb5a ares: use core-specific serializer version 2023-01-21 23:40:43 +00:00
Luke Usher 5018755374 ng: serialize sram 2023-01-21 23:33:01 +00:00
Luke Usher 3d4db007a9 ng: fix inverted dip switches (0 = on, 1 = off) 2023-01-21 23:32:50 +00:00
Luke Usher 706a5850a1 desktop-ui: show system name next to the game in "Recent Games" 2023-01-21 23:14:29 +00:00
Luke Usher 0a9a6b58c2 ng: add board type detection from feature flags 2023-01-21 22:54:06 +00:00
Luke Usher 0d588e0c0a mame2bml: support 'feature' tags 2023-01-21 22:47:18 +00:00
Luke Usher 9b74e87507 ng: support "fill" type loadflags
Fixes segfaults when loading Metal Slug 3 and others

Note that these games still won't boot due to missing protection
emulation.
2023-01-21 22:37:44 +00:00
Luke Usher 6b15519c9d mame2bml: support "fill" type loadflags 2023-01-21 22:31:40 +00:00
Luke Usher e655b3c096 ng: implement standard PROM bank switching 2023-01-21 22:05:32 +00:00
Luke Usher f3f1e4adcb ng: fix a (new) bug where voice-a rom was loaded instead of voice-b 2023-01-21 21:22:23 +00:00
Luke Usher 516c2c6eba mia: fix code comment 2023-01-21 21:21:39 +00:00
Luke Usher 131e353b9b ng: support loading mame format roms without guess-based heuristics
NOTE: This requires 'non merged' type roms, with all files related to
the game in a single zip file, ares does NOT resolve parent/child
relationships between roms.
2023-01-21 21:18:38 +00:00
Luke Usher 6d1a3a420c ng: fix an issue where sprite/fixed rom were swapped in the debug view 2023-01-21 20:44:00 +00:00
Luke Usher 7b1a58aa47 mame2bml: also convert load type flags 2023-01-20 21:44:03 +00:00
Luke Usher ef1f05848e mia: update neo geo database 2023-01-20 17:17:27 +00:00
Luke Usher 89718ab50a mame2bml: fix issue where invalid characters were inserted into node names 2023-01-20 17:16:28 +00:00
Luke Usher 21cf7c99bf mia: add initial Neo Geo rom database 2023-01-20 16:27:36 +00:00
Luke Usher dabc688b26 tools: add too lool to convert mame software lists from xml to bml
The use case here is quickly importing metadata about Neo Geo roms,
rather than hard-coding everything or using unreliable heuristics
2023-01-20 16:27:24 +00:00
Luke Usher ae179fef67 tools: move genius and sourcery to tools subdirectory 2023-01-20 14:55:04 +00:00
Luke Usher ec055dafcc scripts: add script to split nall/hiro/ruby/libco to their upstream repos
Assumes that the local environment has remotes set up for each library.
2023-01-20 13:42:13 +00:00
Luke Usher 8a71af4be1 n64: fix is-viewer debug output in commercial games + libdragon
This is a little bit hacky, because the debugging code in libdragon
is not compatible with actual IS-Viewer hardware, so we emulate
a 'quirky' version that satisfies both libraries.
2023-01-20 13:38:10 +00:00
invertego c47afd5c76 build: fix gcc-only fallthrough warnings 2023-01-17 11:16:42 +00:00
Luke Usher f037be9248 spec: preliminary ZX Spectrum core
This emulates the ZX Spectrum 48k and 128k models and should be fairly accurate
although imperfect; it is considered experimental for now. Save States are not
fully implemented, you may wish to avoid using them for this core.

No controller interface is currently exposed, meaning games must be played with
the keyboard at this time. It is planned to support the Kempston interface,
while supported by the underlying core, the UI interface for attaching expansion
port devices has not yet been implemented.

You must map a "Keyboard Capture" hotkey to allow ares to emulate the keyboard.

Ares maps most ZX Spectrum keys 1:1 with the same key on the host keyboard.
CAPS SHIFT is mapped to Left Shift, and Symbol shift is mapped to Left Control.

For special characters, it may be beneficial to look up the ZX Spectrum
keyboard layout. For the 48K it is necessary, as BASIC uses hot keys
rather than typed commands, for example, to load a game on the 48k,you must
type `J <symbol shift> PP` and then hit enter, which results in `LOAD ""`
being entered on the screen.

For the ZX Spectrum 128k, you can just use the Tape Loader menu option.

The emulator only implements support for raw WAV dumps right now; this is
because the TZX format is over-complicated, and I did wish to implement it at
this time.

There are many tools available for converting TZX to WAV, for all platforms,
so this isn't really seen as a blocking issue.
2023-01-15 22:32:31 +00:00
invertego 48fa446eeb gba: fix eeprom saves, fate willing 2023-01-08 17:55:41 +00:00
invertego 3fd666c583 Revert "gba: fix eeprom saves for real this time"
This reverts commit 972495df89.
2023-01-08 17:55:41 +00:00
invertego 9eb14aea6f nall: enable switch case fallthrough warnings
Enable these warnings in nall so they apply to all of ares and annotate
legitimate fallthrough with C++17 standard [[fallthrough]] attribute.
This type of mistake is just too easy to make.
2023-01-04 08:48:54 +00:00
invertego 3db5740bd3 mia: stop reporting famicom mapper 0 as unknown 2023-01-04 08:48:54 +00:00
invertego 3c226ed0ca ym2610, v9938: fix accidental switch case fallthrough 2023-01-04 08:48:54 +00:00
invertego 191393445e build: guard usage of sse4.1 round instructions
Guard usage of round_ss/sd intrinsics with a preprocessor check just as
we do with other SSE4.1 instructions.
2023-01-04 08:47:35 +00:00
remutro 621301990a Fix NeoGeo Save States 2023-01-03 08:12:53 +00:00
remutro d40b890d83 Add ability to set shader from command line 2023-01-02 09:37:28 +00:00
invertego 1891477e12 hiro: account for menu wrapping on Windows 2023-01-02 09:36:29 +00:00
Luke Usher 86207ff3a3 hiro: fix compilation with qt5 2023-01-02 08:42:45 +00:00
Adrian Siekierka 72956e4ba0 v30mz: fix disassembler adding CPU cycle overhead 2023-01-01 21:26:26 +00:00
Adrian Siekierka 1256987e9c ws: fix blocking APU writes to Color-mode only I/O ports in Mono mode 2023-01-01 10:44:44 +00:00
Adrian Siekierka 517dd3efc6 ws: return open bus for unavailable RAM in mono mode on WonderSwan Color 2023-01-01 10:44:44 +00:00
Adrian Siekierka 9176ed7418 v30mz, ws: implement SRAM/ROM waitstates 2023-01-01 10:44:44 +00:00
Adrian Siekierka 4f4ec10cdf ws: fix debugger cartridge ROM wait information 2023-01-01 10:44:44 +00:00
Adrian Siekierka 14db9f1ead v30mz: fix behaviour of undefined opcodes 0xC0F0, 0xC0F1, 0xFFF8 2023-01-01 10:44:44 +00:00
Adrian Siekierka 81be3393dc v30mz: fix JL/JGE emulation bug 2023-01-01 10:44:44 +00:00
Adrian Siekierka d15439a292 v30mz: fix AAA, AAS flags 2023-01-01 10:44:44 +00:00
Adrian Siekierka 7514b29e31 v30mz: fix DAA, DAS flags 2023-01-01 10:44:44 +00:00
Adrian Siekierka 0afef3389a v30mz: fix SAL, SAR, SHL, SHR flags 2023-01-01 10:44:44 +00:00
Adrian Siekierka 2dadc1e899 v30mz: fix RCL, RCR, ROL, ROR flags 2023-01-01 10:44:44 +00:00
Adrian Siekierka b07423749a v30mz: fix ADC, SBB, MUL, IMUL, AAD flags 2023-01-01 10:44:44 +00:00
Adrian Siekierka 1120921a1b v30mz: improve timing of two-register effective address calculation 2023-01-01 10:44:44 +00:00
Adrian Siekierka 9a826fd416 v30mz: fix undefined opcodes 0xD8-0xDF 2023-01-01 10:44:44 +00:00
Adrian Siekierka edd062c76f v30mz: fix opcode 0x0F, remove outdated/inaccurate comments 2023-01-01 10:44:44 +00:00
Adrian Siekierka 2429999b3c v30mz: implement BRK flag handling 2023-01-01 10:44:44 +00:00
Adrian Siekierka 8cb9a4a9c9 v30mz: more cycle-accurate memory fetching 2023-01-01 10:44:44 +00:00
Adrian Siekierka a2bd8a46f5 v30mz: fix opcode INTO implementation, implement distinct interrupt type timings 2023-01-01 10:44:44 +00:00
invertego 1dcaf2d2c1 fc: use database for unheadered roms 2023-01-01 10:43:31 +00:00
invertego e7f4d8cd2b fc: support ave nina-001 board
Add support for American Video Entertainment's NINA-001 board which was
used only by the unlicensed NES port of Impossible Mission II developed
by Novotrade.

iNES mapper 34 is assigned to two unrelated boards, so detection must
rely on the NES 2.0 header or use the CHR ROM size as a heuristic.
2022-12-31 09:44:08 +00:00
invertego 0ad3a7d8da fc: fix scanline check on ppudata access
Calculate the pre-render scanline from vlines() intead of hardcoding
the NTSC value. Also allow access on the post-render scanline (240).
2022-12-31 09:23:03 +00:00
Adrian Siekierka 92bf0c6669 v30mz: emulate PUSH SP bug 2022-12-28 01:33:01 +00:00
Luke Usher e536ff34a8 gb: expose color emulation options in the ui 2022-12-27 23:30:21 +00:00
Luke Usher 519423fa68 z80: oops 2022-12-27 23:30:21 +00:00
Adrian Siekierka 3f31de661d ws: accurate PPU OAM synchronization 2022-12-27 22:52:11 +00:00
Luke Usher 7c57dfa7bc z80: LD_rr_inn should set WZ to addr + 1 2022-12-27 22:37:41 +00:00
Luke Usher 3b7e0d440b bump version to v131 2022-12-27 20:02:27 +00:00
Adrian Siekierka 1e97bd6a8b ws: fix interrupt base handling on WSC, add missing cartridge/interrupt debugger properties 2022-12-27 18:41:11 +00:00
Adrian Siekierka 4b43bbf853 v30mz: fix opcode 0xF7:1 to match hardware 2022-12-27 18:41:11 +00:00
Adrian Siekierka b2a240b335 v30mz: fix opcode 0xD6 implementation 2022-12-27 18:41:11 +00:00
Adrian Siekierka 709afef820 ws: clean up level-triggered interrupt code, more accurate keypad interrupt logic 2022-12-27 18:41:11 +00:00
Adrian Siekierka 6b70091f6c ws: support pixel inaccuracy mode, for per-scanline PPU and fast APU processing - ~65% speedup on my machine 2022-12-27 18:41:11 +00:00
Adrian Siekierka 7a71b7e98f apu: more accurate timing model 2022-12-27 18:41:11 +00:00
Adrian Siekierka 7b9d8e9232 ws: add missing apu clock serialization 2022-12-27 18:41:11 +00:00
Adrian Siekierka de219e37e8 ws: expose headphone/speaker toggle 2022-12-27 18:41:11 +00:00
Adrian Siekierka 052f486793 ws: fix ppu timer behaviour on reload=1 to match hardware, add ppu timers to debugger properties 2022-12-27 18:41:11 +00:00
Adrian Siekierka 0b3f87c97d ws: fix screen regression from debugger change 2022-12-27 18:41:11 +00:00
Adrian Siekierka 35b5a4cf0a v30mz: disassembler: fix IN/OUT immediate 2022-12-27 18:41:11 +00:00
Adrian Siekierka 669fb4a433 v30mz: fix timing of opcodes 0x63-0x67, IMUL, POLL, INS, OUTS 2022-12-27 18:41:11 +00:00
Adrian Siekierka 418666dd20 ws: add serial, SoC/CPU debug properties 2022-12-27 18:41:11 +00:00
Adrian Siekierka e44cf2e956 ws: add apu, cartridge debugger properties 2022-12-27 18:41:11 +00:00
Adrian Siekierka a421550477 ws: add PPU screen1/screen2 layer support to debugger, fix 4bpp packed tiles view 2022-12-27 18:41:11 +00:00
Adrian Siekierka 1474f1001d ws: add PPU tiles to graphics debugger 2022-12-27 18:41:11 +00:00
Adrian Siekierka 3d2f8e0633 ws: minor apu hotfix 2022-12-27 18:41:11 +00:00
Adrian Siekierka dcbce15b24 ws: serial fixes 2022-12-27 18:41:11 +00:00
Adrian Siekierka 08c75e6e55 ws: appropriately gate WSC-mode-specific registers 2022-12-27 18:41:11 +00:00
Adrian Siekierka 018e07945a ws: stub serial implementation with interrupt/flag support 2022-12-27 18:41:11 +00:00
Adrian Siekierka 0355ef08ed ws: apu improvements - properly emit 24000 Hz digital samples, fix headphone output, fix channel 2 "half volume" flag 2022-12-27 18:41:11 +00:00
Adrian Siekierka c95a27d66a ws: support setting NMI register 0xB7 (no implementation), more accurate Bandai 2003 mapper emulation (>16MB ROM support) 2022-12-27 18:41:11 +00:00
Adrian Siekierka a46ab04e47 gb: fix MBC1 mapper style 2022-12-27 18:32:59 +00:00
Adrian Siekierka b8f6aeb52c gb: fix MBC1 mapper implementation for 8/16Mbit cartridges 2022-12-27 18:32:59 +00:00
invertego d46f7a3445 ares: fix console build option on Windows
The -mconsole and -mwindows flags don't seem to do much of anything when
Clang isn't targeting MinGW. On the other hand, directly overriding the
subsystem with a linker flag results in a bunch of unresolved symbols.
However, if the right entry point exists (either WinMain or main),
some apparent magic goes on under the hood to ensure that everything
links as expected, so we can just take advantage of that.
2022-12-21 07:52:37 +00:00
Giovanni Bajo 4524f9d188 n64: fix 32bit / 64bit address space confusion
context.physMask is only used for TLBs. In directly-mapped memory
segments (either cached or uncached), the virtual-to-physical conversion
uses a hardcoded mask that depends on the exact address space segment,
and is not contextful. In 32-bit, segments only use 29 bits of the
virtual address. In 64-bit, some segments (xkphys*) use the full 32 bits.

Besides 64-bit direct-mapped segments correctness, this also fixes
the devirtualize function that is used as part of the CACHE/LL/SC
opcodes, which were misbehaving when used with a uncached segment
(0xa000'0000) in 32-bit mode. This might actually affect also games.
2022-12-20 14:35:54 +00:00
invertego 67d1647d6e build: prefer clang on all platforms
Use clang++ if it exists on the path, otherwise fall back to g++.
2022-12-20 14:35:41 +00:00
invertego 619415d7dc normalize whitespace
Replace tabs with spaces and CRLF newlines with LF.
2022-12-20 09:22:06 +00:00
invertego 2daf9f5908 nall: define _WIN32_WINNT in makefile
We build third party dependencies that do not include nall, so defining
the target Windows version (currently Win7) in a header is unreliable.
2022-12-19 20:06:34 +00:00
Luke Usher 68fe9514bf ci: fix packaging of new msvc zips 2022-12-19 16:23:21 +00:00
Luke Usher 67a9b0ec1a ci: publish msvc compiled artifacts 2022-12-19 15:39:57 +00:00
invertego 0d02303de6 ci: add Clang + MSVC builds 2022-12-19 15:35:57 +00:00
invertego 91d4fb70ec build: support Clang + MSVC/WinSDK libraries
This change makes it possible to build ares using Clang without
MinGW-w64. All that is required is a copy of Visual Studio (or Build
Tools for Visual Studio) and Clang (also available through the VS
installer) along with GNU Make.

To build, just open an x64 Native Tools command prompt and run
`make compiler=clang++` as usual.
2022-12-19 15:35:57 +00:00
invertego 90af756e3c thirdparty: add glext.h and khrplatform.h
Unlike gl.h, these aren't distributed with the Windows SDK.

https://github.com/KhronosGroup/OpenGL-Registry
https://github.com/KhronosGroup/EGL-Registry
2022-12-19 15:35:57 +00:00
invertego e1e11cf75e nall: split implementation into .cpp files
Begin the process of splitting nall into separate translation units.
It can now be used in two ways:

1) as a header-only library by defining NALL_HEADER_ONLY
2) by compiling nall/nall.cpp

sourcery has been updated to demonstrate the header-only use and
everything else now builds nall.cpp.

So far the only things moved into .cpp files are implementations that
call Windows APIs. This allows most of ares to build without including
windows.h and enables the removal of the abomination that was
windows/guard.hpp. The things that actually need windows.h (hiro, ruby)
must avoid using names reserved by Windows headers, but the rest of ares
is free to use names like "far", "boolean", and "interface" with
reckless abandon.

This work is done in preparation for building against MSVC and Windows
SDK headers/libraries an an alternative to MinGW-w64.
2022-12-18 09:18:52 +00:00
invertego 8f60efcb20 nall: move lowercase primitive types to namespace
Avoid conflicts with the "boolean" type added to the global namespace by
Windows headers.
2022-12-18 09:18:52 +00:00
invertego 5ff724427a huc6280: adc/sbc decimal mode fixes
This only impacts cases with inputs that are not valid BCD. This change
was verified against hardware test roms in the Mednafen repo.
2022-12-15 23:02:48 +00:00
Luke Usher c60f91e5d5 gb: fix secondary obj palettes in dmg mode on a gbc 2022-12-14 23:46:10 +00:00
invertego b6919cd118 6502: fix adc/sbc flags in decimal mode 2022-12-14 18:57:32 +00:00
Luke Usher 1294fdb679 md: fix template naming conflicts 2022-12-12 23:20:36 +00:00
Luke Usher d4b67a92d2 hiro: store windows settings in app directory, making ares truely portable 2022-12-12 22:18:05 +00:00
Luke Usher b442ef4624 md: use templating to reduce if statements in tight inner loops
This boosts performance enough to get 80-90fps in 32X doom on my machine.
2022-12-12 21:56:20 +00:00
Luke Usher 4da6316d1d desktop-ui: make LTO default again
I know we play with this a lot; but it is the difference between barely scraping 50-55fps on 32x core to getting constant 60-70fps on my machine.

This does increase compilation time with GCC, clang fares a lot better.
2022-12-12 21:52:13 +00:00
Luke Usher 27bc5bc2bf md: reduce sync between components
Since the cpu does a full system sync on each clock cycle, there's no need to do the extra work per-component here.
2022-12-11 15:51:16 +00:00
Luke Usher 3051af6e21 md: make sure bus functions are always inlined as intended 2022-12-09 22:45:03 +00:00
Giovanni Bajo 489ac87a1c Squashed 'ares/n64/vulkan/parallel-rdp/' changes from fc3121239..4c3129f71
4c3129f71 Add missing files.
a2037e284 Update to 95b1176f929570996a4c8fa41934095f14103d32.

git-subtree-dir: ares/n64/vulkan/parallel-rdp
git-subtree-split: 4c3129f71a5d9c8865bf7aa3365ccccdcb083a9d
2022-12-08 00:41:14 +01:00
Giovanni Bajo ecb8d30b69 Merge commit '489ac87a1cbd75e44e48f15f362eafdd6f52f3bc' into n64_load_block_limit 2022-12-08 00:41:14 +01:00
Giovanni Bajo adacb0be02 n64: implement hardware limit of LOAD_BLOCK RDP command (mame RDP)
This is a documented limit of the hardware that I have personally
re-verified on real hardware. The same bug exists in parallel-RDP.
2022-12-07 11:26:17 +01:00
Giovanni Bajo 29cdd17113 nall: use snprintf to avoid warnings 2022-12-07 11:25:28 +01:00
invertego 5866a1b9f1 recompiler: implement masked shifts 2022-12-06 03:34:24 +00:00
invertego 5e8277b290 recompiler: implement bit rotates 2022-12-06 03:34:24 +00:00
Luke Usher a1bd8e63eb ps1: reduce pause command duration 2022-12-03 21:08:08 +00:00
Luke Usher 265ba002e6 fc: merge apu/cpu/cartridge into one cothread
This brings a significant performance increase to the NES/FC core with no accuracy or maintainability impact;

This is possible only because they share the same base clock, and always step at the same rate.
2022-12-03 19:18:20 +00:00
Luke Usher 88879890fb Squashed 'thirdparty/libchdr/' changes from e02b3d68eb..a20e04c12c
a20e04c12c Merge pull request #88 from irixxxx/master
04d631b0de fix double file close if opening failed
10938cbd97 Merge pull request #87 from mjunix/patch-1
b25a4c36aa Fix potential NULL dereference
50f58600ec Merge pull request #86 from jpd002/fseek_int64
678434c447 Fix fseek offset type.
464044e6cc Merge pull request #85 from scribam/patch-1
89338e7840 cmake: fix compilation with bundled zlib

git-subtree-dir: thirdparty/libchdr
git-subtree-split: a20e04c12c0c20048bf771da6df7aa2e51f5e0cb
2022-12-02 16:29:45 +00:00
Luke Usher af3e42515c Merge commit '88879890fb343037e38938b8ce2e6228418ea86d' 2022-12-02 16:29:45 +00:00
Luke Usher 8ed3b44f0b Squashed 'thirdparty/sljit/' changes from 4de967acd0..4b8798e4d2
4b8798e4d2 config: simplify use of external allocator (#143)
d598b86d81 Add tcc to the list of compilers using AT&T syntax (#142)
c8e664c73b Fix x86 inline asm register clobbers (#141)
b65c854289 Add conditional exit for clz/ctz on riscv, mips
f55425dac8 riscv: typo in detect_jump_type (#140)
0148e65576 Implement ctz and improve clz on riscv, mips
e8eb434b2e Implement ctz on s390x
51d3c96183 arm: add missing check sljit_emit_mem_update in aarch64 (#139)
cd2a31e199 Implement ctz on x86, arm, and ppc
c0286016cf Improve rotate on mips, riscv
fded9f7823 Implement rotate on s390x
35764edc9e Implement rotate on mips, riscv
ea49b3f52e Implement rotate on x86, arm, and ppc
da180ae7e1 Implement sljit_emit_shift_into on s390x
05f5980620 Implement sljit_emit_shift_into on ppc, mips, riscv
84c0bc3614 Implement sljit_emit_shift_into on x86 and arm
8da3b39558 Label odd numbered tests (#134)
06e13ac7cc Label even numbered tests (#133)
1501371fad Split emit_mem to emit_mem and emit_mem_update
89965887cc Implement return_to on mips, ppc, riscv
e21f485cb4 Implement return_to on s390x
a122423a40 Implement return_to on x86, ARM
4672d4f6cb Improve cmov on s390x
06e9864247 Change SLJIT_32 flag passing to cmov
29af0267ce Update documentation
190313fcc2 Fix spelling of 'subtract' (#132)
4325440b0b Support floating point return
ba0f935c9a Implement recent features on s390x
12e6cb055b Implement always masked shift
f22f976060 Support memory moving of register pairs on riscv, mips, and ppc

git-subtree-dir: thirdparty/sljit
git-subtree-split: 4b8798e4d2fe8f8e8fb82b28e2dda9d71a00b27f
2022-12-02 16:29:39 +00:00
Luke Usher 9c53d97491 Merge commit '8ed3b44f0bd1e872d5e02cb106da30d732549e5d' 2022-12-02 16:29:39 +00:00
Lior Halphon 6415c3a853 Prevent AppKit from handling file opens, fixes #665 2022-12-02 13:17:18 +00:00
Adrian Siekierka 09aa6346c7 v30mz, ws: emulation fixes
* The NEC V30MZ does not ignore the immediate operand in AAD/AAM calls.
  This is contrary to NEC V20/V30 behaviour, as well as many existing
  emulators. It is, broadly speaking, important to remember that the
  V30MZ is much closer to "an 80186-compatible CPU with much better
  opcode timings" than "a V20/V30 derivative". A test ROM is provided
  for this.
* The sprite base location register's access to 0x4000-0x7FFF memory
  is gated by the color mode bit, not by the 4bpp mode bit. A test
  ROM is provided for this.
* The PPU can address 1024 tiles in 2bpp color mode, simply by
  following the consecutive addresses (so 0x2000-0x5FFF total). This
  has been verified independently.
* The planar(), packed(), depth() and grayscale() functions have been
  reworked to accurately reflect what the hardware does. This has been
  verified independently.
2022-11-23 08:13:26 +00:00
Luke Usher 98ea150bce ci: remove libgtksourceview2.0-dev
This is no longer present in ubuntu 22.04.
2022-11-23 08:12:16 +00:00
Giovanni Bajo d1847c9cd3 n64: improve behavior in case of RDP crash
We want to make sure to really stop processing other commands
afterwards. Tested now with both parallelRDP and mameRDP.
2022-11-21 09:39:14 +00:00
Giovanni Bajo 9c9d7d4bf3 n64: implement correct PI openbus behavior
This is correct for direct I/O only, not for DMA. Better than nothing.
2022-11-21 09:39:14 +00:00
Giovanni Bajo 48454fe53a n64: add PC address to FPU exception logs 2022-11-21 09:39:14 +00:00
encoded-byte 6d17f38be4 fc: shift apu triangle sequence
First step is step 16 in that sequence
2022-11-21 09:38:58 +00:00
encoded-byte 9819f2f967 fc: boots audio output levels 2022-11-21 09:38:58 +00:00
invertego 3088c4942c desktop-ui: enable debugging self-signed builds on macOS
The get-task-allow entitlement is required to enable attaching a
debugger to a hardened runtime process.
2022-11-20 11:59:39 +00:00
invertego 353272a1db desktop-ui: bind analog inputs only on motion away from center
Currently, analog inputs are bound when crossing the threshold in either
direction halfway between zero and full positive/negative. This logic
doesn't work for triggers that are mapped to the full range of an axis
(as opposed to half the range) which makes them impossible to bind
correctly unless they are initially half pulled when pressing the assign
button. I'm not convinced there is much utility in binding any axis on
motion toward the center position, so this change triggers binding only
on motion away from the center.
2022-11-20 11:59:17 +00:00
invertego f42258bf9f n64: fix analog stick inputs on arm64
Converting a negative floating-point value to an unsigned integer is
undefined behavior and just happens to do the desired thing when
compiling for x86-64. Convert to a signed integer first to avoid UB and
guarantee the expected result on arm64.
2022-11-20 11:59:17 +00:00
invertego 6bd57e790e recompiler: simplify carry flag usage
Using the host carry flag is a bit tricky because on ARM64 (and most
other non-x86 architectures) the meaning of the flag is inverted for
subtraction. There were some helpers in the recompiler to deal with this
but they performed explicit architecture checks which ran counter to the
goals of a generic recompiler.

Reading back the carry flag is now handled directly by sljit. This
feature had been removed from sljit but was recently added back. It
internally tracks whether the setting operation was an add or a subtract
so that x86 semantics are observed on all architectures.

Loading the carry flag is now handled with an explicit add or subtract
that matches the subsequent usage. This results in expected behavior on
all architectures.
2022-11-15 16:06:55 +00:00
invertego 7ea6cf76e4 build: add mame rgb utils for all architectures
Pull in the files necessary to build MAME RDP for any architecture.
2022-11-15 16:06:55 +00:00
invertego 50dd52bb47 build: guard SSE usage with preprocessor
Reinstate preprocessor guards for SSE code. Constexpr if statements
don't really work because the compiler still requires declarations for
the SSE types and intrinsics even if the body is ultimately discarded.
2022-11-15 16:06:55 +00:00
invertego baccd50410 libco: fix powerpc64 LTO build 2022-11-15 16:06:55 +00:00
invertego e3323e248f nall: detect powerpc64 target 2022-11-15 16:06:55 +00:00
Derek "Turtle" Roe 1622ac00a5 Move Star Fox EX to an unlicensed section 2022-11-11 08:08:58 +00:00
Derek "Turtle" Roe 03462690b1 Update Super Famicom.bml
Add Star Fox EX to the Super Famicom database
2022-11-11 08:08:58 +00:00
Luke Usher 69e5025e7a desktop-ui: implement reload game hotkey/menu option 2022-11-08 13:18:53 +00:00
Luke Usher aa9abd7f68 fc: boost apu output 2022-11-05 22:53:43 +00:00
Luke Usher cc792b71fe desktop-ui: move audio driver/device settings onto a new line
prevents overflowing the window with large device names
2022-11-05 18:19:23 +00:00
encoded-byte 98ccd3c31f fc: namco163 expansion audio 2022-11-03 15:12:04 +00:00
Giovanni Bajo 98bd18757b n64: do not clear FPU flags on LWC1/LDC1/SWC1/SDC1
This commit fixes the remaining failing tests in n64-systemtest.
2022-10-31 07:22:30 +00:00
invertego 4fe7c7d82d n64: replace lround -> round and lrint -> rint
When building with clang for ARM64, the cmath round functions that
return floats compile to a single FRINT instruction. The ones that
return ints are provided by the C runtime, which is problematic on
Windows because the mingw implementations don't set the desired
status bits.
2022-10-30 21:38:48 +00:00
invertego 4e36ce7ad5 n64: raise unimpl instead of invalid for fpu conversions 2022-10-30 21:38:48 +00:00
Giovanni Bajo ba862a2508 n64: FMOVs do not clear flags 2022-10-30 21:38:48 +00:00
Giovanni Bajo fc425940b6 n64: fix conversion bounds off by ones in FPU 2022-10-30 21:38:48 +00:00
encoded-byte c756ae6ea3 fc: increment scanline before comparing on mmc5 2022-10-24 09:31:18 +01:00
encoded-byte 22e71d1d21 fc: correct mmc5 scanline detection behavior 2022-10-24 09:31:18 +01:00
invertego feff5bf56c build: add windows arm64 CI build
Two things are making this a bit more complicated than it ought to be:
- The msys2 clangarm64 package repository is not enabled by default
  because it is still considered 'experimental'
- Cross-compiling requires that you manually override the runtime
  library directory for the 'builtins' lib to be located

Both of these issues are known and should be addressed eventually.
2022-10-21 09:32:44 +01:00
invertego bcb7713415 thirdparty: update sse2neon.h (2b8615319) 2022-10-21 09:32:44 +01:00
invertego 9b1648f6b2 build: pick up windres from environment if defined 2022-10-21 09:32:44 +01:00
Giovanni Bajo f1df1db489 n64: remove spurious round mode change in FPU implementation on arm64 2022-10-19 09:21:04 +01:00
invertego 94764b7fd7 n64: improve unimplemented exceptions on underflow 2022-10-19 09:21:04 +01:00
invertego fbc921ade9 n64: replace cmath functions with arch-specific intrinsics
We cannot rely on specific status flags being set by C standard math
functions.
2022-10-19 09:21:04 +01:00
invertego 6bff023264 n64: prevent compiler reordering with noinline lambda 2022-10-19 09:21:04 +01:00
Giovanni Bajo ac005568be n64: implement correct denormal flush (depending on rounding mode) 2022-10-19 09:21:04 +01:00
Giovanni Bajo 299f25b8d1 n64: correct denormals handling in FCTV_S_D 2022-10-19 09:21:04 +01:00
Giovanni Bajo 0d73fb47d6 n64: reset fpu cause bits for every FPU operation 2022-10-19 09:21:04 +01:00
Giovanni Bajo c0d96da45a n64: add DCTC1/DCTFC1 2022-10-19 09:21:04 +01:00
Giovanni Bajo 0f50ac2810 n64: fix FPU round-to-even using intrinsics 2022-10-19 09:21:04 +01:00
Giovanni Bajo 1c169602dc n64: fix correct roundings and flags for conversion functions 2022-10-19 09:21:04 +01:00
Giovanni Bajo 9e8255d213 n64: implement FPU flags/exceptions for FCVT_* 2022-10-19 09:21:04 +01:00
Giovanni Bajo 9151cf66fc n64: trigger FPU exceptions also via CTC1 2022-10-19 09:21:04 +01:00
Giovanni Bajo 494068fd9d n64: improve generation of FPU flags/exceptions for comparisons 2022-10-19 09:21:04 +01:00
Giovanni Bajo bd65032a88 n64: improve generations of FPU flags/exceptions 2022-10-19 09:21:04 +01:00
encoded-byte d973a52e99 fc: don't reset scanline on nmi 2022-10-18 07:37:42 +01:00
encoded-byte 726ca11ea3 fc: fix mmc5 expansion sound 2022-10-18 07:37:42 +01:00
encoded-byte 3049510000 mia: updated fc mapper 5 default 2022-10-16 21:22:15 +01:00
encoded-byte 84cd3ccd46 fc: code refactoring 2022-10-16 21:22:15 +01:00
encoded-byte 927b9f16aa fc: fix ram banking on mmc5 2022-10-16 21:22:15 +01:00
TascoDLX 0b739bfd36 ares: bump serializer version to 130.3 2022-10-16 15:01:39 +01:00
TascoDLX b49dd6a4ca md: fix cart rom banking (support rom up to 32MB) 2022-10-16 15:01:39 +01:00
TascoDLX c0e8b64b68 m32x: fix rle render 2022-10-16 15:01:39 +01:00
TascoDLX bcfcbd6735 m32x: implement dreq1 & fix irq for pwm 2022-10-16 15:01:39 +01:00
TascoDLX 92424dc97d m32x: fix pwm fifo 2022-10-16 15:01:39 +01:00
Giovanni Bajo e73ec4cac9 n64: emulate VI guardband
There's a "hardware bug" in VI that hides 8 pixels on beginning/end
of each scanline if the scanout begins within the active area.
It is emulated by parallel-RDP but not by our VI implementation.

In a CRT, this is all within the border so it's not visible, and most
games will also respect an even smaller "safe area" anyway. It becomes
visible once the horizontal scanout start is pushed right into the
central area of the screen.
2022-10-12 09:07:32 +01:00
invertego 480343bb98 ares: bump serializer version to 130.2 2022-10-12 09:07:00 +01:00
invertego 477e4c6f12 ms: serialize cartridge ram 2022-10-12 09:07:00 +01:00
Giovanni Bajo 40b8728b1f Avoid codesigning/notarization when building from PRs 2022-10-12 09:04:37 +01:00
Giovanni Bajo 2db3a09162 n64: fix 1-bit precision error in mame RDP
This is another regression introduced to mame RDP wrt upstream
angrylion and parallel-RDP. The color combiner slot "ONE" should use
the value 0x100 for the color components, not 0xff. Notice that
"ONE" in the blender is indeed 0xFF, instead.
2022-10-12 09:04:31 +01:00
invertego ed43ab72b2 nall: fix various hashset issues
- Fix copy assignment operator
- Prevent reserve() from reallocating/rehashing unless capacity is increasing
- Prevent insert() from inserting duplicate entries
- Disable remove() as needs some work and is currently unused
2022-10-09 22:54:33 +01:00
invertego f1b7eb0589 debugger: use hashset to track visited addresses
The "mask" feature in the instruction tracer broke when the N64 address
space was increased to 64 bits. This change fixes it by switching from a
vector to a hashset for tracking visited addresses.
2022-10-09 21:49:23 +01:00
invertego 148eac9346 debugger: store 64-bit address in trace history 2022-10-09 21:49:23 +01:00
invertego 5a58ebdad6 debugger: set per-processor trace history depth
The instruction tracer's default history depth (4) is much too low to
reliably filter out hot loops in processors clocked above a few
megahertz.

Assuming a correlation between processor speed and the path length of
code written for that processor, this change sets the history depth to
the processor's clock speed in megahertz rounded to the nearest power of
two.

This choice is arbitrary, but in practice I've nearly always had to
manually adjust the trace depth to values in the 16-64 range when
dealing with faster processors, so this seems like a good enough
heuristic.
2022-10-09 21:49:23 +01:00
encoded-byte 45667df0f1 fc: fix mmc5 compilation 2022-10-09 21:49:16 +01:00
encoded-byte 817317c5b3 mia: updated famicom database 2022-10-09 21:49:16 +01:00
encoded-byte f3cc8ff52f fc: mmc5 ram management 2022-10-09 21:49:16 +01:00
encoded-byte 6986881a94 fc: improve mmc5 frame detection 2022-10-09 21:49:16 +01:00
invertego 4e4c50be19 gb: fix rtc emulation
- Detect RTC with MBC30 mapper (Pocket Monsters - Crystal Version)
- Read current time before saving it to disk, not after
- Don't clear RTC in power()
2022-10-07 08:30:39 +01:00
Luke Usher f757d496ce Update game-issue-report.md 2022-10-05 09:23:32 +01:00
Luke Usher ef62807b77 a26: fix pixel aspect ratio 2022-10-04 21:44:39 +01:00
PikaSamus 7c17727d1a Correct Game Gear PAR again 2022-10-04 16:00:01 +01:00
PikaSamus 22f2d060d1 Correct Game Gear PAR to 8:7 2022-10-04 16:00:01 +01:00
PikaSamus faf195eba7 Correct ColecoVision PAR to 8:7 2022-10-04 16:00:01 +01:00
PikaSamus 6d22c9e368 Change MSX PAR to 8:7 2022-10-04 16:00:01 +01:00
Luke Usher 97cd14960f ares: release v130.1 (hotfix) 2022-10-03 18:45:51 +01:00
Giovanni Bajo 543111c151 n64: handle vstart/vend RDP coordinate wraparound
Fix Perfect Dark copyright screen in mame RDP. parallel-RDP has the
same bug, but requires a separate fix (to be sent upstream).
2022-10-03 15:49:40 +01:00
Luke Usher 66b60d67d1 recompiler: further tweaks for Intel macOS 2022-10-03 14:24:33 +01:00
Luke Usher 3c99afc0c0 nall: use MAP_JIT on Intel macOS 2022-10-02 23:29:46 +01:00
invertego acc4597407 ruby: improve downscaling with gdi
GDI's default mode of operation for downscaling is optimized for
monochrome images (!) and produces strange artifacts on color images.
This change selects the GDI mode that is essentially nearest-neighbor,
which is not great but is at parity with how it does upscaling.
2022-10-02 22:08:36 +01:00
Luke Usher 19593e157f build: fix broken package detection after the switch to pkg-config 2022-10-02 21:57:40 +01:00
Luke Usher 0c917f3803 ng: read hshrink after sticky-bit parsing 2022-09-30 21:09:48 +01:00
Luke Usher 86db200a23 ares: update version number to v130 2022-09-30 16:09:39 +01:00
Luke Usher 2781365ac3 LICENSE: add MoltenVK license text 2022-09-30 15:57:45 +01:00
Giovanni Bajo a238a7e754 ci: cache MoltenVK builds to speed up CI 2022-09-30 15:12:35 +01:00
Giovanni Bajo 299d211ab1 ci: add signing on Windows 2022-09-30 15:12:35 +01:00
Giovanni Bajo fc2278486e ci: reactivate moltenvk build 2022-09-29 23:12:43 +01:00
Giovanni Bajo f7d5a87667 ci: add macOS notarization 2022-09-29 22:52:27 +01:00
Giovanni Bajo 3e2934529e desktop-ui: fix ares.plist by specifying the package type 2022-09-29 22:52:27 +01:00
Luke Usher ff9afca894 mia: GTROM has 16k chr-ram 2022-09-29 19:42:25 +01:00
Giovanni Bajo 3f002928ed n64: in vulkan backend, fix DP_START.
DP_START shouldn't change after a RDP DMA transfer. This was correct
in the mame-RDP backend but it was wrong in the Vulkan backend.
2022-09-29 14:07:11 +01:00
Giovanni Bajo b124e8a8f0 n64: fix option name in settings change 2022-09-29 14:07:11 +01:00
TascoDLX 0f965050b1 md: support Triple Play cart mappers 2022-09-29 08:24:53 +01:00
Luke Usher b9cd02ddee ng: fix loading of roms with different v-rom naming, fixes aof.
Note that this will cause ADPCM-B roms to be appended to ADPCM-A roms,
 but it's the best we can do without a game database with per-game mappings.
2022-09-28 22:56:03 +01:00
Luke Usher b7198a2334 ng: fix ADPCM-B serialization 2022-09-28 22:48:37 +01:00
Luke Usher 8967e05524 ng: allow ADPCM-B samples to be silenced early 2022-09-28 22:45:33 +01:00
Luke Usher 1b1e7f8f2c ng: implement ADPCM-B audio 2022-09-28 22:45:33 +01:00
TascoDLX 00eb27681e m32x-cd: workaround for Corpse Killer 32X CD gamepad bug 2022-09-28 09:17:48 +01:00
TascoDLX 9ad4b27681 md: add eeprom support for Wonder Boy V (J) 2022-09-28 09:17:48 +01:00
TascoDLX 060eaba2ea sh2: (sh7604) fix serial comm 2022-09-28 09:17:48 +01:00
TascoDLX d75a495fc1 m32x: clear adapter control reg unused bits 2022-09-28 09:17:48 +01:00
Luke Usher f593b12416 ci: switch exclusively to clang for windows builds 2022-09-27 22:24:10 +01:00
Luke Usher 2f3385776d a26: increase scale factor for consistency with other cores 2022-09-27 14:12:05 +01:00
Luke Usher fe8afe05de mia: auto-detect and load common msu-1 filename schemes 2022-09-27 11:57:13 +01:00
Luke Usher 3545360033 Squashed 'thirdparty/libchdr/' changes from b3c1651d0f..e02b3d68eb
e02b3d68eb Merge pull request #84 from scribam/dr_flac
146f076ca7 dr_flac: Version 0.12.39
9882eeaaa2 Bump dr_flac to latest, bump libchdr version to 0.2
44c91c96d4 Bump LZMA SDK to 22.01, need to implement asm optimizations
8cd08c0752 Upgrade to zlib 1.2.12
2781322c4a Merge pull request #78 from snickerbockers/virtual_core_file
40ec221c8a use virtual file i/o API which defaults to a stdio wrapper

git-subtree-dir: thirdparty/libchdr
git-subtree-split: e02b3d68eb759793ab8142376594c840c1194b3e
2022-09-26 18:23:51 +01:00
Luke Usher bd9f52cf8c Merge commit '35453600333f47f6173bf43228e8bc01c2df5a6e' 2022-09-26 18:23:51 +01:00
Luke Usher 3d3513e365 Squashed 'thirdparty/sljit/' changes from 7c37b7ebcf..4de967acd0
4de967acd0 Support memory moving of register pairs on x86 and arm.

git-subtree-dir: thirdparty/sljit
git-subtree-split: 4de967acd03499e7def404eab861e83a0689579b
2022-09-26 18:23:47 +01:00
Luke Usher 5c61c3acbd Merge commit '3d3513e365437e5b16d6c015f55d79d0d2eb2def' 2022-09-26 18:23:47 +01:00
Luke Usher 6a0f2eaf1a ng: tweak overscan 2022-09-26 15:23:12 +01:00
Luke Usher 9422ea5905 md: implement 32x reset register and remove adapterEnable hack 2022-09-26 15:01:30 +01:00
invertego 582fc8f846 sh2: store correct pc in exception frame
The value of PC indicates the fourth byte (second instruction) after the
current instruction. The value stored when an exception raised does not
maintain this four byte offset. Consequently, the RTE instruction must
offset the value it reads back by four bytes.

ares was storing the offset value (and not applying one in RTE) and this
went unnoticed until an encounter with code that manually sets up an
exception frame (in an interrupt handler common to CD 32X games).

This change also fixes the PC stored in the event of an illegal slot
exception, which should be the delayed branch target.
2022-09-26 10:34:27 +01:00
Giovanni Bajo 73893352f7 desktop-ui: show status messages on console too 2022-09-26 00:43:45 +01:00
Giovanni Bajo 47c9ec1f80 desktop-ui: add entitlement to allow JIT as a signed application on mac
Also disable library validation to allow MoltenVK to load. It seems
this is required even if the library is signed. This requires more
investigation.
2022-09-26 00:43:45 +01:00
Giovanni Bajo b482344691 Build universal macOS app on CI 2022-09-26 00:43:45 +01:00
Giovanni Bajo cbdedc9f9c Move update-subtrees.sh into scripts subdirectory 2022-09-26 00:43:45 +01:00
Giovanni Bajo 12a1585ee2 Add script to build an universal binary on mac 2022-09-26 00:43:45 +01:00
Giovanni Bajo 4644bb4494 nall: allow cross-compilation on macOS 2022-09-26 00:43:45 +01:00
Giovanni Bajo a54b551e4d desktop-ui: activate Vulkan by default on all platforms 2022-09-26 00:43:45 +01:00
Giovanni Bajo 30724164be Build MoltenVK on mac builders 2022-09-26 00:43:45 +01:00
Giovanni Bajo 517e0cc454 desktop-ui: mention "GPU acceleration" rather than Vulkan 2022-09-26 00:43:45 +01:00
Giovanni Bajo 2c489cdadd desktop-ui: allow building and bundling libMoltenVK on mac
build
2022-09-26 00:43:45 +01:00
invertego 28a956111d build: ignore -Wdeprecated-non-prototype in zlib 2022-09-25 23:04:25 +01:00
Luke Usher 7115ed9ab5 ng: clip overscan
this will be improved/made configurable later, but for now,
it removes screen-edge artifacts in many games.
2022-09-25 22:30:10 +01:00
invertego 566184f669 md: connect 32x to cart slot in cd+32x mode
This is required for register reads/writes and h/vblank signals to be
handled by the 32x.
2022-09-25 21:42:58 +01:00
TascoDLX 8b5fbf511f md: combine banked & linear carts into standard mapper 2022-09-25 09:57:38 +01:00
TascoDLX c6a6972a75 ym2612: fix volume floor 2022-09-25 09:56:14 +01:00
Luke Usher 59713ea9b1 ng: show the full frame + fix top/bottom blanking 2022-09-24 22:39:08 +01:00
Luke Usher 4e1e3e02bb ng: position sprites relative to the top border rather than line 0. 2022-09-24 16:14:56 +01:00
Luke Usher a26e1ae006 md: apply 32:35 aspect ratio 2022-09-24 15:03:40 +01:00
Luke Usher 160ddb4457 Merge remote-tracking branch 'upstream/master' 2022-09-23 17:17:52 +01:00
invertego 8dda1836ac m32x: expose cart sram through 0x900000... range
The functional part of this change is just a few additional lines in
bus-external.cpp. The rest is refactoring to model the game cart as a
separate entity from the 32x, making it possible to delegate reads and
writes through the 0x900000... range to the cart implementation.

This fixes the corrupted menus and crashes in  Golf Magazine: 36 Great
Holes Starring Fred Couples.
2022-09-23 16:13:30 +01:00
Giovanni Bajo 18884d6aa2 Squashed 'ares/n64/vulkan/parallel-rdp/' changes from 428884dea..fc3121239
fc3121239 Update to 0f7cc6c3a13494a575dbbb977ff4424743b688d7.
d37cf0ed0 Update to 93dfb98643d0dd8094c5739300dfed818502304e.
d433bc4d2 Update to 93d77f713ba0fbcf6bb9e654924e89f808b04398.
22f03bb13 Update to 0f0f9446470f4d0aa018b88ff6280bbc4137b6f6.
482a41deb Update to 07c3d161dbeb78121be5eebdab7c810b72af822a

git-subtree-dir: ares/n64/vulkan/parallel-rdp
git-subtree-split: fc3121239716e3cd99ec63175c9ce5c9d088c033
2022-09-23 12:28:00 +01:00
Giovanni Bajo 1e9c07c803 n64: add RDP crash support to Vulkan backend
Like #769, but for Vulkan.
2022-09-23 12:28:00 +01:00
kev4cards 2c463d0322 n64: fix control stick dead-zone scaling
Scale axially instead of radially
2022-09-23 12:27:40 +01:00
TascoDLX 2c3963c24e z80: fix extended/prefixed instruction timings + behavior
* timing info based on Z80 netlist analysis by Floh

1. Corrected cycle counts for DDCB & FDCB prefixed opcode fetches (was 17, now 16). Instructions cycle counts were increased to compensate for the lost cycle, though this corrects wrong cycle counts for corresponding instructions without a DD or FD prefix (+1 cycle).
2. Removed redundant code for instructions fixed in 1.
3. Changed BIT instructions in DDCB & FDCB blocks to not modify registers (ref: "The Undocumented Z80 Documented").
2022-09-22 07:48:04 +01:00
TascoDLX 3d57bf7914 z80: fix various instruction timings
* based on Z80 netlist analysis by Floh

1. Corrected cycle counts for EX (SP),rr (was 16, now 19) & IM n (was 12, now 8).
2. Reordered cycles for ADD/ADC/SBC HL,rr, RLD/RRD, & LD (rr),n.
3. Removed redundant code for CALL nn & IN (C).
2022-09-22 07:48:04 +01:00
Luke Usher 9fa501cc3a ps1: add simple idle loop detection 2022-09-20 11:10:31 +01:00
Luke Usher c66e3471e0 z80: fix IM0 and simplify IRQ implementation 2022-09-19 10:53:36 +01:00
Giovanni Bajo 17924254a1 GNUmakefile: add error message for incompatible GNU make
While testing parallel-RDP on macOS via MoltenVK, I found out that
a special syntax used in the N64 Makefile to compile parallel-RDP
requires a version of GNU make which is newer than the one that comes
with macOS. To avoid confusion, just error out for now.
2022-09-19 10:24:55 +01:00
invertego 27fe06917e n64: fix numerical instability in Gamepad::read() 2022-09-18 16:33:54 +01:00
invertego 164ef7b678 ps1: clamp f32 to u8 color conversions 2022-09-18 16:33:54 +01:00
invertego 2ad30215df build: fix missing override warning 2022-09-18 16:33:54 +01:00
invertego d4ae964be4 v30mz: fix shift behavior
The presence of undefined behavior (in C++) revealed several
bugs in various shift and rotate instructions. These are
deceptively hard get right without resorting to iteration.
Rather than complicate the implementation further, a few more
are now implemented wtih loops like RCL/RCR.
2022-09-18 16:33:54 +01:00
invertego 228105e6de nall: fix hashset new[]/delete mismatch 2022-09-18 16:33:54 +01:00
Giovanni Bajo 6c5e8ed49e n64: add rdp.command.crashed to serialization 2022-09-18 07:33:21 +01:00
remutro 019287a648 Why did my line endings change 2022-09-17 18:28:42 +01:00
remutro 719dac2dc1 Add missing disc command 0xf - GetParam 2022-09-17 18:28:42 +01:00
Giovanni Bajo abf2ef5832 n64: fix buffer overflows in mame RDP
RDP supports pixel coordinates in range -2048..2047, so we need to
account for up to 4096 spans.
2022-09-17 15:34:56 +01:00
Giovanni Bajo 953a50d827 n64: fix support for interlaced resolutions
The new code was completely wrong for interlaced resolutions, fix it
by changing into a simple filter on the current field.
Moreover, for some reason, the screen was only updated at 30fps.
Do it at 60fps, as both Vulkan and the native Ares screen knows how
to handle that.
2022-09-17 15:34:56 +01:00
Giovanni Bajo 7c116300bc n64: add RDP crash support
There a handful of sequences of invalid commands that can
cause the RDP to crash (it will stop processing commands until hard
reboot). Mame RDP already knows about them and reacts by throwing an
exception, that currently kills Ares because it is not caught.

This commit lets Ares actually emulate the crashed RDP by basically
freezing its command processor. A log is also emitted on console.

This is useful to homebrew developers that can do mistakes while
coding.
2022-09-17 15:34:20 +01:00
invertego cbfd7ed270 m32x: unify interpreter/recompiler sync timing 2022-09-17 15:33:52 +01:00
invertego 78d926b31d m32x: synchronize sh2 processors w/ each other 2022-09-17 15:33:52 +01:00
invertego a4d03c263f sh2: break min_cycles loop on uncached writes 2022-09-17 15:33:52 +01:00
Luke Usher 5283135a49 ps1: fix input issues in many titles 2022-09-16 22:47:19 +01:00
invertego 2c9cf460f3 sh2: initial emulation of sh7604 internal bus
Fix DMA in Metal Head and recompiler implementation of TAS instruction.
2022-09-16 09:13:49 +01:00
LuigiBlood 2bcb236dd6 n64: add dd serialization 2022-09-14 14:14:46 +01:00
LuigiBlood 77ff400bb1 n64: adjust access times as it prevented certain games to work properly 2022-09-14 14:14:46 +01:00
LuigiBlood c87166f9c5 n64: accurate ERR_SECTOR and CUR_SECTOR register info 2022-09-14 14:14:46 +01:00
LuigiBlood 6827540f11 n64: adjust seek times to be more accurate 2022-09-14 14:14:46 +01:00
LuigiBlood 0615773904 n64: finetune disk access times to be closer to real hardware tests 2022-09-14 14:14:46 +01:00
LuigiBlood c73e19bdf2 n64: only start motor state timer after seek is complete 2022-09-14 14:14:46 +01:00
LuigiBlood c0cac55065 n64: use dd command busy state 2022-09-14 14:14:46 +01:00
LuigiBlood e45e82bd19 n64: implement dd motor state management and adjust timings 2022-09-14 14:14:46 +01:00
LuigiBlood 26a7ac35ca n64: change dd seek timings 2022-09-14 14:14:46 +01:00
LuigiBlood 9748b37532 n64: rely on hardcoded block sizes (for retail and development disks) 2022-09-14 14:14:46 +01:00
LuigiBlood 0feacdc6a5 n64: recognize 64dd cic on connect using iplrom and set dd id between retail and dev 2022-09-14 14:14:46 +01:00
LuigiBlood be2495b253 n64: properly recognize and convert development disks 2022-09-14 14:14:46 +01:00
Luke Usher 24762209aa n64: support NTSC-U/NTSC-J/DEV 64DD variants 2022-09-14 14:14:46 +01:00
LuigiBlood 74ec42e889 n64: check and analyze disk region and disk ID 2022-09-14 14:14:46 +01:00
LuigiBlood fa76d1fb16 n64: map DD bus only if DD is enabled 2022-09-14 14:14:46 +01:00
LuigiBlood c437bc2d25 n64: detect errors in disk with heuristics for system disk data and return errors if attempting to read it 2022-09-14 14:14:46 +01:00
LuigiBlood 86ec0d1226 n64: redo drive controller error management 2022-09-14 14:14:46 +01:00
LuigiBlood 12c771e5c9 n64: make sure disk is present before performing disk access commands 2022-09-14 14:14:46 +01:00
LuigiBlood 451d562186 n64: support combo n64 & dd emulation 2022-09-14 14:14:46 +01:00
LuigiBlood aa5efe67ef n64: perform basic system disk area check for conversion 2022-09-14 14:14:46 +01:00
LuigiBlood 1749d4bd9b n64: support already converted mame ndd files 2022-09-14 14:14:46 +01:00
LuigiBlood d21820dab7 n64: add mouse to Nintendo 64DD emulator core 2022-09-14 14:14:46 +01:00
LuigiBlood 51474d86e7 n64: make sure cartridge.rom exists before accessing it 2022-09-14 14:14:46 +01:00
LuigiBlood 7fc641c787 n64: working dd disk save 2022-09-14 14:14:46 +01:00
LuigiBlood 1059725734 n64: add timer to mecha dd commands 2022-09-14 14:14:45 +01:00
LuigiBlood 6396c8c9ac n64: fix disk writing and add comments 2022-09-14 14:14:45 +01:00
LuigiBlood 57647bf62b n64: working 64DD disk conversion, drive read/write, 64DD real time clock 2022-09-14 14:14:45 +01:00
LuigiBlood 5176bfead1 n64: Change PIF ROM loading based on Console Region 2022-09-14 14:14:45 +01:00
LuigiBlood 91281a8247 n64: implement more DD commands including previously undocumented features 2022-09-14 14:14:45 +01:00
LuigiBlood c46beaff32 n64: add rtc.cpp and implement rtc timestamp 2022-09-14 14:14:45 +01:00
LuigiBlood b3c49a4636 n64: working rtc save 2022-09-14 14:14:45 +01:00
LuigiBlood 7ae217bc79 n64: add rtc file pak + commands 2022-09-14 14:14:45 +01:00
LuigiBlood 5d37682c6b n64: Add basic DD interface 2022-09-14 14:14:45 +01:00
LuigiBlood d70cb368de n64: add DD interrupts 2022-09-14 14:14:45 +01:00
Luke Usher 4fcfa471a4 n64: refactor to allow 64dd ipl to work
hard-coded to Retail - Japan for now.
2022-09-14 14:14:45 +01:00
LuigiBlood 01da5ed20d n64: handle 64dd cic in pif power on 2022-09-14 14:14:45 +01:00
LuigiBlood 433f230c9c n64: recognize 64dd ipl rom and cic 2022-09-14 14:14:45 +01:00
Luke Usher 91e49ab940 Revert "gb: correct oam dma startup delay"
This reverts commit e464f45605 as while allowing the test to not crash, it caused regressions in games.
2022-09-14 09:10:29 +01:00
Luke Usher e464f45605 gb: correct oam dma startup delay
from mooneye/acceptance/oam_dma_start
```
 Expected timing (fresh DMA):
; M = 0: write to $FF46 happens
; M = 1: nothing (OAM still accessible)
; M = 2: new DMA starts, OAM reads will return $FF
```

The test still fails, likely due to bad restart behavior,
but it no longer hangs.
2022-09-13 17:41:55 +01:00
Luke Usher e062350552 desktop-ui: check for game load failure for Sega Master System 2022-09-13 17:41:55 +01:00
Giovanni Bajo 74d6e885f6 Implement overflow exception in TRUNC 2022-09-13 15:08:16 +01:00
invertego ec34c02e4f Add nall/float-env.hpp 2022-09-13 15:08:16 +01:00
Giovanni Bajo 0aa84312c5 n64: improve generation of FPU exceptions.
Hook at least standard IEEE-754 exceptions on basic operations. This
should already catch most mistakes done while developing home-brew
games.
2022-09-13 15:08:16 +01:00
invertego 17a654cfc4 32x: reduce recompiler min_cycles 22 -> 19
Required by After Burner Complete
2022-09-13 11:41:49 +01:00
invertego 027a3db94c sh2: fix pc-relative moves in branch delay slots 2022-09-13 11:41:49 +01:00
invertego 38a7c74f28 build: qualify std::move/forward calls 2022-09-13 09:44:41 +01:00
Luke Usher 3147c3c996 6502: fix more SLO variants 2022-09-12 23:04:03 +01:00
Luke Usher d6605625bc 6502: implement remaining undocumented immediate addressing opcodes 2022-09-12 23:02:51 +01:00
Luke Usher e534e56002 sh2: fix broken illegal instruction debug logging
Illegal instructions were being logged after jumping to the exception handler,
causing almost useless debug output
2022-09-11 23:05:41 +01:00
TascoDLX cf9c02e571 ym2612: fix pm vibrato effect 2022-09-10 23:41:21 +01:00
Giovanni Bajo 0483193439 n64: rewrite VI resolution scaling
This should fix all games that had broken resolutions when not using
Vulkan. It also fix garbled graphics appearing on screen during scene
changes, usually at boot.
2022-09-10 17:56:15 +01:00
TascoDLX 6112bcaced ares: bump serializer version (ym2612 fix) 2022-09-10 17:12:19 +01:00
TascoDLX 64ae531ead ym2612: fix the envelope update logic 2022-09-10 17:12:19 +01:00
Luke Usher e90c318c0e md: 32X interrupt control register returns 0 in the upper bits 2022-09-09 00:22:04 +01:00
Luke Usher a4551216e9 md: better fix for 32x overscan: this one fixes bottom border also 2022-09-08 21:08:53 +01:00
Luke Usher 2e38fa5fc6 md: prevent 32x from incorrectly writing over megadrive borders
fixes overscan issues in a few titles
2022-09-08 20:50:01 +01:00
Raphael Assenat e2b96c8bab ms: Add support for the Mega Mouse
This pull request adds support for the Sega Mega Mouse. As the name implies,
this mouse was released for the MegaDrive, but as it is the case for 3/6 Button
controllers, the Mega Mouse can be safely connected to a Master System console and
even used, provided that the game software is programmed accordingly.

To my knowledge there are no official games on the SMS with mouse support, but there
is one demo I released (SMS-A-Sketch) which supports the Mega Mouse, and I have
an unreleased game that also supports it. I think it would be great to have ares
support the Mega Mouse on SMS as the only alternative at this point is to use
real hardware.
2022-09-08 09:19:53 +01:00
Raphael Assenat 4c3c07eb38 md: Fix a typo 2022-09-08 09:19:25 +01:00
Luke Usher 3e7ca5baec ms: fix incorrect hcount calculation
The VDPTEST still doesn't pass for any hcounter tests.
Inserting debug prints to print the hcounter value for every possible x coord shows correct output.
I suspect there are still some core timing issues in the z80...
2022-09-07 23:00:17 +01:00
TascoDLX c74700f35d z80: proper reset logic + implement for md 2022-09-07 08:15:52 +01:00
TascoDLX 368578d736 z80: correct timings for RET, LD (IX+d),n & LD (IY+d),n 2022-09-07 08:15:52 +01:00
TascoDLX 65d9640b20 ym2612: various improvements & fixes
1. Envelope gen clean-up + emulation of odd behaviors (see inline comments)
2. SSG-EG fixes -- mode 7, control register behavior
3. LFO PM (vibrato) fix + calc tweak
4. Clock fixes for envelope, LFO, timer B
2022-09-07 08:15:52 +01:00
Luke Usher 836f3fc976 msx: add database entry for Batman (Japan) 2022-09-06 22:24:19 +01:00
Luke Usher 5636e2b0f6 ruby: use glXSwapIntervalEXT where available 2022-09-06 18:53:45 +01:00
Luke Usher 37bc375c64 msx: distinguish between ASC16 and the r-type specific variant 2022-09-06 14:25:12 +01:00
Luke Usher 50467b7e6d Update README.md 2022-09-06 10:04:40 +01:00
Raphael Assenat dc37e934e6 md: Add support for the Mega Mouse 2022-09-06 09:10:24 +01:00
Raphael Assenat 21e5daebfc N64: Make the "Nothing" controller type in the menu work as expected
At the moment, the game sees a controller in all ports, even after
the controller type is changed from Gamepad to Nothing. (the Gamepad
instance still lives and still gets called...)

I worked around this by making sure that port->allocate gets called,
even when the selection is "Nothing". The code in port.cpp simply
does not allocate anything in this case.

For most systems and in most practical cases this probably does
not matter. But now the raphnet N64 adapter manager ROM correctly
reports "Not conneted" in ports set to Nothing.
2022-09-06 09:08:25 +01:00
Raphael Assenat 8f579b1993 n64: Leave PIF RAM as-is when no data was received
When the ->comm method returns with the invalid bit set, it means no
data was received. This happens for instance when sending invalid
or proprietary commands to a standard controller which does not answer.

When there is no answer, the PIF emulation code sets bit 7 of the receive
length byte to flag this error.

Since no data was received, the original (filler) bytes should be left
as-is in PIF RAM. This is what the hardware appears to do.

This fixes code that checks if the receive buffer got overwritten instead of
inspecting bit 7 for errors.
2022-09-06 09:08:25 +01:00
Raphael Assenat ed336af513 Fix indentation 2022-09-06 09:01:34 +01:00
Raphael Assenat 03186eb4d3 desktop-ui: Document command-line options and add --help
Ideally I think one should not need to read the source code to learn
that ares accepts command-line options and what those options are.

I wish I had known earlier that I could pass --system MSX when loading
a ROM directly, it would have saved me a lot of time. I had tried --help,
but it just opened the application window...
2022-09-06 09:01:34 +01:00
Luke Usher 972495df89 gba: fix eeprom saves for real this time 2022-09-05 23:46:59 +01:00
Luke Usher 3366b1dc6c mia: if no size is specified in the manifest, use on-disk size 2022-09-05 23:46:30 +01:00
Luke Usher 2c86419dd8 Revert "gba: fix eeprom saves (no longer zero bytes)"
This reverts commit d5c094e9e8.
2022-09-05 22:40:41 +01:00
Luke Usher 0e30732950 Revert "gba: eeprom size must only come from manifest or auto-detect, not file size"
This reverts commit f0598aaeb3.
2022-09-05 22:40:41 +01:00
Luke Usher 0fb5569c6b Revert "gba: don't re-create the eeprom array: it's already large enough"
This reverts commit f289cdd08a.
2022-09-05 22:40:40 +01:00
Luke Usher f289cdd08a gba: don't re-create the eeprom array: it's already large enough 2022-09-05 22:19:40 +01:00
Luke Usher f0598aaeb3 gba: eeprom size must only come from manifest or auto-detect, not file size
fixes #717
2022-09-05 19:46:02 +01:00
Luke Usher 1a498d64c9 ci: remove broken subtree split workflow 2022-09-05 15:48:39 +01:00
Luke Usher c2f58d1c79 Update split-subtrees.yml 2022-09-05 15:43:27 +01:00
invertego 3d826f5b26 nall: always pass by reference to make_string()
Many specializations of stringify store a reference to the wrapped
value. Therefore, passing arguments to make_string() by value can be
disastrous if the compiler does not perform copy elision and stringify
stores a reference to a variable that goes out of scope when
make_string() returns.
2022-09-05 14:20:55 +01:00
invertego 2bb95a13cb build: detect when gcc is an alias for clang
Detect build environments where 'g++' is just an alias for 'clang++'.
Example: MSYS2's Clang64 environment. This avoids the need to manually
override compiler detection.
2022-09-05 09:04:39 +01:00
invertego 1de21e178c build: pass through target from top-level makefile 2022-09-05 09:04:11 +01:00
Raphael Assenat cde0e1603d ms: Implement megadrive 3 and 6 buttons pads
Master system ports are compatible with megadrive controllers and
those can be used directly to play many original master system
games.

However MD controllers can be fully supported (i.e all buttons
working) if the game software is programmed to do so.

While really only useful on real hardware, there are game patches to
enable the Start button on MD controllers. But it's also possible
to make patches that use additional buttons or code full support
for Megadrive controllers in a homebrew title.
2022-09-04 10:44:34 +01:00
invertego 6fe063815c n64, ps1: stop video thread immediately on unload
The N64 and PS1 cores set custom Screen:refresh() callbacks that run on
the video thread and have meaningful dependencies on core state. It's
not safe to unload components from beneath them, so the video thread
should be stopped before any unloading occurs.
2022-09-04 10:44:03 +01:00
invertego b527a33b85 nall: make posix impl of thread::join idempotent
ares uses nall::thread with the assumption that calling join() multiple
times on the same thread will have no harmful effects. This was true of
the Windows implementation but not of the POSIX one.
2022-09-04 08:55:44 +01:00
Raphael Assenat 29a9c53a62 ms: Fix writes to controller port 2
Corrects an error in the original pull request which sent incorrect
data to port 2. The Sports Pad now also works in port 2.
2022-09-04 08:55:00 +01:00
CasualPokePlayer 56fe0d8269 Correct types for screen.hpp
Fixes some memory leaks due to delete being used instead of delete[]
2022-09-03 23:47:11 +01:00
invertego dc28723d52 nall: fix assignment operators
Almost all of the assignment operators in nall leaked resources, failed
to handle self assignment, or both.
2022-09-03 12:32:01 +01:00
Luke Usher 36af497fdf nall: add support for ccache
Use ccache ccache=true is passed to make
See https://ccache.dev/ for further details.

On msys/mingw, the ccache package is `mingw-w64-x86_64-ccache`
2022-09-02 22:56:48 +01:00
Luke Usher d5c094e9e8 gba: fix eeprom saves (no longer zero bytes)
mia cannot save a file when the manifest size is zero.
instead, use the largest known eeprom size + 1 as a default.

The +1 signifies that we should auto-detect the real size of the eeprom
and the large size makes sure mia creates a file on disk large enough.

For games without a database entry, the eeprom size be larger on disk
than is actually used, but it's better than completely broken saves.

Note that even with this, some games will require database entries,
but most should work now.
2022-09-02 22:38:36 +01:00
Luke Usher 6adc70cbc8 input: prevent polling more than necessary
This prevents slowdown in games that poll games multiple times per-frame.
5ms was chosen as ares already has a 5ms limit higher up the chain.

For me, Advanced Wars 2 (GBA) jumped from 50-55fps to 65-68 with this change
2022-09-02 20:51:03 +01:00
invertego 2e385844d0 sfc: fix performance ppu override detection 2022-09-02 00:03:14 +01:00
invertego 7e48079a46 pce: performance vdp timing overrides
Following the precedent set by the SFC performance PPU, override the
timing of the PCE performance VDP for a handful of problematic games.

All of these games already work fine with the accuracy VDP (enabled with
the "pixel accuracy mode" video setting) which does not and never will
contain contain game specific logic.

Affected games:
- Kore ga Pro Yakyuu '89
- Kore ga Pro Yakyuu '90
- TV Sports Baseball
- TV Sports Football
- TV Sports Hockey
- Valkyrie no Densetsu
- Victory Run
2022-09-01 16:16:56 +01:00
Giovanni Bajo f9eb9304f0 README: simplify build instructions 2022-09-01 08:13:48 +01:00
Giovanni Bajo c3eb8bc49e n64: improve exceptions for invalid instructions in cop1/cop2
Also implement MFC2/MTC2 and friends which seems to exist at some
level (though they just access a latch).

Fixes new set of tests in n64-systemtest.
2022-09-01 07:39:55 +01:00
invertego 8759a7d3e8 n64: precise rsp block invalidation
- The primary lookup table is direct addressed
- The secondary lookup table is indexed by hash of code block contents
- IMEM invalidation is tracked at 64-byte granularity and used to
  evict primary lookup table entries
- The secondary lookup table is only pruned on a full code cache flush
- Only executed instructions are hashed, so the code cache no longer
  experiences unbounded growth
- Code blocks can now wrap around the end of IMEM
- generic::recompiler now supports aborting recompilation (required by
  by an earlier version of this change)
2022-08-30 09:28:37 +01:00
Raphael Assenat a785ce924b msx: auto-connect the Arkanoid Vaus Paddle 2022-08-30 09:17:40 +01:00
Raphael Assenat 938b1647b0 msx: Implement the Arkanoid Vaus Paddle
This adds support for the Taito Arkanoid Vaus Paddle.
2022-08-30 09:17:40 +01:00
Raphael Assenat 6abe6bfb19 msx: Implement joystick port 2
On MSX, both joysticks are read through a common port (PSG port 14).
Which joystick is being accessed is selected through bit 6 in PSG
port 15. In other words, the ports inputs are multiplexed.

This pull request adds a simple concept of controller multiplexer
which the PSG IO code can call whenever port 14 is read.

PSG port 15 also controls the level and direction of some joystick
pins, but those are not multiplexed. This pull request corrects how
writes to port 15 are handled and organizes output bits in a predefined
order so controller implementation do not need to know which port they
are connected to. This paves the way for more advanced peripherals
controlled through those outputs, such as the Taito Arkanoid Vaus Paddle.
2022-08-30 09:17:21 +01:00
Raphael Assenat d22fae0cae ay38910: Keep a copy of the last data written to IO ports 2022-08-30 09:17:21 +01:00
Luke Usher 4effa2b6d2 ms: auto-connect sports pad for games that require it 2022-08-29 23:28:10 +01:00
Luke Usher e6dfd5ee74 ms: auto-connect paddle controller for the games that require it 2022-08-29 23:00:35 +01:00
Raphael Assenat a5966490c9 ms: Add support for the Sports Pad
This adds support for the Sports Pad, a trackball controller for Master System. Input
is done using a Mouse or a trackball (best).

Tested with Sports Pad Soccer and a homebrew test ROM.
2022-08-29 22:08:11 +01:00
Raphael Assenat f5f75cdeef ms: Expose output signals to controller port
The write method is now actually called when TR/TH level and direction
IO port is written to. Also redefined the write method bit width (4) and
document which bit is used for what.

This will allow emulation of controllers which uses the TH line as a
control output. This includes the Export Paddle, the Sports Pad, and
Megadrive controllers.
2022-08-29 22:08:11 +01:00
Raphael Assenat a6209af97b ruby: xlib mouse double event workaround
When the mouse is grabbed, the current implementation hides the
pointer and centers it on the screen.

When the mouse is polled, its relative motion is determined by how far it
has moved from the center of the screen, then it is moved back to the
center by calling XWarpPointer().

XWarpPointer generates an event resulting in an additional poll, which then
sees no movement at all (since the pointer is now centered) and therefore
resets the relative motion values to zero.

If the above reset occurs before the controller code has had the chance to
access the relative motion values, the motion never reach the game. This
works around this issue using a flag to ignore the next event if the
mouse is still centered on the screen.
2022-08-29 22:07:06 +01:00
Luke Usher 93e24926ae mia: add partial iNES 2.0 support
just enough to detect additional mapper types and games with additional CHR RAM for now.
2022-08-27 14:04:04 +01:00
Luke Usher 6f3997dc38 ms: fix an issue where the GG bios failed to detect SMS mode. 2022-08-25 23:17:52 +01:00
Luke Usher b380834c0e ms: fix Game Gear bios support (bios is optional) 2022-08-25 23:00:32 +01:00
Luke Usher 9e551be17a ps1: improve gamepad behavior when receiving invalid commands 2022-08-25 21:47:31 +01:00
Luke Usher d77c6f0788 ms: various vdp improvements
1. Nametable address is not a latched register, it takes effect immediately
2. Sprites should still be processed & overflow is still set during display disable
3. Hcounter -94 offset is incorrect for ares, as we already have clock 0 = pixel 0.
2022-08-25 14:16:38 +01:00
Luke Usher a1df486779 ms: fully decode port $3e on GameGear + allow $3f writes (latches h-counter)
Despite the Game Gear having no physical controller ports, writes to the IO control register still need to be emulated, and thus the ports need to be present in ares, such that latching h-counter on 0-1 transition is still possible.
2022-08-25 09:51:06 +01:00
Luke Usher cdedb9b0f5 sn76489: fix additional data writes to noise channel
fixes broken audio in Micro Machines on the Master System
2022-08-24 23:44:23 +01:00
Luke Usher 9ff41ed45a ms: initialize ram to zero
Fixes hang in Shanghai II (Japan) for Game Gear
2022-08-24 22:01:32 +01:00
Luke Usher 56aa5dac0d ms: fix precision loss when latching hcounter
Internal Hcounter values (actually clock cycles) are larger than the range of a u8.

The actual Master System h-counter (0x00-0xff range) is calculated later.
2022-08-24 16:36:07 +01:00
Luke Usher ebde92c891 mia: add database entry for Chase H.Q (USA)
This is another Game Gear release that targets SMS mode.
2022-08-24 16:21:39 +01:00
Luke Usher 7dc55eeb54 mia: add database entry for Taito Chase H.Q (Japan)
This is another Game Gear release that targets SMS mode.
2022-08-24 14:10:01 +01:00
Luke Usher ec4e0050e7 sms: fix a crash when using a Game Gear in SMS mode. 2022-08-23 20:25:15 +01:00
Luke Usher 306d23f38b mia: game-gear doesn't support PAL/50hz mode, use NTSC-U instead 2022-08-23 16:49:50 +01:00
Luke Usher fa3dfa38cd ps1: [SPU] increase precision of volume input to amplify function
fixes pitch modulation, especially obvious in J-E-N-O-V-A from FF7.
2022-08-22 23:36:56 +01:00
Luke Usher a0601f1c79 Update issue templates 2022-08-22 15:29:37 +01:00
Luke Usher 19b56bc118 Update issue templates 2022-08-22 15:28:14 +01:00
Luke Usher 2f12a72cad Update issue templates 2022-08-22 15:26:23 +01:00
Luke Usher ed0fe5599f desktop-ui: allow hotkeys when unfocused if "allow input while focus is lost" is enabled 2022-08-20 21:33:26 +01:00
invertego 081408e961 md: latch bus request on reset 2022-08-20 19:44:10 +01:00
Luke Usher 56d6488b3d 6502: add some undocumented opcode variants
fixes Aladdin and Super Cards on nes/fc
2022-08-20 00:05:55 +01:00
Luke Usher 85f1fb6b7f gb: more DMG mode fixes;
fixes titlescreen in Pokemon Red/Blue/Yellow on GBC in DMG mode.
2022-08-18 22:40:57 +01:00
Luke Usher 34d6d465c4 gb: handle differences with bgEnable in DMG mode on CGB 2022-08-18 22:40:56 +01:00
Parashoe fcef806553 n64 setting: "Disable Video Interface Processing" 2022-08-18 13:54:49 +01:00
Luke Usher 61258a7063 gb: fix an oops in KEY0 2022-08-17 11:35:48 +01:00
Luke Usher b1d216b8af gb: allow CGB to run in DMG mode
This is not fully hardware accurate yet (lots of CGB only registers remain enabled)
but most of the rendering issues should be resolved now.
2022-08-17 11:16:22 +01:00
Luke Usher c53023e6c8 gb: fixes to mbc2
1. ram is mirrored between 0xa000-0xbfff, not 0xa000-0xa1ff
2. ram & bank registers are mapped through 0x0000-0x3fff, using only bit.8 to select between them
2022-08-17 00:23:00 +01:00
Luke Usher 637aa19a72 gb: display is disabled while stopped 2022-08-17 00:10:43 +01:00
Luke Usher 2cf4d8cac8 gb: don't increment div when stopped 2022-08-17 00:10:29 +01:00
Luke Usher 0071e8a7d4 gb: fix div initial value (validated via mooneye tests) 2022-08-17 00:10:15 +01:00
Luke Usher d546f147c3 hiro: remove DirectDraw backend
DirectDraw has not been updated by Microsoft since DirectX7.
It has been deprecated/not recommended for use since DirectX8, released in 2000.
2022-08-16 22:01:05 +01:00
Luke Usher b03a942bf4 desktop-ui: simplify some code paths by removing lesser-used functions
1. Grouping systems by vendor in the system menu can no longer be disabled.
2. It is no longer possible to hide emulator cores from the menu
3. It is no longer possible to use the higan file select dialog; only the native OS file picker is available.
2022-08-16 21:57:29 +01:00
Raphael Assenat 23416eae32 Add support for the Japanese HPD-200 Paddle
This makes games requiring a Paddle, such as Megumi Rescue,
playable with an analog stick, or using adapters USB adapters
supporting the HPD-200 Paddle.

"Prefer Japan" should be selected in tools->Boot Options before load
otherwise the game will expect the "Export Paddle" which is not
compatible.
2022-08-16 10:30:47 +01:00
invertego 2ade0e39de m68000: fix memory read order for A/SBCD, ADD/SUBX
This is especially important when both operands reference the same
register, as the first predecrement should affect the second read.
2022-08-15 13:11:26 +01:00
Chris Jalbert 62930f8da8 accidentally excluded two important components - fixed 2022-08-14 18:21:33 +01:00
Tobias Jakobi be1f424398 build: use pkg-config in ruby Makefile
Checking for libraries in /usr/lib does not work reliably, e.g.
on a x86-64 Gentoo the 64-bit libraries are located in /usr/lib64.

Use pkg-config to detect libraries, which should work much better
on any modern Linux distro and also covers Debian's multi-arch
setup.
2022-08-14 17:21:18 +01:00
invertego 003afbbb58 m68000: fix divs/divu negative flag 2022-08-14 16:58:39 +01:00
Chris Jalbert 3010c8a8c9 Issue 521: Basic Build Instructions 2022-08-14 16:58:28 +01:00
invertego 4a935893d2 md: preserve bank register on apu reset 2022-08-14 16:56:25 +01:00
Giovanni Bajo 32096b8e85 n64: use Neon instructions also in mame RDP 2022-08-11 22:23:43 +01:00
Luke Usher 3142bd3aef n64: change rsp.ipu.pc to u16 from u12
Using a native data type significantly improves performance of ares::Nintendo64::RSP::instructionEpilogue, making it jump from ~9-10% of cpu time to 5-6% of cpu time during execution
2022-08-06 23:56:51 +01:00
Luke Usher 9985c693bd n64: use xxh3 instead of crc32 for rsp cache
This is a significantly faster and stronger algorithm than crc32
2022-08-06 23:37:08 +01:00
Luke Usher 81e15695c8 n64: a little more performance tuning 2022-08-06 17:38:48 +01:00
Luke Usher f486867292 n64: move some function implementations from icache.cpp to cpu.hpp
Identified via profiling: this improves performance due to better compiler optimisation.
2022-08-06 17:38:48 +01:00
Giovanni Bajo ffa7040b6f n64: use sse2neon to emulate RSP with SIMD instructions on ARM64 2022-08-06 14:43:05 +01:00
Giovanni Bajo 247a269054 thirdparty: vendor sse2neon.h (a951d8760) 2022-08-06 14:43:05 +01:00
invertego 50b2a8f3ab mia: fix 32x eeprom 2022-08-05 09:27:59 +01:00
Luke Usher f1e36f2775 n64: split rsp recompiler cache into 256-byte sized blocks
Significantly increases the cache hit ratio due to games utilising multiple small ucode programs.
2022-08-04 20:14:36 +01:00
FitzRoyX 997fda03fe md: add sram entry for psy-o-blade 2022-08-04 15:52:19 +01:00
Luke Usher c6ecbe81b2 n64: restore old recompiler invalidate behavior 2022-08-04 09:13:49 +01:00
Luke Usher 9c9ef927d7 desktop-ui: re-order systems by vendor in the menu 2022-08-02 23:04:07 +01:00
Luke Usher 029ae18514 Squashed 'thirdparty/libchdr/' changes from 045f2a7f23..b3c1651d0f
b3c1651d0f Merge pull request #80 from scribam/vita
e802754335 vita: fix core_fseek/core_ftell

git-subtree-dir: thirdparty/libchdr
git-subtree-split: b3c1651d0fee6543968d916cb4e39c9b184c231f
2022-08-02 20:53:54 +01:00
Luke Usher dcfce18d7f Merge commit '029ae18514c23e538f79126326e4244e79f648ff' 2022-08-02 20:53:54 +01:00
Luke Usher 295c729ecf Merge commit '43e0dd770d5e32ec2b4794a19281e2aa22f45bd1' 2022-08-02 20:52:59 +01:00
Luke Usher 43e0dd770d Squashed 'ares/n64/vulkan/parallel-rdp/' changes from 808a89d23a..428884deab
428884deab Update to e6cf0e5ca257135acbcacfbdacd7cd3fdf3fb408
6879314041 Update to 9dacdc9d73c5febda2448fec9b393034fa5d9fe3

git-subtree-dir: ares/n64/vulkan/parallel-rdp
git-subtree-split: 428884deab9571cc04be756960e3649f678c8f63
2022-08-02 20:52:59 +01:00
Luke Usher 6e9c08b491 n64: fix an issue where invalidateRange was called with incorrect inputs 2022-08-02 19:50:11 +01:00
Luke Usher 1808e3f50c n64: make the recompiler invalidate single blocks rather than entire pools 2022-08-02 09:40:25 +01:00
Luke Usher 8f39e06900 Squashed 'thirdparty/libchdr/' changes from 6eeb6abc4..045f2a7f2
045f2a7f2 Merge pull request #74 from 2weak2live/raw
e23f32f37 Add support for reading LZMA and FLAC hunks in non-CD CHDs.

git-subtree-dir: thirdparty/libchdr
git-subtree-split: 045f2a7f23f5ac10c0122f6f56e42023dfb71e2a
2022-08-01 16:12:29 +01:00
Luke Usher 7742b49289 Merge commit '8f39e06900d298526f86b9c808520bd6236d4475' 2022-08-01 16:12:29 +01:00
Luke Usher 4750a7f224 Squashed 'thirdparty/sljit/' changes from 761d48d2b..7c37b7ebc
7c37b7ebc Rework x86-32 stack layout
09a58361f Improve sljit abi calling convention
58e36c06a Change skip checks to a macro
ac445a3ef Add sljit specific register argument calling convention
a6c8e5bf7 Remove fast call support on x86-32
a3785b330 Fix x86 mem address encoding
2f8e5c2f2 Implement ARM unaligned support
3e86c50e9 Fix PPC logical or/xor with flag set
d8af3f91b Remove sparc support
3055f116b Fix test50 alignment
41cb888d8 Start supporting unaligned memory access

git-subtree-dir: thirdparty/sljit
git-subtree-split: 7c37b7ebcf17a80f606100ae88e744dff22befe6
2022-08-01 16:12:20 +01:00
Luke Usher ff78815e90 Merge commit '4750a7f224641df4c98038c32a50fb92e8facc11' 2022-08-01 16:12:20 +01:00
Luke Usher 00a5c6864e Squashed 'ares/n64/vulkan/parallel-rdp/' changes from af9b4b00f..808a89d23
808a89d23 Update to f187ecba0df48e3185ac61e5516c34f903c7a095
8a2986a64 Update to a691960e8d4f72fea6a384fd89881cbdb8a78a0b
31e97d2f2 Update to 4137ff0771ca473b7610a1c8ea307d7a5141aee4

git-subtree-dir: ares/n64/vulkan/parallel-rdp
git-subtree-split: 808a89d23ae193e003b3e54de61a8172582168d1
2022-08-01 16:12:13 +01:00
Luke Usher a38572199d Merge commit '00a5c6864e20cd9c3a556e477abd2eb063c750a2' 2022-08-01 16:12:13 +01:00
Giovanni Bajo bcd501edf6 n64: fix AI DMA enable bit handling
Fix again Twisted Edge, that was recently broken when we reworked AI DMA
2022-08-01 09:05:40 +01:00
Giovanni Bajo 8d1ad79fdb n64: refactor AI::sample to always return a sample 2022-08-01 09:05:40 +01:00
invertego b2db7f16f6 ng: clean up screen thread on unload 2022-08-01 09:05:05 +01:00
Luke Usher 080b53a652 Revert "desktop-ui: optimize for generic x86-64-v2 rather than nehalem"
because Ubuntu 20.04 still has outdated GCC that doesn't support this flag;
people who get a performance hit from optimising for nehalem will just need to
self compile.

This reverts commit f7657dca4f.
2022-07-31 23:31:38 +01:00
Luke Usher 2b9fcab30f ci/desktop-ui: disable lto by default
The added compile time is not worth it when for many users this harms performance, rather than improving it.

TODO: Why?
2022-07-31 22:11:42 +01:00
Luke Usher 5565d2def4 attempt to fix ci builds for macOS 2022-07-31 11:27:09 +01:00
Luke Usher 9aa05bcbe3 nall: more LTO tuning 2022-07-30 19:26:51 +01:00
Simon Eriksson e0434ca82b n64: Add missing variables in RDP serialization 2022-07-29 23:53:52 +01:00
Luke Usher 9c5ecf52ce nall: tweak LTO settings for better performance in compiled builds
GameBoy core +10 FPS on average in my testing
2022-07-29 23:19:03 +01:00
Luke Usher 6d890244c1 desktop-ui: enable lto by default but allow it to be disabled with lto=false 2022-07-29 23:18:18 +01:00
Luke Usher f7657dca4f desktop-ui: optimize for generic x86-64-v2 rather than nehalem 2022-07-29 23:03:33 +01:00
Luke Usher eda2918f58 ng: fix games with non-power-of-two croms 2022-07-28 23:33:48 +01:00
Luke Usher d75c13107c ng: avoid syncing with the YM2610 more than necessary 2022-07-27 22:10:35 +01:00
Luke Usher 1a5984be70 ng: preliminary support for ADPCM-A channel 2022-07-27 14:53:39 +01:00
FitzRoyX e1711eb28a sfc: fix typo that broke bg4 2022-07-27 09:20:41 +01:00
Giovanni Bajo 1a564fa93e n64: fix AI IRQ
The AI IRQ should be generated when a buffer starts playing, not when
it finishes playing, as verified by hardware tests.

Fixes the audio in Hey Pikachu and possibly other games.
2022-07-26 22:22:15 +01:00
Luke Usher 6118facaf2 ng: refactor rom loading
Fixes Twinkle Star Sprites + possibly others
2022-07-23 22:34:39 +01:00
Luke Usher d52a3b9dfc ng: fix loading of roms that use .ep instead of .p for program roms 2022-07-22 23:16:26 +01:00
Luke Usher 38495197d2 ng: remove leftover debug logging 2022-07-22 23:09:44 +01:00
Luke Usher dd6a448bc4 ng: fix FM/SSG audio playback
ADPCM playback is still unsupported, so a lot of audio will be missing.
2022-07-22 22:56:57 +01:00
Luke Usher 1cea9ad1d9 mia: cleanup old famicom-disk source file 2022-07-22 20:02:56 +01:00
remutro 14c9dc04fd Rename all instances of Famicom Disk to Famicom Disk System 2022-07-22 14:35:15 +01:00
remutro 9e983e720f match emulator name with expected mia media definition to fix auto-detection of fds 2022-07-22 14:35:15 +01:00
Luke Usher b2dd52c0a4 ps1: fix a crash when using out of range vram co-ordinates 2022-07-21 22:24:36 +01:00
Luke Usher 9a3d949fc2 ms: implement support for NTSC-U/NTSC-J Game Gear variants 2022-07-21 21:43:46 +01:00
invertego 00819b70c0 a26: fix buffer overflows 2022-07-18 01:31:27 +01:00
Ralakimus cd83a939e8 32X: Implement preliminary Sega/SSF2 mapper support (see #628) 2022-07-15 13:51:32 +01:00
1457 changed files with 249521 additions and 169244 deletions

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
---
name: Bug report
about: Report a bug *not* relating to game compatibility
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
@@ -0,0 +1,21 @@
---
name: Game Issue Report
about: Report an issue running a specific game in ares
title: "[system] Game"
labels: bug
assignees: ''
---
Before submitting an issue, please use the search to make sure an issue doesn't already exist, you should also make sure your rom is not a bad dump, by comparing against the hashes in the No-Intro (Cartridges) or Redump (CD-ROM) databases.
**Describe the issue**
A clear and concise description of what the bug is.
**Rom Information**
Specify the impacted rom filename and any associated hashes (sha256 preferred)
```
file: Some Game (REGION).ext
sha256: <hash>
```
+105 -16
View File
@@ -13,17 +13,43 @@ jobs:
- ares
platform:
- name: windows
os: windows-latest
compiler: g++
shell: 'msys2 {0}'
msystem: mingw64
msys-env: x86_64
- name: windows-clang
os: windows-latest
compiler: clang++
windres: windres
shell: 'msys2 {0}'
msystem: clang64
msys-env: clang-x86_64
install: mingw-w64-clang-x86_64-clang
- name: windows-arm64
os: windows-latest
compiler: clang++ --target=aarch64-w64-windows-gnu --sysroot=/clangarm64 -resource-dir=/clangarm64/lib/clang/$(basename "$(clang++ -print-resource-dir)")
windres: windres --target=aarch64-w64-windows-gnu
shell: 'msys2 {0}'
msystem: clang64
install: mingw-w64-clang-x86_64-clang mingw-w64-clang-aarch64-clang
- name: windows-msvc-x64
os: windows-latest
compiler: clang++
windres: llvm-rc
shell: bash
msvc-arch: x64
- name: windows-msvc-arm64
os: windows-latest
compiler: clang++ --target=aarch64-w64-windows-msvc
windres: llvm-rc
shell: bash
msvc-arch: x64_arm64
- name: windows-cl-x64
os: windows-latest
compiler: cl
windres: rc
shell: bash
msvc-arch: x64
- name: windows-cl-arm64
os: windows-latest
compiler: cl
windres: rc
shell: bash
msvc-arch: x64_arm64
- name: macos
os: macos-latest
compiler: clang++
@@ -43,15 +69,74 @@ jobs:
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.platform.msystem }}
install: make mingw-w64-${{ matrix.platform.msys-env }}-toolchain
install: make ${{ matrix.platform.install }}
- name: Install Linux Dependencies
if: runner.os == 'Linux'
run: |
sudo apt-get update -y -qq
sudo apt-get install libsdl2-dev libgtksourceview2.0-dev libgtk2.0-dev libao-dev libopenal-dev
- uses: actions/checkout@v2
sudo apt-get install libsdl2-dev libgtk-3-dev libao-dev libopenal-dev
- name: "macOS: Import Certificate"
if: runner.os == 'macOS' && github.event_name != 'pull_request'
uses: devbotsxyz/import-signing-certificate@2ac4f44d28045073d23153256efbb4c4b2d8aa22 # Don't use rolling branch for security reasons
with:
certificate-data: ${{ secrets.MACOS_CERTIFICATE_DATA }}
certificate-passphrase: ${{ secrets.MACOS_CERTIFICATE_PASSPHRASE }}
keychain-name: ares-macos-keychain
keychain-password: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
- name: Checkout source code
uses: actions/checkout@v2
- name: "macOS: recover cache"
if: runner.os == 'macOS'
uses: actions/cache@v3
env:
cache-name: moltenvk
with:
path: thirdparty/MoltenVK/MoltenVK
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('thirdparty/MoltenVK/HEAD') }}
- name: Install macOS Dependencies
if: runner.os == 'macOS'
run: |
brew install make ninja
echo "MAKE=gmake" >> $GITHUB_ENV
pushd thirdparty/MoltenVK
./build-moltenvk.sh
popd
- name: Set up MSVC environment
if: matrix.platform.msvc-arch != ''
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.platform.msvc-arch }}
- name: Make
run: make -j4 -C desktop-ui build=optimized local=false lto=true compiler=${{ matrix.platform.compiler }}
if: runner.os != 'macOS'
run: ${MAKE:-make} -j4 -C desktop-ui build=optimized local=false compiler="${{ matrix.platform.compiler }}" windres="${{ matrix.platform.windres }}"
- name: "macOS: Make universal app"
if: runner.os == 'macOS'
run: scripts/macos-make-universal.sh
env:
MAKEFLAGS: -j3
MACOS_CERTIFICATE_NAME: ${{ secrets.MACOS_CERTIFICATE_NAME }}
MACOS_KEYCHAIN_NAME: ares-macos-keychain
MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
- name: "Windows: sign"
if: runner.os == 'Windows' && github.event_name != 'pull_request'
uses: DanaBear/code-sign-action@98c79121b376beab8d6a9484f445089db4461bca
with:
certificate: '${{ secrets.WIN_CERTIFICATE }}'
password: '${{ secrets.WIN_PASSWORD }}'
certificatesha1: '${{ secrets.WIN_CERTHASH }}'
certificatename: '${{ secrets.WIN_CERTNAME }}'
folder: 'desktop-ui/out'
timestampUrl: 'http://timestamp.digicert.com'
- name: "macOS: notarize"
if: runner.os == 'macOS' && github.event_name != 'pull_request'
run: |
ditto -c -k --keepParent desktop-ui/out/ares.app /tmp/ares.zip
xcrun notarytool submit /tmp/ares.zip --apple-id "$MACOS_NOTARIZATION_USERNAME" --password "$MACOS_NOTARIZATION_PASSWORD" --team-id "$MACOS_NOTARIZATION_TEAMID" --wait
xcrun stapler staple desktop-ui/out/ares.app
env:
MACOS_NOTARIZATION_USERNAME: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
MACOS_NOTARIZATION_PASSWORD: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
MACOS_NOTARIZATION_TEAMID: ${{ secrets.MACOS_NOTARIZATION_TEAMID }}
- name: Upload
uses: actions/upload-artifact@v2
with:
@@ -87,16 +172,16 @@ jobs:
# Hack: Workaround for GitHub artifacts losing attributes.
chmod +x ${bindir}/ares-macos/ares.app/Contents/MacOS/ares
for os in windows macos
for package in windows windows-msvc-arm64 macos
do
mkdir "${os}"
cd "${os}"
mkdir "${package}"
cd "${package}"
# Package ares.
outdir=ares${suffix}
mkdir ${outdir}
cp -ar ${bindir}/ares-${os}/* ${outdir}
zip -r ../ares-${os}.zip ${outdir}
cp -ar ${bindir}/ares-${package}/* ${outdir}
zip -r ../ares-${package}.zip ${outdir}
cd -
done
@@ -183,6 +268,10 @@ jobs:
uses: actions/upload-release-asset@v1
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-windows.zip', asset_name: 'ares-windows.zip', asset_content_type: 'application/zip' }
- name: Upload ares-windows-msvc-arm64
uses: actions/upload-release-asset@v1
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
with: { upload_url: '${{ env.UPLOAD_URL }}', asset_path: 'ares-windows-msvc-arm64.zip', asset_name: 'ares-windows-msvc-arm64.zip', asset_content_type: 'application/zip' }
- name: Upload ares-macos
uses: actions/upload-release-asset@v1
env: { GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' }
-30
View File
@@ -1,30 +0,0 @@
name: 'Split Subtrees'
on:
push:
branches:
- master
tags:
- '*'
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
jobs:
packages_split:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package:
- nall
- hiro
- ruby
- libco
steps:
- uses: actions/checkout@v2
- if: "!startsWith(github.ref, 'refs/tags/')"
uses: "symplify/[email protected]"
with:
package_directory: '${{ matrix.package }}'
repository_organization: 'ares-emulator'
repository_name: '${{ matrix.package }}'
user_name: "Luke Usher"
user_email: "[email protected]"
+7
View File
@@ -1,2 +1,9 @@
*.moc
*.user
.vs/
obj/
out/
obj-amd64/
obj-arm64/
out-amd64/
out-arm64/
+4 -4
View File
@@ -1,6 +1,6 @@
all: desktop
targets = all clean install uninstall verbose
desktop:
$(MAKE) -C desktop-ui
$(targets):
@$(MAKE) -C desktop-ui $@
.PHONY: all desktop
.PHONY: $(targets)
+323 -33
View File
@@ -45,38 +45,6 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
----------------------------------------------------------------------
MAME
Copyright (c) 1997-2021 MAMEdev and contributors
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
----------------------------------------------------------------------
libchdr
@@ -145,4 +113,326 @@ Gailly and Mark Adler; it does not include third-party code.
If you redistribute modified sources, we would appreciate that you include in
the file ChangeLog history information documenting your changes. Please read
the FAQ for more information on the distribution of modified source versions.
----------------------------------------------------------------------
----------------------------------------------------------------------
----------------------------------------------------------------------
xxHash - Extremely Fast Hash algorithm
Header File
Copyright (C) 2012-2021 Yann Collet
BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at:
- xxHash homepage: https://www.xxhash.com
- xxHash source repository: https://github.com/Cyan4973/xxHash
----------------------------------------------------------------------
MoltenVK
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
----------------------------------------------------------------------
----------------------------------------------------------------------
OpenGL API and Extension Registry
https://github.com/KhronosGroup/OpenGL-Registry
Copyright 2013-2020 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
----------------------------------------------------------------------
----------------------------------------------------------------------
EGL API and Extension Registry
https://github.com/KhronosGroup/EGL-Registry
Copyright (c) 2008-2018 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
----------------------------------------------------------------------
----------------------------------------------------------------------
TZXFile
MIT License
Copyright (c) 2020 MrReeMachine
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
----------------------------------------------------------------------
+134 -1
View File
@@ -1,4 +1,4 @@
![ares logo](https://ares-emulator.github.io/images/logo.png)
![ares logo](https://github.com/ares-emulator/ares/blob/master/ares/ares/resource/logo.png)
[![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://github.com/higan-emu/ares/blob/master/LICENSE)
@@ -16,3 +16,136 @@ Nightly Builds
Automated, untested builds of ares are available for Windows and macOS as a [pre-release](https://github.com/higan-emu/ares/releases/tag/nightly).
Only the latest nightly build is kept.
Prerequisites
-------------
### *nix building
###### Minimum required packages:
```
g++ make pkg-config libgtk-3-dev libcanberra-gtk-module libgl-dev libasound2-dev
```
###### Additional Audio Drivers
ares supports additional audio drivers besides the ALSA drivers included above. Installing these additional packages will allow them to be selected in Settings > Drivers:
`libao-dev libopenal-dev'
###### GTK2 & GTK3
By default, GTK3 is used, but support for GTK2 is available. You will need to install the additional package `libgtk2.0-dev` as well as specifying the command line option `hiro=gtk2` at compile time.
###### SDL2 for input
If you would like to use SDL for input, you will need to install the following the `libsdl2-dev` and `libsdl2-0.0` packages and perform a clean build of ares. You should then be able to select SDL for input in the Settings > Drivers menu.
##### Building with clang
clang++ is now the preferred compiler for ares. If it is detected, the build will default to building with clang. It is necessary to install both the `clang` and `lld` packages. If you would like to manually specify a compiler, you can use the following option: `compiler=[g++|clang++]`
--------------
### Windows building
To build on Windows, using MSYS2 is recommended which can be download [here](https://www.msys2.org/). Follow the instructions
on this page to install and setup an appropriate MINGW64 environment. Running the command:
```
pacman -S --needed base-devel mingw-w64-x86_64-toolchain
```
from the MSYS2 MSYS terminal should setup everything you need to compile ares. Note that in order to compile, you will want to be in a MINGW64 terminal window after install and setup is complete.
##### Building with clang
clang is available through Visual Studio (or Build Tools for Visual Studio) through its installer and can be used to build ares. You will still need to supply GNU make in this instance. MSYS2 also offers a clang environment. You will want to make sure you select the clangw64 option during installation of MSYS2 which should provide and additional CLANG64 pre-configured environment. Install the clang toolchain package from the MSYS2 terminal:
```
pacman -S mingw-w64-clang-x86_64-toolchain
```
Once complete, open a CLANG64 terminal window and proceed with building ares.
###### Debug Symbols
When building with clang, by default symbols will be generated for debug builds using an MSVC compatible format (CodeView) for use with Windows debugging tools. In order to generate GDB compatible symbols, specify the following option: `symformat=gdb`
Compilation
-----------
Check out the source code by running this command:
```
git clone https://github.com/ares-emulator/ares.git
```
From the root of the project directory run:
```
make -j4
```
`-j#` indicates number of parallel build processes, and shouldn't be set higher than N-1 cores on your processor. Specifying this option can significantly decrease the time to build this project. There are multiple build types available and it defaults to an 'optimized' build. Build types can be specified using: `build=[debug|stable|release|minified|optimized]`
Build options can be found in the following two make files: nall/GNUmakefile desktop-ui/GNUmakefile
To start compilation from the beginning, run the following prior to compiling:
```
make clean
```
#### Building specific cores
If you would like to build a subset of cores, you can specify the `cores="core1 core2"` option. Currently available cores:
```
a26 fc sfc n64 sg ms md ps1 pce ng msx cv gb gba ws ngp spec
```
Build Output
------------
There is a single binary produced at the end of compilation which can be found in `desktop-ui/out`. On OS's besides Linux, the `Database` & `Shader` directories are copied over here as well. On Linux, running `make install` after compilation will copy these directories and binary into suitable locations (see desktop-ui/GNUmakefile for details). Alternatively, these directories can be copied from `ares/Shaders/*` and `mia/Database/*`.
Command-line options
--------------------
When started from the command-line, ares accepts a few options.
```
Usage: ./ares [options] game(s)
--help Displays available options and exit
--fullscreen Start in full screen mode
--system system Specify the system name
--shader shader Specify GLSL shader name to load (requires OpenGL driver)
--setting name=value Specify a value for a setting
--dump-all-settings Show a list of all existing settings and exit
--no-file-prompt Do not prompt to load (optional) additional roms (eg: 64DD)
```
The --system option is useful when the system type cannot be auto-detected.
--fullscreen will only have an effect if a game is also passed in argument.
Example:
`ares --system MSX examples.rom --fullscreen`
Specifying multiple games allows for multi-cart support. For example, to load
the Super GameBoy BIOS and a game in one command (to avoid a file prompt), you
can do:
`ares "Super GameBoy.sfc" "Super Mario Land.gb"`
The --no-file-prompt option is useful if you wish to launch a game from CLI
without being prompted to load additional roms. For example, some Nintendo 64
games optionally support 64DD expansion disks, so this option can be used to
suppress the "64DD Disk" file dialog, and assume any secondary content is
disconnected.
High-level Components
---------------------
* __ares__: emulator cores and component implementations
* __desktop-ui__: main GUI implementation for this project
* __hiro__: cross-platform GUI toolkit that utilizes native APIs on supported platforms
* __nall__: Near's alternative to the C++ standard library
* __ruby__: interface between a hiro application and platform-specific APIs for emulator video, audio, and input
* __mia__: internal ROM database and ROM/image loader
* __libco__: cooperative multithreading library
Contributing
------------
Please join our discord to chat with other ares developers: https://discord.com/invite/gz2quhk2kv
+13 -3
View File
@@ -1,7 +1,5 @@
ifeq ($(platform),windows)
options += -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32
options += -Wl,-enable-auto-import
options += -Wl,-enable-runtime-pseudo-reloc
options += $(call lib,uuid kernel32 user32 gdi32 comctl32 comdlg32 shell32)
else ifeq ($(platform),macos)
else ifneq ($(filter $(platform),linux bsd),)
options += -Wl,-export-dynamic
@@ -15,6 +13,10 @@ ares.objects := ares ares-fixed-allocator
$(object.path)/ares.o: $(ares.path)/ares/ares.cpp
$(object.path)/ares-fixed-allocator.o: $(ares.path)/ares/memory/fixed-allocator.cpp
ifeq ($(platform),macos)
ares.dylibs :=
endif
ifeq ($(vulkan),true)
flags += -DVULKAN
endif
@@ -75,6 +77,10 @@ ifneq ($(filter $(cores),cv),)
include $(ares.path)/cv/GNUmakefile
endif
ifneq ($(filter $(cores),myvision),)
include $(ares.path)/myvision/GNUmakefile
endif
ifneq ($(filter $(cores),gb),)
include $(ares.path)/gb/GNUmakefile
endif
@@ -95,6 +101,10 @@ ifneq ($(filter $(cores),ngp),)
include $(ares.path)/ngp/GNUmakefile
endif
ifneq ($(filter $(cores),spec),)
include $(ares.path)/spec/GNUmakefile
endif
include $(ares.path)/component/GNUmakefile
flags += $(foreach c,$(call strupper,$(cores)),-DCORE_$c)
File diff suppressed because it is too large. Load diff
+15 -15
View File
@@ -1,16 +1,16 @@
#version 150
in vec4 position;
in vec2 texCoord;
out Vertex {
vec2 vTexCoord;
};
uniform vec4 targetSize;
uniform vec4 sourceSize[];
void main() {
gl_Position = position;
vTexCoord = texCoord;
#version 150
in vec4 position;
in vec2 texCoord;
out Vertex {
vec2 vTexCoord;
};
uniform vec4 targetSize;
uniform vec4 sourceSize[];
void main() {
gl_Position = position;
vTexCoord = texCoord;
}
+11 -11
View File
@@ -1,12 +1,12 @@
input
filter: nearest
program
filter: nearest
vertex: lottes.vs
fragment: lottes.fs
output
height: 0
width: 0
input
filter: nearest
program
filter: nearest
vertex: lottes.vs
fragment: lottes.fs
output
height: 0
width: 0
filter: linear
@@ -32,18 +32,18 @@ out vec4 fragColor;
#ifdef LuminanceLUT
#define LUT_SizeLum 16.0
// Code taken from RetroArch's LUT shader
// Code taken from RetroArch's LUT shader
float luminancelut(vec4 org)
{
vec4 imgColorLum = org;
float redLum = ( imgColorLum.r * (LUT_SizeLum - 1.0) + 0.4999 ) / (LUT_SizeLum * LUT_SizeLum);
float greenLum = ( imgColorLum.g * (LUT_SizeLum - 1.0) + 0.4999 ) / LUT_SizeLum;
float blue1Lum = (floor( imgColorLum.b * (LUT_SizeLum - 1.0) ) / LUT_SizeLum) + redLum;
float blue2Lum = (ceil( imgColorLum.b * (LUT_SizeLum - 1.0) ) / LUT_SizeLum) + redLum;
float mixerLum = clamp(max((imgColorLum.b - blue1Lum) / (blue2Lum - blue1Lum), 0.0), 0.0, 32.0);
float color1Lum = texture(pixmap[1], vec2( blue1Lum, greenLum )).x;
float color2Lum = texture(pixmap[1], vec2( blue2Lum, greenLum )).x;
return mix(color1Lum, color2Lum, mixerLum);
vec4 imgColorLum = org;
float redLum = ( imgColorLum.r * (LUT_SizeLum - 1.0) + 0.4999 ) / (LUT_SizeLum * LUT_SizeLum);
float greenLum = ( imgColorLum.g * (LUT_SizeLum - 1.0) + 0.4999 ) / LUT_SizeLum;
float blue1Lum = (floor( imgColorLum.b * (LUT_SizeLum - 1.0) ) / LUT_SizeLum) + redLum;
float blue2Lum = (ceil( imgColorLum.b * (LUT_SizeLum - 1.0) ) / LUT_SizeLum) + redLum;
float mixerLum = clamp(max((imgColorLum.b - blue1Lum) / (blue2Lum - blue1Lum), 0.0), 0.0, 32.0);
float color1Lum = texture(pixmap[1], vec2( blue1Lum, greenLum )).x;
float color2Lum = texture(pixmap[1], vec2( blue2Lum, greenLum )).x;
return mix(color1Lum, color2Lum, mixerLum);
}
#endif
@@ -52,48 +52,48 @@ float luminancelut(vec4 org)
vec4 TrinitronD50(vec4 org)
{
vec4 imgColorTrinitron = org;
float redTrinitron = ( imgColorTrinitron.r * (LUT_SizeTrinitron - 1.0) + 0.4999 ) / (LUT_SizeTrinitron * LUT_SizeTrinitron);
float greenTrinitron = ( imgColorTrinitron.g * (LUT_SizeTrinitron - 1.0) + 0.4999 ) / LUT_SizeTrinitron;
float blue1Trinitron = (floor( imgColorTrinitron.b * (LUT_SizeTrinitron - 1.0) ) / LUT_SizeTrinitron) + redTrinitron;
float blue2Trinitron = (ceil( imgColorTrinitron.b * (LUT_SizeTrinitron - 1.0) ) / LUT_SizeTrinitron) + redTrinitron;
float mixerTrinitron = clamp(max((imgColorTrinitron.b - blue1Trinitron) / (blue2Trinitron - blue1Trinitron), 0.0), 0.0, 32.0);
vec4 color1Trinitron = texture(pixmap[2], vec2( blue1Trinitron, greenTrinitron ));
vec4 color2Trinitron = texture(pixmap[2], vec2( blue2Trinitron, greenTrinitron ));
vec4 fragColorTrinitron = mix(color1Trinitron, color2Trinitron, mixerTrinitron);
return vec4(pow(fragColorTrinitron.rgb,vec3(GammaCorrection,GammaCorrection,GammaCorrection)),1.0);
vec4 imgColorTrinitron = org;
float redTrinitron = ( imgColorTrinitron.r * (LUT_SizeTrinitron - 1.0) + 0.4999 ) / (LUT_SizeTrinitron * LUT_SizeTrinitron);
float greenTrinitron = ( imgColorTrinitron.g * (LUT_SizeTrinitron - 1.0) + 0.4999 ) / LUT_SizeTrinitron;
float blue1Trinitron = (floor( imgColorTrinitron.b * (LUT_SizeTrinitron - 1.0) ) / LUT_SizeTrinitron) + redTrinitron;
float blue2Trinitron = (ceil( imgColorTrinitron.b * (LUT_SizeTrinitron - 1.0) ) / LUT_SizeTrinitron) + redTrinitron;
float mixerTrinitron = clamp(max((imgColorTrinitron.b - blue1Trinitron) / (blue2Trinitron - blue1Trinitron), 0.0), 0.0, 32.0);
vec4 color1Trinitron = texture(pixmap[2], vec2( blue1Trinitron, greenTrinitron ));
vec4 color2Trinitron = texture(pixmap[2], vec2( blue2Trinitron, greenTrinitron ));
vec4 fragColorTrinitron = mix(color1Trinitron, color2Trinitron, mixerTrinitron);
return vec4(pow(fragColorTrinitron.rgb,vec3(GammaCorrection,GammaCorrection,GammaCorrection)),1.0);
}
#endif
void main() {
//Source Image
vec4 org = texture(source[0], texCoord);
vec4 org = texture(source[0], texCoord);
#ifdef LuminanceLUT
// Use a 3DLUT instead of an equation so that it can use any arbitrary mess you can come up with.
float luminance = luminancelut(org);
float luminance = luminancelut(org);
#elif defined LuminanceDawnbringer
// Dawnbringer's brightness equation from Dawnbringer's Toolbox scripts for Grafx2
float luminance = sqrt(org.r*org.r*0.0676 + org.g*org.g*0.3025 + org.b*org.b*0.0361) * 1.5690256395005606;
float luminance = sqrt(org.r*org.r*0.0676 + org.g*org.g*0.3025 + org.b*org.b*0.0361) * 1.5690256395005606;
#else
// Plain, standard, fine; slightly faster
float luminance = ((0.299*org.r) + (0.587*org.g) + (0.114*org.b));
float luminance = ((0.299*org.r) + (0.587*org.g) + (0.114*org.b));
#endif
// Don't let it exceed 1.0
luminance = clamp(luminance, 0.0, 1.0);
luminance = clamp(luminance, 0.0, 1.0);
// Scanline Mapping, based on the Phosphor LUT shader's method of tiling a texture over the screen
vec2 LUTeffectiveCoord = vec2(luminance,fract((texCoord.y*targetSize.y)/4.0));
vec2 LUTeffectiveCoord = vec2(luminance,fract((texCoord.y*targetSize.y)/4.0));
// Scanline Layer
vec4 screen = texture(pixmap[0], LUTeffectiveCoord);
vec4 screen = texture(pixmap[0], LUTeffectiveCoord);
// Output multiplying the scanlines into the original image, with control over opacity
#ifdef TrinitronColors
org = TrinitronD50(org);
org = TrinitronD50(org);
#endif
fragColor = ((screen*ScanlinesOpacity)+(1.0 - ScanlinesOpacity)) * (org);
fragColor = ((screen*ScanlinesOpacity)+(1.0 - ScanlinesOpacity)) * (org);
}
+10 -10
View File
@@ -1,11 +1,11 @@
input
filter: nearest
program
filter: nearest
height: 100%
fragment: pal-r57shell.fs
output
height: 0
input
filter: nearest
program
filter: nearest
height: 100%
fragment: pal-r57shell.fs
output
height: 0
filter: linear
+367 -367
View File
@@ -1,368 +1,368 @@
#version 150
// NES PAL composite signal simulation for RetroArch
// shader by r57shell
// thanks to feos & HardWareMan & NewRisingSun
// also TV subpixels and scanlines
// LICENSE: PUBLIC DOMAIN
// NOTE: for nice TV subpixels and scanlines I recommend to
// disable this features here and apply CRT-specialized shader.
// Quality considerations
// there are three main options:
// USE_RAW (R), USE_DELAY_LINE (D), USE_COLORIMETRY (C)
// here is table of quality in decreasing order:
// RDC, RD, RC, DC, D, C
// compatibility macros
#define float2 vec2
#define float3 vec3
#define float4 vec4
#define frac(c) fract(c)
#define saturate(c) clamp(c, 0.0, 1.0)
#define fmod(x,y) mod(x,y)
#define mul(x,y) (y*x)
#define float2x2 mat2
#define float3x3 mat3
#define float4x4 mat4
#define bool2 bvec2
#define bool3 bvec3
#define bool4 bvec4
#define static
uniform sampler2D source[];
uniform vec4 sourceSize[];
uniform vec4 outputSize;
uniform int phase;
in Vertex {
vec2 texCoord;
};
out vec4 fragColor;
// TWEAKS start
// use delay line technique
// without delay line technique, color would interleave
// to avoid this, set HueRotation to zero.
#define USE_DELAY_LINE
// use this if you need to swap even/odd V sign.
// sign of V changes each scanline
// so if some scanline is positive, then next is negative
// and if you want to match picture
// to actual running PAL NES on TV
// you may want to have this option, to change signs
// if they don't match
//#define SWAP_VSIGN
// rough simulation of scanlines
// better if you use additional shader instead
// if you still use it, make sure that SizeY
// is at least twice lower than output height
#define USE_SCANLINES // FIXME: scanlines are broken and I'm too lazy to fix it right now
// to change gamma of virtual TV from 2.2 to something else
#define USE_GAMMA
// use sampled version. it's much more slower version of shader.
// because it is computing x4 more values. NOT RECOMMENDED.
//#define USE_SAMPLED
#ifndef PARAMETER_UNIFORM
// NTSC standard gamma = 2.2
// PAL standard gamma = 2.8
// according to many sources, very unlikely gamma of TV is 2.8
// most likely gamma of PAL TV is in range 2.4-2.5
const float Gamma_static = 2.8; // gamma of virtual TV
const float Brightness_static = 0.25;
const float Contrast_static = 1.1;
const float Saturation_static = 1.1;
const int
Ywidth_static = 12,
Uwidth_static = 23,
Vwidth_static = 23;
#define Brightness Brightness_static
#define Gamma Gamma_static
#define Ywidth Ywidth_static
#define Uwidth Uwidth_static
#define Vwidth Vwidth_static
#define SCANLINE_MUL (sw.x*dark_scanline+sw.y)
int Mwidth = int(max(float(Ywidth), max(float(Uwidth), float(Vwidth))));
// correct one is -2.5
// works only with USE_RAW
const float HueShift = -2.5;
// rotation of hue due to luma level.
const float HueRotation = 2.;
// touch this only if you know what you doing
const float Phase_Y = 2.; // fmod(341*10,12)
const float Phase_One = 0.; // alternating phases.
const float Phase_Two = 8.;
// screen size, scanlines = y*2; y one field, and y other field.
const int SizeX = 256;
const int SizeY = 240;
// count of pixels of virtual TV.
// value close to 1000 produce small artifacts
const int TV_Pixels = 400;
const float dark_scanline = 0.5; // half
#endif
// this is using following matrixes.
// it provides more scientific approach
// by conversion into linear XYZ space
// and back to sRGB.
// it's using Gamma setting too.
// define USE_GAMMA is not required.
#define USE_COLORIMETRY
const float3x3 RGB_to_XYZ =
mat3(
0.4306190, 0.3415419, 0.1783091,
0.2220379, 0.7066384, 0.0713236,
0.0201853, 0.1295504, 0.9390944
);
const float3x3 XYZ_to_sRGB =
mat3(
3.2406, -1.5372, -0.4986,
-0.9689, 1.8758, 0.0415,
0.0557, -0.2040, 1.0570
);
// TWEAKS end
const float YUV_u = 0.492;
const float YUV_v = 0.877;
const mat3 RGB_to_YUV =
mat3(
float3( 0.299, 0.587, 0.114), //Y
float3(-0.299,-0.587, 0.886)*YUV_u, //B-Y
float3( 0.701,-0.587,-0.114)*YUV_v //R-Y
);
#ifdef USE_DELAY_LINE
const float comb_line = 1.;
#else
const float comb_line = 2.;
#endif
static const float Voltage_0 = 0.518;
static const float Voltage_1 = 1.962;
static const float DeltaV = (Voltage_1-Voltage_0);
float RGB_y = Contrast_static/Ywidth_static/DeltaV;
float RGB_u = comb_line*Contrast_static*Saturation_static/YUV_u/Uwidth_static/DeltaV;
float RGB_v = comb_line*Contrast_static*Saturation_static/YUV_v/Vwidth_static/DeltaV;
mat3 YUV_to_RGB =
mat3(
float3(1., 1., 1.)*RGB_y,
float3(0., -0.114/0.587, 1.)*RGB_u,
float3(1., -0.299/0.587, 0.)*RGB_v
);
const float pi = 3.1415926535897932384626433832795;
float sinn(float x)
{
return sin(/*fmod(x,24)*/x*(pi*2./24.));
}
float coss(float x)
{
return cos(/*fmod(x,24)*/x*(pi*2./24.));
}
float3 monitor(sampler2D tex, float2 p)
{
float2 size = sourceSize[0].xy;//float2(SizeX,SizeY);
// align vertical coord to center of texel
float2 uv = float2(
p.x,
(floor(p.y*sourceSize[0].y)+0.5)/sourceSize[0].y);
#ifdef USE_DELAY_LINE
float2 sh = (sourceSize[0].xy/sourceSize[0].xy/size)*float2(14./10.,-1.0);
#endif
float2 pc = uv*sourceSize[0].xy/sourceSize[0].xy*size*float2(10.,1.);
float alpha = dot(floor(float2(pc.x,pc.y)),float2(2.,Phase_Y*2.));
alpha += Phase_One*2.;
// 1/size.x of screen in uv coords = sourceSize[0].x/sourceSize[0].x/size.x;
// then 1/10*size.x of screen:
float ustep = sourceSize[0].x/sourceSize[0].x/size.x/10.;
float border = sourceSize[0].x/sourceSize[0].x;
float ss = 2.0;
#ifdef SWAP_VSIGN
#define PAL_SWITCH(A) A < 1.
#else
#define PAL_SWITCH(A) A > 1.
#endif
if (PAL_SWITCH(fmod(uv.y*sourceSize[0].y/sourceSize[0].y*size.y,2.0)))
{
// cos(pi-alpha) = -cos(alpha)
// sin(pi-alpha) = sin(alpha)
// pi - alpha
alpha = -alpha+12012.0;
ss = -2.0;
}
float ysum = 0., usum = 0., vsum = 0.;
for (int i=0; i<Mwidth; ++i)
{
float4 res = texture(tex, uv);
float3 yuv = mul(RGB_to_YUV, res.xyz);
float a1 = alpha+(HueShift+2.5)*2.-yuv.x*ss*HueRotation;
float sig = yuv.x+dot(yuv.yz,sign(float2(sinn(a1),coss(a1))));
#ifdef USE_DELAY_LINE
float4 res1 = texture(tex, uv+sh);
float3 yuv1 = mul(RGB_to_YUV, res1.xyz);
float a2 = (HueShift+2.5)*2.+12012.0-alpha+yuv.x*ss*HueRotation;
float sig1 = yuv1.x+dot(yuv1.yz,sign(float2(sinn(a2),coss(a2))));
#endif
if (i < Ywidth)
ysum += sig;
#ifdef USE_DELAY_LINE
if (i < Uwidth)
usum += (sig+sig1)*sinn(alpha);
if (i < Vwidth)
vsum += (sig-sig1)*coss(alpha);
#else
if (i < Uwidth)
usum += sig*sinn(alpha);
if (i < Vwidth)
vsum += sig*coss(alpha);
#endif
alpha -= ss;
uv.x -= ustep;
}
float3 rgb = mul(float3(ysum+Brightness*Ywidth_static,usum,vsum), YUV_to_RGB);
#if defined(USE_GAMMA) && !defined(USE_COLORIMETRY)
float3 rgb1 = saturate(rgb);
rgb = pow(rgb1, Gamma/2.2);
#endif
#ifdef USE_COLORIMETRY
float3 rgb1 = saturate(rgb);
rgb = pow(rgb1, float3(Gamma, Gamma, Gamma));
#endif
#if (defined(USE_SCANLINES))
float2 q = (p*sourceSize[0].xy/sourceSize[0].xy)*float2(TV_Pixels*3.,size.y*2.);
#endif
#ifdef USE_SCANLINES
float scanlines = size.y * outputSize.z;
float top = fmod(q.y-0.5*scanlines*2.,2.);
float bottom = top+frac(scanlines)*2.;
float2 sw = saturate(min(float2(1.,2.),float2(bottom, bottom))
-max(float2(0.,1.),float2(top)))
+saturate(min(float2(3.,4.),float2(bottom, bottom))
-max(float2(2.,3.),float2(top)))
+floor(scanlines);
rgb = rgb*SCANLINE_MUL/(sw.x+sw.y);
/*
//old stupid method
float z =
#ifdef ANIMATE_SCANLINE
fmod(phase,2.0)+
#endif
0.5;
if (abs(fmod(q.y+0.5,2)-z)<0.5)
rgb *= dark_scanline;
*/
#endif
// size of pixel screen in texture coords:
//float output_pixel_size = sourceSize[0].x/(outputSize.x*sourceSize[0].x);
// correctness check
//if (fmod(p.x*output_pixel_size,2.0) < 1.0)
// rgb = float3(0.,0.,0.);
#ifdef USE_COLORIMETRY
float3 xyz1 = mul(RGB_to_XYZ,rgb);
float3 srgb = saturate(mul(XYZ_to_sRGB,xyz1));
float3 a1 = 12.92*srgb;
float3 a2 = 1.055*pow(srgb,float3(1./2.4))-0.055;
float3 ssrgb;
ssrgb.x = (srgb.x<0.0031308?a1.x:a2.x);
ssrgb.y = (srgb.y<0.0031308?a1.y:a2.y);
ssrgb.z = (srgb.z<0.0031308?a1.z:a2.z);
return ssrgb;
#else
return rgb;
#endif
}
// pos (left corner, sample size)
float4 monitor_sample(sampler2D tex, float2 p, float2 sample_)
{
// linear interpolation was...
// now other thing.
// http://imgur.com/m8Z8trV
// AT LAST IT WORKS!!!!
// going to check in retroarch...
float2 size = sourceSize[0].xy;
float2 next = float2(.25,1.)/size;
float2 f = frac(float2(4.,1.)*size*p);
sample_ *= float2(4.,1.)*size;
float2 l;
float2 r;
if (f.x+sample_.x < 1.)
{
l.x = f.x+sample_.x;
r.x = 0.;
}
else
{
l.x = 1.-f.x;
r.x = min(1.,f.x+sample_.x-1.);
}
if (f.y+sample_.y < 1.)
{
l.y = f.y+sample_.y;
r.y = 0.;
}
else
{
l.y = 1.-f.y;
r.y = min(1.,f.y+sample_.y-1.);
}
float3 top = mix(monitor(tex, p), monitor(tex, p+float2(next.x,0.)), r.x/(l.x+r.x));
float3 bottom = mix(monitor(tex, p+float2(0.,next.y)), monitor(tex, p+next), r.x/(l.x+r.x));
return float4(mix(top,bottom, r.y/(l.y+r.y)),1.0);
}
void main() {
#ifdef USE_SAMPLED
fragColor = vec4(monitor_sample(source[0], texCoord, outputSize.zw).rgb, 1.0);
#else
fragColor = float4(monitor(source[0], texCoord), 1.);
#endif
#version 150
// NES PAL composite signal simulation for RetroArch
// shader by r57shell
// thanks to feos & HardWareMan & NewRisingSun
// also TV subpixels and scanlines
// LICENSE: PUBLIC DOMAIN
// NOTE: for nice TV subpixels and scanlines I recommend to
// disable this features here and apply CRT-specialized shader.
// Quality considerations
// there are three main options:
// USE_RAW (R), USE_DELAY_LINE (D), USE_COLORIMETRY (C)
// here is table of quality in decreasing order:
// RDC, RD, RC, DC, D, C
// compatibility macros
#define float2 vec2
#define float3 vec3
#define float4 vec4
#define frac(c) fract(c)
#define saturate(c) clamp(c, 0.0, 1.0)
#define fmod(x,y) mod(x,y)
#define mul(x,y) (y*x)
#define float2x2 mat2
#define float3x3 mat3
#define float4x4 mat4
#define bool2 bvec2
#define bool3 bvec3
#define bool4 bvec4
#define static
uniform sampler2D source[];
uniform vec4 sourceSize[];
uniform vec4 outputSize;
uniform int phase;
in Vertex {
vec2 texCoord;
};
out vec4 fragColor;
// TWEAKS start
// use delay line technique
// without delay line technique, color would interleave
// to avoid this, set HueRotation to zero.
#define USE_DELAY_LINE
// use this if you need to swap even/odd V sign.
// sign of V changes each scanline
// so if some scanline is positive, then next is negative
// and if you want to match picture
// to actual running PAL NES on TV
// you may want to have this option, to change signs
// if they don't match
//#define SWAP_VSIGN
// rough simulation of scanlines
// better if you use additional shader instead
// if you still use it, make sure that SizeY
// is at least twice lower than output height
#define USE_SCANLINES // FIXME: scanlines are broken and I'm too lazy to fix it right now
// to change gamma of virtual TV from 2.2 to something else
#define USE_GAMMA
// use sampled version. it's much more slower version of shader.
// because it is computing x4 more values. NOT RECOMMENDED.
//#define USE_SAMPLED
#ifndef PARAMETER_UNIFORM
// NTSC standard gamma = 2.2
// PAL standard gamma = 2.8
// according to many sources, very unlikely gamma of TV is 2.8
// most likely gamma of PAL TV is in range 2.4-2.5
const float Gamma_static = 2.8; // gamma of virtual TV
const float Brightness_static = 0.25;
const float Contrast_static = 1.1;
const float Saturation_static = 1.1;
const int
Ywidth_static = 12,
Uwidth_static = 23,
Vwidth_static = 23;
#define Brightness Brightness_static
#define Gamma Gamma_static
#define Ywidth Ywidth_static
#define Uwidth Uwidth_static
#define Vwidth Vwidth_static
#define SCANLINE_MUL (sw.x*dark_scanline+sw.y)
int Mwidth = int(max(float(Ywidth), max(float(Uwidth), float(Vwidth))));
// correct one is -2.5
// works only with USE_RAW
const float HueShift = -2.5;
// rotation of hue due to luma level.
const float HueRotation = 2.;
// touch this only if you know what you doing
const float Phase_Y = 2.; // fmod(341*10,12)
const float Phase_One = 0.; // alternating phases.
const float Phase_Two = 8.;
// screen size, scanlines = y*2; y one field, and y other field.
const int SizeX = 256;
const int SizeY = 240;
// count of pixels of virtual TV.
// value close to 1000 produce small artifacts
const int TV_Pixels = 400;
const float dark_scanline = 0.5; // half
#endif
// this is using following matrixes.
// it provides more scientific approach
// by conversion into linear XYZ space
// and back to sRGB.
// it's using Gamma setting too.
// define USE_GAMMA is not required.
#define USE_COLORIMETRY
const float3x3 RGB_to_XYZ =
mat3(
0.4306190, 0.3415419, 0.1783091,
0.2220379, 0.7066384, 0.0713236,
0.0201853, 0.1295504, 0.9390944
);
const float3x3 XYZ_to_sRGB =
mat3(
3.2406, -1.5372, -0.4986,
-0.9689, 1.8758, 0.0415,
0.0557, -0.2040, 1.0570
);
// TWEAKS end
const float YUV_u = 0.492;
const float YUV_v = 0.877;
const mat3 RGB_to_YUV =
mat3(
float3( 0.299, 0.587, 0.114), //Y
float3(-0.299,-0.587, 0.886)*YUV_u, //B-Y
float3( 0.701,-0.587,-0.114)*YUV_v //R-Y
);
#ifdef USE_DELAY_LINE
const float comb_line = 1.;
#else
const float comb_line = 2.;
#endif
static const float Voltage_0 = 0.518;
static const float Voltage_1 = 1.962;
static const float DeltaV = (Voltage_1-Voltage_0);
float RGB_y = Contrast_static/Ywidth_static/DeltaV;
float RGB_u = comb_line*Contrast_static*Saturation_static/YUV_u/Uwidth_static/DeltaV;
float RGB_v = comb_line*Contrast_static*Saturation_static/YUV_v/Vwidth_static/DeltaV;
mat3 YUV_to_RGB =
mat3(
float3(1., 1., 1.)*RGB_y,
float3(0., -0.114/0.587, 1.)*RGB_u,
float3(1., -0.299/0.587, 0.)*RGB_v
);
const float pi = 3.1415926535897932384626433832795;
float sinn(float x)
{
return sin(/*fmod(x,24)*/x*(pi*2./24.));
}
float coss(float x)
{
return cos(/*fmod(x,24)*/x*(pi*2./24.));
}
float3 monitor(sampler2D tex, float2 p)
{
float2 size = sourceSize[0].xy;//float2(SizeX,SizeY);
// align vertical coord to center of texel
float2 uv = float2(
p.x,
(floor(p.y*sourceSize[0].y)+0.5)/sourceSize[0].y);
#ifdef USE_DELAY_LINE
float2 sh = (sourceSize[0].xy/sourceSize[0].xy/size)*float2(14./10.,-1.0);
#endif
float2 pc = uv*sourceSize[0].xy/sourceSize[0].xy*size*float2(10.,1.);
float alpha = dot(floor(float2(pc.x,pc.y)),float2(2.,Phase_Y*2.));
alpha += Phase_One*2.;
// 1/size.x of screen in uv coords = sourceSize[0].x/sourceSize[0].x/size.x;
// then 1/10*size.x of screen:
float ustep = sourceSize[0].x/sourceSize[0].x/size.x/10.;
float border = sourceSize[0].x/sourceSize[0].x;
float ss = 2.0;
#ifdef SWAP_VSIGN
#define PAL_SWITCH(A) A < 1.
#else
#define PAL_SWITCH(A) A > 1.
#endif
if (PAL_SWITCH(fmod(uv.y*sourceSize[0].y/sourceSize[0].y*size.y,2.0)))
{
// cos(pi-alpha) = -cos(alpha)
// sin(pi-alpha) = sin(alpha)
// pi - alpha
alpha = -alpha+12012.0;
ss = -2.0;
}
float ysum = 0., usum = 0., vsum = 0.;
for (int i=0; i<Mwidth; ++i)
{
float4 res = texture(tex, uv);
float3 yuv = mul(RGB_to_YUV, res.xyz);
float a1 = alpha+(HueShift+2.5)*2.-yuv.x*ss*HueRotation;
float sig = yuv.x+dot(yuv.yz,sign(float2(sinn(a1),coss(a1))));
#ifdef USE_DELAY_LINE
float4 res1 = texture(tex, uv+sh);
float3 yuv1 = mul(RGB_to_YUV, res1.xyz);
float a2 = (HueShift+2.5)*2.+12012.0-alpha+yuv.x*ss*HueRotation;
float sig1 = yuv1.x+dot(yuv1.yz,sign(float2(sinn(a2),coss(a2))));
#endif
if (i < Ywidth)
ysum += sig;
#ifdef USE_DELAY_LINE
if (i < Uwidth)
usum += (sig+sig1)*sinn(alpha);
if (i < Vwidth)
vsum += (sig-sig1)*coss(alpha);
#else
if (i < Uwidth)
usum += sig*sinn(alpha);
if (i < Vwidth)
vsum += sig*coss(alpha);
#endif
alpha -= ss;
uv.x -= ustep;
}
float3 rgb = mul(float3(ysum+Brightness*Ywidth_static,usum,vsum), YUV_to_RGB);
#if defined(USE_GAMMA) && !defined(USE_COLORIMETRY)
float3 rgb1 = saturate(rgb);
rgb = pow(rgb1, Gamma/2.2);
#endif
#ifdef USE_COLORIMETRY
float3 rgb1 = saturate(rgb);
rgb = pow(rgb1, float3(Gamma, Gamma, Gamma));
#endif
#if (defined(USE_SCANLINES))
float2 q = (p*sourceSize[0].xy/sourceSize[0].xy)*float2(TV_Pixels*3.,size.y*2.);
#endif
#ifdef USE_SCANLINES
float scanlines = size.y * outputSize.z;
float top = fmod(q.y-0.5*scanlines*2.,2.);
float bottom = top+frac(scanlines)*2.;
float2 sw = saturate(min(float2(1.,2.),float2(bottom, bottom))
-max(float2(0.,1.),float2(top)))
+saturate(min(float2(3.,4.),float2(bottom, bottom))
-max(float2(2.,3.),float2(top)))
+floor(scanlines);
rgb = rgb*SCANLINE_MUL/(sw.x+sw.y);
/*
//old stupid method
float z =
#ifdef ANIMATE_SCANLINE
fmod(phase,2.0)+
#endif
0.5;
if (abs(fmod(q.y+0.5,2)-z)<0.5)
rgb *= dark_scanline;
*/
#endif
// size of pixel screen in texture coords:
//float output_pixel_size = sourceSize[0].x/(outputSize.x*sourceSize[0].x);
// correctness check
//if (fmod(p.x*output_pixel_size,2.0) < 1.0)
// rgb = float3(0.,0.,0.);
#ifdef USE_COLORIMETRY
float3 xyz1 = mul(RGB_to_XYZ,rgb);
float3 srgb = saturate(mul(XYZ_to_sRGB,xyz1));
float3 a1 = 12.92*srgb;
float3 a2 = 1.055*pow(srgb,float3(1./2.4))-0.055;
float3 ssrgb;
ssrgb.x = (srgb.x<0.0031308?a1.x:a2.x);
ssrgb.y = (srgb.y<0.0031308?a1.y:a2.y);
ssrgb.z = (srgb.z<0.0031308?a1.z:a2.z);
return ssrgb;
#else
return rgb;
#endif
}
// pos (left corner, sample size)
float4 monitor_sample(sampler2D tex, float2 p, float2 sample_)
{
// linear interpolation was...
// now other thing.
// http://imgur.com/m8Z8trV
// AT LAST IT WORKS!!!!
// going to check in retroarch...
float2 size = sourceSize[0].xy;
float2 next = float2(.25,1.)/size;
float2 f = frac(float2(4.,1.)*size*p);
sample_ *= float2(4.,1.)*size;
float2 l;
float2 r;
if (f.x+sample_.x < 1.)
{
l.x = f.x+sample_.x;
r.x = 0.;
}
else
{
l.x = 1.-f.x;
r.x = min(1.,f.x+sample_.x-1.);
}
if (f.y+sample_.y < 1.)
{
l.y = f.y+sample_.y;
r.y = 0.;
}
else
{
l.y = 1.-f.y;
r.y = min(1.,f.y+sample_.y-1.);
}
float3 top = mix(monitor(tex, p), monitor(tex, p+float2(next.x,0.)), r.x/(l.x+r.x));
float3 bottom = mix(monitor(tex, p+float2(0.,next.y)), monitor(tex, p+next), r.x/(l.x+r.x));
return float4(mix(top,bottom, r.y/(l.y+r.y)),1.0);
}
void main() {
#ifdef USE_SAMPLED
fragColor = vec4(monitor_sample(source[0], texCoord, outputSize.zw).rgb, 1.0);
#else
fragColor = float4(monitor(source[0], texCoord), 1.);
#endif
}
+1
View File
@@ -10,6 +10,7 @@ auto ControllerPort::load(Node::Object parent) -> void {
port->setType("Controller");
port->setHotSwappable(true);
port->setAllocate([&](auto name) { return allocate(name); });
port->setDisconnect([&] { device.reset(); });
port->setSupported({"Gamepad"});
}
+4 -2
View File
@@ -41,8 +41,10 @@ auto RIOT::step(u32 clocks) -> void {
auto RIOT::power(bool reset) -> void {
Thread::create(system.frequency() / 3, {&RIOT::main, this});
timer = {};
port[0] = {.data = 0xff};
port[1] = {.data = 0xff};
port[0] = {};
port[0].data = 0xff;
port[1] = {};
port[1].data = 0xff;
leftDifficulty = 1;
rightDifficulty = 1;
tvType = 1;
+2
View File
@@ -1,3 +1,5 @@
static const string SerializerVersion = "v131";
auto System::serialize(bool synchronize) -> serializer {
if(synchronize) scheduler.enter(Scheduler::Mode::Synchronize);
serializer s;
+2 -2
View File
@@ -20,7 +20,7 @@ struct System {
auto name() const -> string { return information.name; }
auto region() const -> Region { return information.region; }
auto frequency() const -> u32 { return information.frequency; }
auto frequency() const -> f64 { return information.frequency; }
//system.cpp
auto game() -> string;
@@ -39,7 +39,7 @@ private:
struct Information {
string name = "Atari 2600";
Region region = Region::NTSC;
u32 frequency = Constants::Colorburst::NTSC;
f64 frequency = Constants::Colorburst::NTSC;
} information;
//serialization.cpp
-1
View File
@@ -73,7 +73,6 @@ auto TIA::write(n8 address, n8 data) -> void {
auto TIA::vsync(n1 state) -> void {
if(io.vsync && !state) {
io.vcounter = 0;
frame();
}
+20 -6
View File
@@ -15,10 +15,10 @@ auto TIA::load(Node::Object parent) -> void {
screen = node->append<Node::Video::Screen>("Screen", 160, vlines());
screen->colors(1 << 7, {&TIA::color, this});
screen->setSize(160, vlines());
screen->setScale(2.0, 1.0);
screen->setAspect(1.0, 1.0);
screen->setViewport(0, 0, 160, vlines());
screen->setSize(160, displayHeight());
screen->setScale(1.0, 1.0);
screen->setAspect(12.0, 7.0);
screen->setViewport(0, 0, 160, displayHeight());
stream = node->append<Node::Audio::Stream>("Audio");
stream->setChannels(1);
@@ -44,11 +44,17 @@ auto TIA::scanline() -> void {
cpu.rdyLine(1);
for(io.hcounter = 0; io.hcounter < 228; io.hcounter++) {
auto x = io.hcounter - 68;
if(x >= 0) pixel(x);
if(x >= 0 && io.vcounter < vlines()) pixel(x);
writeQueue.step();
runAudio();
step();
}
// Prevent an infinite emulator hang when games miss vblank
if(io.vcounter > vlines()) {
scheduler.exit(Event::Frame);
io.vcounter = 0;
}
}
auto TIA::pixel(n8 x) -> void {
@@ -144,6 +150,14 @@ auto TIA::runBall(n8 x) -> n1 {
}
auto TIA::frame() -> void {
auto height = io.vcounter;
if(height <= 0) {
debug(unusual, "invalid screen height");
height = vlines();
}
screen->setViewport(0, 0, 160, height);
screen->frame();
scheduler.exit(Event::Frame);
}
@@ -163,7 +177,7 @@ auto TIA::power(bool reset) -> void {
ball = {};
collision = {};
for(auto n : range(writeQueue.maxItems)) writeQueue.items[n] = {};
audio[0] = {}; audio[1] = {};
for(u32 level : range(15)) {
volume[level] = pow(2, level * -2.0 / 6.0);
}
+1
View File
@@ -4,6 +4,7 @@ struct TIA : Thread {
Node::Audio::Stream stream;
auto vlines() const -> u32 { return Region::NTSC() ? 262 : 312; }
auto displayHeight() const -> u32 { return Region::NTSC() ? 192 : 228; }
//tia.cpp
auto load(Node::Object) -> void;
+1 -1
View File
@@ -23,7 +23,7 @@ auto TIA::WriteQueue::step() -> void {
auto TIA::WriteQueue::QueueItem::commit() -> void {
switch(address) {
case 0x01: tia.io.vblank = data.bit(1); return; // VBLANK
case 0x01: tia.io.vblank = data.bit(1); if(tia.io.vblank == 0) { tia.io.vcounter = 0; } return; // VBLANK
case 0x0b: tia.player[0].reflect = data.bit(3); return; // REFP0
case 0x0c: tia.player[1].reflect = data.bit(3); return; // REFP1
case 0x0d: tia.playfield.graphics.bit(0, 3) = data.bit(4, 7); return; // PF0
+4 -2
View File
@@ -8,10 +8,12 @@
#include <nall/any.hpp>
#include <nall/array.hpp>
#include <nall/bump-allocator.hpp>
#include <nall/case-range.hpp>
#include <nall/chrono.hpp>
#include <nall/directory.hpp>
#include <nall/dl.hpp>
#include <nall/endian.hpp>
#include <nall/hashset.hpp>
#include <nall/image.hpp>
#include <nall/literals.hpp>
#include <nall/priority-queue.hpp>
@@ -35,10 +37,11 @@
#include <nall/hash/crc32.hpp>
#include <nall/hash/sha256.hpp>
using namespace nall;
using namespace nall::primitives;
namespace ares {
static const string Name = "ares";
static const string Version = "129";
static const string Version = "133";
static const string Copyright = "ares team, Near";
static const string License = "ISC";
static const string LicenseURI = "https://opensource.org/licenses/ISC";
@@ -47,7 +50,6 @@ namespace ares {
//incremented only when serialization format changes
static const u32 SerializerSignature = 0x31545342; //"BST1" (little-endian)
static const string SerializerVersion = "129";
namespace VFS {
using Pak = shared_pointer<vfs::directory>;
+4 -4
View File
@@ -4,19 +4,19 @@ struct Debug {
auto reset() -> void;
template<typename... P> auto unhandled(P&&... p) -> void {
return _unhandled({forward<P>(p)...});
return _unhandled({std::forward<P>(p)...});
}
template<typename... P> auto unimplemented(P&&... p) -> void {
return _unimplemented({forward<P>(p)...});
return _unimplemented({std::forward<P>(p)...});
}
template<typename... P> auto unusual(P&&... p) -> void {
return _unusual({forward<P>(p)...});
return _unusual({std::forward<P>(p)...});
}
template<typename... P> auto unverified(P&&... p) -> void {
return _unverified({forward<P>(p)...});
return _unverified({std::forward<P>(p)...});
}
private:
+1 -1
View File
@@ -2,7 +2,7 @@
namespace ares::Memory {
#if defined(PLATFORM_MACOS) && defined(ARCHITECTURE_ARM64)
#if defined(PLATFORM_MACOS)
//stub for unsupported platforms
FixedAllocator::FixedAllocator() {
}
+14 -14
View File
@@ -1,14 +1,14 @@
#pragma once
namespace ares::Memory {
struct FixedAllocator {
static auto get() -> bump_allocator&;
private:
FixedAllocator();
bump_allocator _allocator;
};
}
#pragma once
namespace ares::Memory {
struct FixedAllocator {
static auto get() -> bump_allocator&;
private:
FixedAllocator();
bump_allocator _allocator;
};
}
+1 -1
View File
@@ -25,7 +25,7 @@ struct Stream : Audio {
template<typename... P>
auto frame(P&&... p) -> void {
if(runAhead()) return;
f64 samples[sizeof...(p)] = {forward<P>(p)...};
f64 samples[sizeof...(p)] = {f64(std::forward<P>(p))...};
write(samples);
}
+33 -16
View File
@@ -18,13 +18,14 @@ struct Instruction : Tracer {
auto setMask(bool mask) -> void {
_mask = mask;
_masks.reset();
}
auto setDepth(u32 depth) -> void {
_depth = depth;
_history.reset();
_history.resize(depth);
for(auto& history : _history) history = ~0;
for(auto& history : _history) history = ~0ull;
}
auto address(u64 address) -> bool {
@@ -32,9 +33,10 @@ struct Instruction : Tracer {
_address = address;
address >>= _addressMask; //clip unneeded alignment bits (to reduce _masks size)
if(_mask && updateMasks()) {
if(_masks[address >> 3] & 1 << (address & 7)) return false; //do not trace twice
_masks[address >> 3] |= 1 << (address & 7);
if(_mask) {
auto mask = _masks.find(address);
if(!mask) mask = _masks.insert(address);
if(mask->visit(address)) return false; //do not trace twice
}
if(_depth) {
@@ -56,10 +58,12 @@ struct Instruction : Tracer {
//mark an already-executed address as not executed yet for trace masking.
//call when writing to executable RAM to support self-modifying code.
auto invalidate(u64 address) -> void {
if(unlikely(_mask && updateMasks())) {
if(unlikely(_mask)) {
address &= ~0ull >> (64 - _addressBits);
address >>= _addressMask;
_masks[address >> 3] &= ~(1 << (address & 7));
auto mask = _masks.find(address);
if(mask) mask->unvisit(address);
}
}
@@ -103,14 +107,27 @@ struct Instruction : Tracer {
}
protected:
auto updateMasks() -> bool {
auto size = 1ull << (_addressBits - _addressMask - 3);
if(!_mask || !size) return _masks.reset(), false;
if(_masks.size() == size) return true;
_masks.reset();
_masks.resize(size);
return true;
}
struct VisitMask {
VisitMask(u64 address) : upper(address >> 6), mask(0) {}
auto operator==(const VisitMask& source) const -> bool { return upper == source.upper; }
auto hash() const -> u32 { return upper; }
auto visit(u64 address) -> bool {
const u64 bit = 1ull << (address & 0x3f);
if(mask & bit) return true;
mask |= bit;
return false;
}
auto unvisit(u64 address) -> void {
const u64 bit = 1ull << (address & 0x3f);
mask &= ~bit;
}
private:
u64 upper;
u64 mask;
};
u32 _addressBits = 32;
u32 _addressMask = 0;
@@ -120,6 +137,6 @@ protected:
//unserialized:
n64 _address = 0;
n64 _omitted = 0;
vector<u32> _history;
vector<u08> _masks;
vector<u64> _history;
hashset<VisitMask> _masks;
};
+1
View File
@@ -1,4 +1,5 @@
struct Input : Object {
DeclareClass(Input, "input")
using Object::Object;
u64 lastPoll;
};
+2 -2
View File
@@ -33,7 +33,7 @@ struct Object : shared_pointer_this<Object> {
template<typename T, typename... P>
auto prepend(P&&... p) -> Node::Object {
using Type = typename T::type;
return prepend(shared_pointer<Type>::create(forward<P>(p)...));
return prepend(shared_pointer<Type>::create(std::forward<P>(p)...));
}
auto append(Node::Object node) -> Node::Object {
@@ -47,7 +47,7 @@ struct Object : shared_pointer_this<Object> {
template<typename T, typename... P>
auto append(P&&... p) -> Node::Object {
using Type = typename T::type;
return append(shared_pointer<Type>::create(forward<P>(p)...));
return append(shared_pointer<Type>::create(std::forward<P>(p)...));
}
auto remove(Node::Object node) -> void {
+4 -4
View File
@@ -82,10 +82,10 @@ protected:
u32 _rotation = 0; //counter-clockwise (90 = left, 270 = right)
function<n64 (n32)> _color;
unique_pointer<u32> _inputA;
unique_pointer<u32> _inputB;
unique_pointer<u32> _output;
unique_pointer<u32> _rotate;
unique_pointer<u32[]> _inputA;
unique_pointer<u32[]> _inputB;
unique_pointer<u32[]> _output;
unique_pointer<u32[]> _rotate;
unique_pointer<u32[]> _palette;
vector<Node::Video::Sprite> _sprites;
+1 -1
View File
@@ -92,7 +92,7 @@ inline auto Thread::synchronize(Thread& thread, P&&... p) -> void {
co_switch(thread.handle());
}
//convenience: allow synchronizing multiple threads with one function call.
if constexpr(sizeof...(p) > 0) synchronize(forward<P>(p)...);
if constexpr(sizeof...(p) > 0) synchronize(std::forward<P>(p)...);
}
inline auto Thread::serialize(serializer& s) -> void {
+2
View File
@@ -196,9 +196,11 @@ auto AY38910::write(n8 data) -> void {
envelope.output = !envelope.attacking ? 15 : 0;
break;
case 14:
portA.data = data;
writeIO(0, data);
break;
case 15:
portB.data = data;
writeIO(1, data);
break;
}
+7 -3
View File
@@ -20,17 +20,17 @@ auto SN76489::clock() -> array<n4[4]> {
}
auto SN76489::Tone::clock() -> void {
if(!counter--) {
if(!counter || !--counter) {
counter = pitch;
output ^= 1;
}
}
auto SN76489::Noise::clock() -> void {
if(!counter--) {
if(!counter || !--counter) {
counter = array<n10[4]>{0x10, 0x20, 0x40, pitch}[rate];
if(flip ^= 1) { //0->1 transition
output = !lfsr.bit(0);
output = lfsr.bit(0);
lfsr = (lfsr.bit(0) ^ lfsr.bit(3) & enable) << 15 | lfsr >> 1;
}
}
@@ -63,6 +63,10 @@ auto SN76489::write(n8 data) -> void {
case 0: tone0.pitch.bit(4,9) = data.bit(0,5); break;
case 1: tone1.pitch.bit(4,9) = data.bit(0,5); break;
case 2: tone2.pitch.bit(4,9) = data.bit(0,5); noise.pitch = tone2.pitch; break;
case 3: noise.rate = data.bit(0,1);
noise.enable = data.bit(2);
noise.lfsr = 0x8000;
break;
}
}
}
+81 -22
View File
@@ -1,47 +1,106 @@
auto YM2610::read(n2 address) -> n8 {
switch(address) {
case 0: return fm.readStatus();
case 1: return ssg.read();
case 2: return pcmStatus();
}
debug(unimplemented, "[YM2610] read ", hex(address));
return 0;
}
auto YM2610::pcmStatus() -> n8 {
n8 output;
for(auto c : range(6)) output.bit(c) = pcmA.channels[c].ended;
output.bit(7) = pcmB.ended;
return output;
}
auto YM2610::write(n2 address, n8 data) -> void {
switch(address) {
case 0: register = 0x000 | data; return;
case 0: {
registerAddress = 0x000 | data;
if (registerAddress <= 0xf) ssg.select(registerAddress);
else fm.writeAddress(registerAddress);
return;
}
case 1: return writeLower(data);
case 2: register = 0x100 | data; return;
case 2: registerAddress = 0x100 | data; fm.writeAddress(registerAddress); return;
case 3: return writeUpper(data);
}
}
auto YM2610::writeLower(n8 data) -> void {
switch(register) {
case 0x000 ... 0x00f:
ssg.select(register);
ssg.write(data);
return;
case 0x010 ... 0x01b:
//ADPCM-B
switch(registerAddress) {
case range16(0x000, 0x00f):
ssg.write(data);
return;
case 0x010:
pcmB.repeat = data.bit(4);
if(data.bit(0)) pcmB.power();
if(data.bit(7)) pcmB.beginPlay();
else pcmB.playing = 0;
return;
case 0x011: pcmB.left = data.bit(7);
pcmB.right = data.bit(6); return;
case 0x012: pcmB.startAddress.bit( 8, 15) = data; return;
case 0x013: pcmB.startAddress.bit(16, 23) = data; return;
case 0x014: pcmB.endAddress.bit ( 8, 15) = data; return;
case 0x015: pcmB.endAddress.bit (16, 23) = data; return;
case range3(0x016, 0x018):
debug(unimplemented, "[YM2610::ADPCMB] Write ", hex(registerAddress), " = ", data);
return;
case 0x019: pcmB.delta.bit ( 0, 7) = data; return;
case 0x01a: pcmB.delta.bit ( 8, 15) = data; return;
case 0x01b: pcmB.volume = data; return;
case 0x01c:
//EOS
return;
case 0x01d ... 0x1ff:
fm.writeAddress(register);
fm.writeData(data);
for(auto c : range(6)) {
pcmA.channels[c].endedMask = data.bit(c);
if(data.bit(c)) pcmA.channels[c].ended = 0;
}
pcmB.endedMask = data.bit(7);
if(data.bit(7)) pcmB.ended = 0;
return;
default:
if(registerAddress >= 0x01d && registerAddress <= 0x1ff) {
fm.writeData(data);
return;
}
break;
}
unreachable;
debug(unimplemented, "[YM2610] Write ", hex(registerAddress), " = ", data);
}
auto YM2610::writeUpper(n8 data) -> void {
switch(register) {
case 0x000 ... 0x12f:
//ADPCM-A
return;
case 0x130 ... 0x1ff:
fm.writeAddress(register);
fm.writeData(data);
switch(registerAddress) {
case 0x100:
for(auto n : range(6)) {
if(!data.bit(n)) continue;
if(data.bit(7)) {
pcmA.channels[n].keyOff();
continue;
}
pcmA.channels[n].keyOn();
}
return;
case 0x101: pcmA.volume = data.bit(0, 5); return;
case range6(0x108, 0x10d): pcmA.channels[registerAddress - 0x108].volume = data.bit(0,4);
pcmA.channels[registerAddress - 0x108].left = data.bit(7);
pcmA.channels[registerAddress - 0x108].right = data.bit(6); return;
case range6(0x110, 0x115): pcmA.channels[registerAddress - 0x110].startAddress.bit( 8, 15) = data; return;
case range6(0x118, 0x11d): pcmA.channels[registerAddress - 0x118].startAddress.bit(16, 23) = data; return;
case range6(0x120, 0x125): pcmA.channels[registerAddress - 0x120].endAddress.bit ( 8, 15) = data; return;
case range6(0x128, 0x12d): pcmA.channels[registerAddress - 0x128].endAddress.bit (16, 23) = data; return;
default:
if(registerAddress >= 0x130 && registerAddress <= 0x1ff) {
fm.writeAddress(registerAddress);
fm.writeData(data);
return;
}
break;
}
debug(unimplemented, "[YM2610] Write ", hex(registerAddress), " = ", data);
}
+153
View File
@@ -0,0 +1,153 @@
auto YM2610::PCMA::power() -> void {
for(auto c : range(6)) {
channels[c].startAddress.bit(0, 7) = 0x00;
channels[c].endAddress.bit(0, 7) = 0x00;
channels[c].decodeAccumulator = 0;
channels[c].decodeStep = 0;
}
i16 stepSize[] = {
16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
};
// Generate a decode table
for (int step = 0; step < 49; step++) {
for (int nibble = 0; nibble < 16; nibble++) {
int value = (2 * (nibble & 0x07) + 1) * stepSize[step] / 8;
decodeTable[step * 16 + nibble] = ((nibble & 0x08) != 0) ? -value : value;
}
}
}
auto YM2610::PCMA::clock() -> array<i16[2]> {
f32 left = 0;
f32 right = 0;
for(auto c : range(6)) {
if(!channels[c].playing) continue;
if(((channels[c].currentAddress ^ (channels[c].endAddress + (1 << 8))) & 0xfffff) == 0) {
channels[c].playing = 0;
if(!channels[c].endedMask) channels[c].ended = 1;
continue;
}
auto sample = channels[c].decode(self.readPCMA(channels[c].currentAddress));
int totalVolume = (volume ^ 0x3f) + (channels[c].volume ^ 0x1f);
int volumeMultiplier = 15 - (totalVolume & 7);
int volumeShift = 5 + (totalVolume >> 3);
sample = ((sample * volumeMultiplier) >> volumeShift) & ~3;
if(channels[c].left) left += sample / 2047.0f;
if(channels[c].right) right += sample / 2047.0f;
}
return {sclamp<16>(left * 32768.0), sclamp<16>(right * 32768.0)};
}
auto YM2610::PCMA::Channel::keyOn() -> void {
if(ended) return;
playing = 1;
currentAddress = startAddress;
decodeAccumulator = 0;
decodeStep = 0;
currentNibble = 0;
}
auto YM2610::PCMA::Channel::keyOff() -> void {
playing = 0;
}
auto YM2610::PCMA::Channel::decode(n8 value) -> i12 {
int stepAdjust[] = { -1, -1, -1, -1, 2, 5, 7, 9, -1, -1, -1, -1, 2, 5, 7, 9 };
value = currentNibble ? value.bit(0, 3) : value.bit(4, 7);
if(currentNibble) currentAddress++;
currentNibble = !currentNibble;
decodeAccumulator += self.decodeTable[decodeStep + value];
decodeStep += stepAdjust[value & 7] * 16;
decodeStep = std::clamp((int)decodeStep, 0, 48 * 16);
return decodeAccumulator;
}
auto YM2610::PCMB::power() -> void {
currentNibble = 0;
currentAddress = 0;
decodeAccumulator = 0;
previousAccumulator = 0;
decodePosition = 0;
decodeStep = 127;
volume = 255;
}
auto YM2610::PCMB::clock() -> array<i16[2]> {
f32 leftSample = 0;
f32 rightSample = 0;
decode();
i32 sample = (previousAccumulator * (i32)((decodePosition ^ 0xffff) + 1) + decodeAccumulator * (i32)(decodePosition)) >> 16;
sample = (sample * (i32)volume) >> 9;
if(left) leftSample += (sample / 65535.0);
if(right) rightSample += (sample / 65535.0);
return {sclamp<16>(leftSample * 32768.0), sclamp<16>(rightSample * 32768.0)};
}
auto YM2610::PCMB::decode() -> void {
if(!playing) {
return;
}
u8 stepSize[8] = { 57, 57, 57, 57, 77, 102, 128, 153 };
u32 position = decodePosition + delta;
decodePosition = (u16)position;
if(position < 0x10000) return;
n8 value = self.readPCMB(currentAddress);
value = currentNibble ? value.bit(0, 3) : value.bit(4, 7);
currentNibble = !currentNibble;
if(currentNibble == 0) {
currentAddress++;
if(currentAddress == endAddress) {
if(repeat) beginPlay();
else {
decodeAccumulator = 0;
previousAccumulator = 0;
playing = 0;
if(!endedMask) ended = 1;
}
}
}
previousAccumulator = decodeAccumulator;
i32 _delta = (value.bit(0, 2) * 2 + 1) * decodeStep / 8;
if(value.bit(3)) _delta = -_delta;
decodeAccumulator = sclamp<16>(decodeAccumulator + _delta);
decodeStep = std::clamp(((int)decodeStep * stepSize[value.bit(0, 2)]) / 64, 127, 24576);
}
auto YM2610::PCMB::beginPlay() -> void {
if(ended) return;
currentAddress = startAddress;
currentNibble = 0;
decodeAccumulator = 0;
previousAccumulator = 0;
decodePosition = 0;
decodeStep = 127;
playing = 1;
}
+40 -1
View File
@@ -1,5 +1,44 @@
auto YM2610::serialize(serializer& s) -> void {
s(register);
s(registerAddress);
s(fm);
s(ssg);
s(pcmA);
s(pcmB);
}
auto YM2610::PCMA::serialize(serializer& s) -> void {
for(auto n : range(6)) {
s(channels[n].playing);
s(channels[n].ended);
s(channels[n].endedMask);
s(channels[n].left);
s(channels[n].right);
s(channels[n].volume);
s(channels[n].startAddress);
s(channels[n].endAddress);
s(channels[n].currentAddress);
s(channels[n].decodeAccumulator);
s(channels[n].decodeStep);
s(channels[n].currentNibble);
}
}
auto YM2610::PCMB::serialize(serializer& s) -> void {
s(playing);
s(ended);
s(endedMask);
s(repeat);
s(left);
s(right);
s(startAddress);
s(endAddress);
s(delta);
s(volume);
s(currentAddress);
s(currentNibble);
s(decodeAccumulator);
s(decodePosition);
s(previousAccumulator);
s(decodeStep);
}
+3
View File
@@ -4,11 +4,14 @@
namespace ares {
#include "io.cpp"
#include "pcm.cpp"
#include "serialization.cpp"
auto YM2610::power() -> void {
fm.power();
ssg.power();
pcmA.power();
pcmB.power();
}
}
+69 -1
View File
@@ -16,14 +16,82 @@ struct YM2610 {
auto write(n2 address, n8 data) -> void;
auto writeLower(n8 data) -> void;
auto writeUpper(n8 data) -> void;
auto pcmStatus() -> n8;
//serialization.cpp
auto serialize(serializer&) -> void;
virtual auto readPCMA(u32 address) -> u8 { return 0; }
virtual auto readPCMB(u32 address) -> u8 { return 0; }
protected:
n9 register;
n9 registerAddress;
YM2612 fm;
YM2149 ssg;
struct PCMA {
YM2610& self;
// pcm.cpp
auto power() -> void;
auto clock() -> array<i16[2]>;
//serialization.cpp
auto serialize(serializer&) -> void;
struct Channel {
PCMA& self;
auto keyOn() -> void;
auto keyOff() -> void;
auto decode(n8) -> i12;
n1 playing;
n1 ended;
n1 endedMask;
n1 left;
n1 right;
n5 volume;
n32 startAddress;
n32 endAddress;
n32 currentAddress;
i12 decodeAccumulator;
i32 decodeStep;
bool currentNibble;
} channels[6]{{*this}, {*this}, {*this}, {*this}, {*this}, {*this}};
n6 volume;
int decodeTable[16 * 49];
} pcmA{*this};
struct PCMB {
YM2610& self;
// pcm.cpp
auto power() -> void;
auto clock() -> array<i16[2]>;
auto decode() -> void;
auto beginPlay() -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
n1 playing;
n1 ended;
n1 endedMask;
n1 repeat;
n1 left;
n2 right;
n32 startAddress;
n32 endAddress;
n16 delta;
n8 volume;
n32 currentAddress;
bool currentNibble;
i32 decodeAccumulator;
u32 decodePosition;
i32 previousAccumulator;
i32 decodeStep;
} pcmB{*this};
};
}
+31 -29
View File
@@ -1,9 +1,6 @@
auto YM2612::Channel::Operator::trigger(bool state) -> void {
auto YM2612::Channel::Operator::updateKeyState(bool state) -> void {
if(keyOn == state) return; //no change
keyOn = state;
envelope.state = Release;
updateEnvelope();
if(keyOn) {
//restart phase and envelope generators
@@ -13,42 +10,46 @@ auto YM2612::Channel::Operator::trigger(bool state) -> void {
updateEnvelope();
if(envelope.rate >= 62) {
//skip attack and possibly decay stages
//skip attack phase
envelope.value = 0;
envelope.state = envelope.sustainLevel ? Decay : Sustain;
updateEnvelope();
}
} else if(ssg.enable && ssg.attack != ssg.invert) {
//SSG-EG key-off
envelope.value = 0x200 - envelope.value;
} else {
envelope.state = Release;
updateEnvelope();
if(ssg.enable && ssg.attack != ssg.invert) {
//SSG-EG key-off
envelope.value = 0x200 - envelope.value;
}
}
updateLevel();
}
auto YM2612::Channel::Operator::runEnvelope() -> void {
u32 sustain = envelope.sustainLevel < 15 ? envelope.sustainLevel << 5 : 0x3f0;
updateKeyState(keyLine);
if(ym2612.envelope.clock & (1 << envelope.divider) - 1) return;
u32 value = ym2612.envelope.clock >> envelope.divider;
u32 step = envelope.steps >> ((~value & 7) << 2) & 0xf;
if(ssg.enable) step <<= 2; //SSG results in a 4x faster envelope
u32 sustain = envelope.sustainLevel < 15 ? envelope.sustainLevel << 5 : 0x1f << 5;
if(envelope.state == Attack) {
u32 next = envelope.value + (~u16(envelope.value) * step >> 4) & 0x3ff;
if(next <= envelope.value) {
envelope.value = next;
} else {
envelope.value = 0;
envelope.state = envelope.value < sustain ? Decay : Sustain;
if(envelope.value == 0) {
envelope.state = Decay;
updateEnvelope();
} else if(envelope.rate < 62) {
// will stop updating if attack rate is increased to upper threshold during attack phase (confirmed behavior)
envelope.value += ~u16(envelope.value) * step >> 4;
}
} else if(!ssg.enable || envelope.value < 0x200) {
envelope.value = min(envelope.value + step, 0x3ff);
}
if(envelope.state != Attack) {
if(envelope.state == Decay && envelope.value >= sustain) {
envelope.state = Sustain;
updateEnvelope();
}
if(ssg.enable) step = envelope.value < 0x200 ? step << 2 : 0; //SSG results in a 4x faster envelope
envelope.value = min(envelope.value + step, 0x3ff);
}
updateLevel();
@@ -59,18 +60,19 @@ auto YM2612::Channel::Operator::runPhase() -> void {
if(!(ssg.enable && envelope.value >= 0x200)) return; //SSG loop check
if(!ssg.hold && !ssg.alternate) phase.value = 0;
if(!ssg.hold || ssg.attack == ssg.invert) ssg.invert ^= ssg.alternate;
if(!(ssg.hold && ssg.invert)) ssg.invert ^= ssg.alternate;
if(envelope.state == Attack) {
//do nothing; SSG is meant to skip the attack phase
} else if(envelope.state != Release && !ssg.hold) {
//if still looping, reset the envelope
envelope.state = Attack;
if(envelope.attackRate >= 62) {
envelope.value = 0;
envelope.state = envelope.sustainLevel ? Decay : Sustain;
}
updateEnvelope();
if(envelope.rate >= 62) {
//skip attack phase
envelope.value = 0;
}
} else if(envelope.state == Release || (ssg.hold && ssg.attack == ssg.invert)) {
//clear envelope once finished
envelope.value = 0x3ff;
@@ -115,11 +117,9 @@ auto YM2612::Channel::Operator::updatePhase() -> void {
u32 tuning = detune & 3 ? detunes[(detune & 3) - 1][ksr & 7] >> (3 - (ksr >> 3)) : 0;
u32 lfo = ym2612.lfo.clock >> 2 & 0x1f;
u32 pm = 4 * vibratos[channel.vibrato][lfo & 15] * (-lfo >> 4);
u32 msb = 10;
while(msb > 4 && ~pitch.value & 1 << msb) msb--;
s32 pm = (pitch.value * vibratos[channel.vibrato][lfo & 15] >> 9) * (lfo > 15 ? -1 : 1);
phase.delta = pitch.value + (pm >> 10 - msb) << 6 >> 7 - octave.value;
phase.delta = pitch.value + pm << 6 >> 7 - octave.value;
phase.delta = (!detune.bit(2) ? phase.delta + tuning : phase.delta - tuning) & 0x1ffff;
phase.delta = (multiple ? phase.delta * multiple : phase.delta >> 1) & 0xfffff;
}
@@ -147,6 +147,7 @@ auto YM2612::Channel::power() -> void {
for(auto& op : operators) {
op.keyOn = 0;
op.keyLine = 0;
op.lfoEnable = 0;
op.detune = 0;
op.multiple = 0;
@@ -155,6 +156,7 @@ auto YM2612::Channel::power() -> void {
op.outputLevel = 0x1fff;
op.output = 0;
op.prior = 0;
op.priorBuffer = 0;
op.pitch.value = 0;
op.pitch.reload = 0;
+15 -10
View File
@@ -14,6 +14,8 @@ auto YM2612::writeData(n8 data) -> void {
case 0x022: {
lfo.rate = data.bit(0,2);
lfo.enable = data.bit(3);
lfo.clock = 0;
lfo.divider = 0;
break;
}
@@ -37,11 +39,12 @@ auto YM2612::writeData(n8 data) -> void {
//timer control
case 0x027: {
//d6,d7 = mode (unimplemented; treated as mode 0 always)
//reload period on 0->1 transition
if(!timerA.enable && data.bit(0)) timerA.counter = timerA.period;
if(!timerB.enable && data.bit(1)) timerB.counter = timerB.period;
if(!timerB.enable && data.bit(1)) {
timerB.counter = timerB.period;
timerB.divider = 0;
}
timerA.enable = data.bit(0);
timerB.enable = data.bit(1);
@@ -51,6 +54,7 @@ auto YM2612::writeData(n8 data) -> void {
if(data.bit(4)) timerA.line = 0;
if(data.bit(5)) timerB.line = 0;
//d7 is enable bit for CSM mode (not yet implemented)
channels[2].mode = data.bit(6,7);
for(auto& op : channels[2].operators) op.updatePitch();
@@ -64,10 +68,10 @@ auto YM2612::writeData(n8 data) -> void {
if(index == 3 || index == 7) break;
if(index >= 4) index--;
channels[index][0].trigger(data.bit(4));
channels[index][1].trigger(data.bit(5));
channels[index][2].trigger(data.bit(6));
channels[index][3].trigger(data.bit(7));
channels[index][0].keyLine = data.bit(4);
channels[index][1].keyLine = data.bit(5);
channels[index][2].keyLine = data.bit(6);
channels[index][3].keyLine = data.bit(7);
break;
}
@@ -145,10 +149,11 @@ auto YM2612::writeData(n8 data) -> void {
//SSG-EG
case 0x090: {
op.ssg.hold = data.bit(0);
op.ssg.alternate = data.bit(1);
op.ssg.attack = data.bit(2);
op.ssg.enable = data.bit(3);
op.ssg.hold = op.ssg.enable ? data.bit(0) : 0;
op.ssg.alternate = op.ssg.enable ? data.bit(1) : 0;
op.ssg.attack = op.ssg.enable ? data.bit(2) : 0;
channel[index].updateLevel();
break;
}
@@ -42,6 +42,7 @@ auto YM2612::Channel::serialize(serializer& s) -> void {
auto YM2612::Channel::Operator::serialize(serializer& s) -> void {
s(keyOn);
s(keyLine);
s(lfoEnable);
s(detune);
s(multiple);
@@ -49,6 +50,7 @@ auto YM2612::Channel::Operator::serialize(serializer& s) -> void {
s(outputLevel);
s(output);
s(prior);
s(priorBuffer);
s(pitch.value);
s(pitch.reload);
+21 -7
View File
@@ -27,16 +27,20 @@ auto YM2612::clock() -> array<i16[2]> {
auto wave = [&](u32 n, u32 modulation) -> s32 {
s32 x = (modulation >> 1) + (op[n].phase.value >> 10);
s32 y = sine[x & 0x3ff] + op[n].outputLevel;
return y < 0x2000 ? pow2[y & 0x1ff] << 2 >> (y >> 9) : 0;
return y < 0x1a00 ? pow2[y & 0x1ff] << 2 >> (y >> 9) : 0; // -78 dB floor
};
s32 feedback = modMask & op[0].output + op[0].prior >> 9 - channel.feedback;
s32 feedback = modMask & op[0].prior + op[0].priorBuffer >> 9 - channel.feedback;
s32 accumulator = 0;
op[0].priorBuffer = op[0].prior; // only need to buffer the output for feedback
for(auto n : range(4)) op[n].prior = op[n].output;
op[0].output = wave(0, feedback * (channel.feedback > 0));
// Note: Despite not emulating per cycle, operator pipelining has been accounted for.
// Given the op order 0-2-1-3, newly generated output is not available for the following op.
if(channel.algorithm == 0) {
//0 -> 1 -> 2 -> 3
op[1].output = wave(1, mod(0));
@@ -48,7 +52,7 @@ auto YM2612::clock() -> array<i16[2]> {
if(channel.algorithm == 1) {
//(0 + 1) -> 2 -> 3
op[1].output = wave(1, 0);
op[2].output = wave(2, mod(0) + old(1));
op[2].output = wave(2, old(0) + old(1));
op[3].output = wave(3, mod(2));
accumulator += out(3);
}
@@ -65,7 +69,7 @@ auto YM2612::clock() -> array<i16[2]> {
//(0 -> 1) + 2 -> 3
op[1].output = wave(1, mod(0));
op[2].output = wave(2, 0);
op[3].output = wave(3, mod(1) + mod(2));
op[3].output = wave(3, old(1) + mod(2));
accumulator += out(3);
}
@@ -104,8 +108,18 @@ auto YM2612::clock() -> array<i16[2]> {
s32 voiceData = sclamp<14>(accumulator) & outMask;
if(dac.enable && (&channel == &channels[5])) voiceData = (s32)dac.sample - 0x80 << 6;
if(channel.leftEnable ) left += voiceData;
if(channel.rightEnable) right += voiceData;
// DAC output + voltage offset (crossover distortion)
if(voiceData < 0) {
left += channel.leftEnable * (voiceData + (1<<5)) - (4<<5);
right += channel.rightEnable * (voiceData + (1<<5)) - (4<<5);
} else {
left += channel.leftEnable * (voiceData + (0<<5)) + (4<<5);
right += channel.rightEnable * (voiceData + (0<<5)) + (4<<5);
}
// DAC output (ym3438 fix)
//if(channel.leftEnable ) left += voiceData;
//if(channel.rightEnable) right += voiceData;
}
timerA.run();
@@ -124,7 +138,7 @@ auto YM2612::clock() -> array<i16[2]> {
if(++envelope.divider == 3) {
envelope.divider = 0;
envelope.clock++;
if(!++envelope.clock) ++envelope.clock; // 12-bit counter: 1..4095 - zero-value is skipped (confirmed behavior)
}
for(auto& channel : channels) {
+4 -2
View File
@@ -36,7 +36,7 @@ protected:
} dac;
struct Envelope {
n32 clock = 0;
n12 clock = 0;
n32 divider = 0;
} envelope;
@@ -91,7 +91,7 @@ protected:
Operator(Channel& channel) : channel(channel), ym2612(channel.ym2612) {}
//channel.cpp
auto trigger(bool) -> void;
auto updateKeyState(bool) -> void;
auto runEnvelope() -> void;
auto runPhase() -> void;
@@ -105,6 +105,7 @@ protected:
auto serialize(serializer&) -> void;
n1 keyOn = 0;
n1 keyLine = 0;
n1 lfoEnable = 0;
n3 detune = 0;
n4 multiple = 0;
@@ -113,6 +114,7 @@ protected:
n16 outputLevel = 0x1fff;
i16 output = 0;
i16 prior = 0;
i16 priorBuffer = 0;
struct Pitch {
n11 value = 0;
@@ -30,20 +30,6 @@ auto GSU::disassembleOpcode(char* output) -> void {
while(length++ < 20) strcat(output, " ");
}
#define case4(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3
#define case6(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5
#define case12(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
case id+ 8: case id+ 9: case id+10: case id+11
#define case15(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14
#define case16(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14: case id+15
#define op0 regs.pipeline
#define op1 read((regs.pbr << 16) + regs.r[15] + 0)
#define op2 read((regs.pbr << 16) + regs.r[15] + 1)
+10 -14
View File
@@ -1,17 +1,15 @@
auto HuC6280::algorithmADC(n8 i) -> n8 {
i16 o;
i16 o = A + i + C;
if(!D) {
o = A + i + C;
C = o.bit(8);
V = ~(A ^ i) & (A ^ o) & 0x80;
} else {
idle();
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o > 0x09) o += 0x06;
C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
n8 l = (A & 0x0f) + (i & 0x0f) + C;
if(l > 0x09) o += 0x06;
if(o > 0x9f) o += 0x60;
C = o > 0xff;
}
C = o.bit(8);
Z = n8(o) == 0;
N = o.bit(7);
return o;
@@ -125,19 +123,17 @@ auto HuC6280::algorithmROR(n8 i) -> n8 {
auto HuC6280::algorithmSBC(n8 i) -> n8 {
i ^= 0xff;
i16 o;
i16 o = A + i + C;
if(!D) {
o = A + i + C;
C = o.bit(8);
V = ~(A ^ i) & (A ^ o) & 0x80;
} else {
idle();
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o <= 0x0f) o -= 0x06;
C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
n8 l = (A & 0x0f) + (i & 0x0f) + C;
C = o > 0xff;
if(o <= 0xff) o -= 0x60;
if(l <= 0x0f) o -= 0x06;
}
C = o.bit(8);
Z = n8(o) == 0;
N = o.bit(7);
return o;
File diff suppressed because it is too large. Load diff
@@ -1,19 +1,32 @@
auto MOS6502::algorithmADC(n8 i) -> n8 {
i16 o;
i16 o = A + i + C;
if(!BCD || !D) {
o = A + i + C;
C = o.bit(8);
Z = n8(o) == 0;
N = o.bit(7);
V = ~(A ^ i) & (A ^ o) & 0x80;
} else {
idle();
Z = n8(o) == 0;
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o > 0x09) o += 0x06;
C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
N = o.bit(7);
V = ~(A ^ i) & (A ^ o) & 0x80;
if(o > 0x9f) o += 0x60;
C = o > 0xff;
}
C = o.bit(8);
Z = n8(o) == 0;
return o;
}
auto MOS6502::algorithmALR(n8 i) -> n8 {
n8 o = A & i;
C = o.bit(0);
o >>= 1;
Z = o == 0;
N = o.bit(7);
return o;
}
@@ -24,6 +37,29 @@ auto MOS6502::algorithmAND(n8 i) -> n8 {
return o;
}
auto MOS6502::algorithmANC(n8 i) -> n8 {
n8 o = A & i;
Z = o == 0;
N = o.bit(7);
C = N;
return o;
}
auto MOS6502::algorithmARR(n8 i) -> n8 {
n8 o = A & i;
Z = o == 0;
N = o.bit(7);
bool c = C;
o = c << 7 | o >> 1;
Z = o == 0;
N = o.bit(7);
C = o.bit(6);
V = o.bit(6) ^ o.bit(5);
return o;
}
auto MOS6502::algorithmASL(n8 i) -> n8 {
C = i.bit(7);
i <<= 1;
@@ -32,6 +68,23 @@ auto MOS6502::algorithmASL(n8 i) -> n8 {
return i;
}
auto MOS6502::algorithmATX(n8 i) -> n8 {
A |= 0xff; //TODO: OR value may differ on non-NES platforms
n8 o = A & i;
X = o;
Z = o == 0;
N = o.bit(7);
return o;
}
auto MOS6502::algorithmAXS(n8 i) -> n8 {
n9 o = (A & X) - i;
C = !o.bit(8);
Z = n8(o) == 0;
N = o.bit(7);
return o;
}
auto MOS6502::algorithmBIT(n8 i) -> n8 {
Z = (A & i) == 0;
V = i.bit(6);
@@ -125,20 +178,35 @@ auto MOS6502::algorithmROR(n8 i) -> n8 {
auto MOS6502::algorithmSBC(n8 i) -> n8 {
i = ~i;
i16 o;
i16 o = A + i + C;
if(!BCD || !D) {
o = A + i + C;
C = o.bit(8);
Z = n8(o) == 0;
N = o.bit(7);
V = ~(A ^ i) & (A ^ o) & 0x80;
} else {
idle();
Z = n8(o) == 0;
o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o <= 0x0f) o -= 0x06;
C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
N = o.bit(7);
V = ~(A ^ i) & (A ^ o) & 0x80;
if(o <= 0xff) o -= 0x60;
C = o > 0xff;
}
C = o.bit(8);
Z = n8(o) == 0;
N = o.bit(7);
return o;
}
auto MOS6502::algorithmSLO(n8 i) -> n8 {
C = i.bit(7);
i <<= 1;
Z = i == 0;
N = i.bit(7);
A |= i;
Z = A == 0;
N = A.bit(7);
return i;
}
@@ -23,23 +23,29 @@ auto MOS6502::instruction() -> void {
op(0x04, NoOperationZeroPage)
op(0x05, ZeroPageRead, fp(ORA), A)
op(0x06, ZeroPageModify, fp(ASL))
op(0x07, ZeroPageModify, fp(SLO))
op(0x08, PushP)
op(0x09, Immediate, fp(ORA), A)
op(0x0a, Implied, fp(ASL), A)
op(0x0b, Immediate, fp(ANC), A)
op(0x0c, NoOperationAbsolute)
op(0x0d, AbsoluteRead, fp(ORA), A)
op(0x0e, AbsoluteModify, fp(ASL))
op(0x0f, AbsoluteModify, fp(SLO))
op(0x10, Branch, N == 0)
op(0x11, IndirectYRead, fp(ORA), A)
op(0x14, NoOperationZeroPage, X)
op(0x15, ZeroPageRead, fp(ORA), A, X)
op(0x16, ZeroPageModify, fp(ASL), X)
op(0x17, ZeroPageModify, fp(SLO), X)
op(0x18, Clear, C)
op(0x19, AbsoluteRead, fp(ORA), A, Y)
op(0x1a, NoOperation)
op(0x1b, AbsoluteModify, fp(SLO), Y)
op(0x1c, NoOperationAbsolute, X)
op(0x1d, AbsoluteRead, fp(ORA), A, X)
op(0x1e, AbsoluteModify, fp(ASL), X)
op(0x1f, AbsoluteModify, fp(SLO), X)
op(0x20, CallAbsolute)
op(0x21, IndirectXRead, fp(AND), A)
op(0x24, ZeroPageRead, fp(BIT), A)
@@ -48,6 +54,7 @@ auto MOS6502::instruction() -> void {
op(0x28, PullP)
op(0x29, Immediate, fp(AND), A)
op(0x2a, Implied, fp(ROL), A)
op(0x2b, Immediate, fp(ANC), A)
op(0x2c, AbsoluteRead, fp(BIT), A)
op(0x2d, AbsoluteRead, fp(AND), A)
op(0x2e, AbsoluteModify, fp(ROL))
@@ -70,6 +77,7 @@ auto MOS6502::instruction() -> void {
op(0x48, Push, A)
op(0x49, Immediate, fp(EOR), A)
op(0x4a, Implied, fp(LSR), A)
op(0x4b, Immediate, fp(ALR), A)
op(0x4c, JumpAbsolute)
op(0x4d, AbsoluteRead, fp(EOR), A)
op(0x4e, AbsoluteModify, fp(LSR))
@@ -92,6 +100,7 @@ auto MOS6502::instruction() -> void {
op(0x68, Pull, A)
op(0x69, Immediate, fp(ADC), A)
op(0x6a, Implied, fp(ROR), A)
op(0x6b, Immediate, fp(ARR), A)
op(0x6c, JumpIndirect)
op(0x6d, AbsoluteRead, fp(ADC), A)
op(0x6e, AbsoluteModify, fp(ROR))
@@ -136,11 +145,13 @@ auto MOS6502::instruction() -> void {
op(0xa8, Transfer, A, Y, 1)
op(0xa9, Immediate, fp(LD), A)
op(0xaa, Transfer, A, X, 1)
op(0xab, Immediate, fp(ATX), A)
op(0xac, AbsoluteRead, fp(LD), Y)
op(0xad, AbsoluteRead, fp(LD), A)
op(0xae, AbsoluteRead, fp(LD), X)
op(0xb0, Branch, C == 1)
op(0xb1, IndirectYRead, fp(LD), A)
op(0xb3, IndirectYRead, fp(LD), A, X)
op(0xb4, ZeroPageRead, fp(LD), Y, X)
op(0xb5, ZeroPageRead, fp(LD), A, X)
op(0xb6, ZeroPageRead, fp(LD), X, Y)
@@ -159,6 +170,7 @@ auto MOS6502::instruction() -> void {
op(0xc8, Implied, fp(INC), Y)
op(0xc9, Immediate, fp(CMP), A)
op(0xca, Implied, fp(DEC), X)
op(0xcb, Immediate, fp(AXS), X)
op(0xcc, AbsoluteRead, fp(CPY), Y)
op(0xcd, AbsoluteRead, fp(CMP), A)
op(0xce, AbsoluteModify, fp(DEC))
@@ -182,6 +194,7 @@ auto MOS6502::instruction() -> void {
op(0xe8, Implied, fp(INC), X)
op(0xe9, Immediate, fp(SBC), A)
op(0xea, NoOperation)
op(0xeb, Immediate, fp(SBC), A)
op(0xec, AbsoluteRead, fp(CPX), X)
op(0xed, AbsoluteRead, fp(SBC), A)
op(0xee, AbsoluteModify, fp(INC))
@@ -199,6 +212,7 @@ auto MOS6502::instruction() -> void {
}
//unimplemented instruction
debug(unusual, "[6502] unimplemented opcode ", hex(code));
return instructionNoOperation();
}
@@ -112,6 +112,11 @@ auto MOS6502::instructionIndirectYRead(fp alu, n8& data) -> void {
L data = ALU(read(absolute + Y));
}
auto MOS6502::instructionIndirectYRead(fp alu, n8& data, n8& data2) -> void {
instructionIndirectYRead(alu, data);
data2 = data;
}
auto MOS6502::instructionIndirectYWrite(n8& data) -> void {
auto zeroPage = operand();
n16 absolute = load(zeroPage + 0);
+8 -2
View File
@@ -32,11 +32,17 @@ namespace ares {
#undef N
#undef L
auto MOS6502::power() -> void {
auto MOS6502::power(bool reset) -> void {
if(reset) {
S-=3;
P.i = 1;
return;
}
A = 0x00;
X = 0x00;
Y = 0x00;
S = 0xff;
S = 0xfd;
P = 0x04;
MDR = 0x00;
}
+8 -1
View File
@@ -14,7 +14,7 @@ struct MOS6502 {
virtual auto readDebugger(n16 addr) -> n8 { return 0; }
//mos6502.cpp
auto power() -> void;
auto power(bool reset = false) -> void;
//memory.cpp
auto idle() -> void;
@@ -31,7 +31,12 @@ struct MOS6502 {
using fp = auto (MOS6502::*)(n8) -> n8;
auto algorithmADC(n8) -> n8;
auto algorithmAND(n8) -> n8;
auto algorithmANC(n8) -> n8;
auto algorithmARR(n8) -> n8;
auto algorithmASL(n8) -> n8;
auto algorithmATX(n8) -> n8;
auto algorithmALR(n8) -> n8;
auto algorithmAXS(n8) -> n8;
auto algorithmBIT(n8) -> n8;
auto algorithmCMP(n8) -> n8;
auto algorithmCPX(n8) -> n8;
@@ -45,6 +50,7 @@ struct MOS6502 {
auto algorithmROL(n8) -> n8;
auto algorithmROR(n8) -> n8;
auto algorithmSBC(n8) -> n8;
auto algorithmSLO(n8) -> n8;
//instruction.cpp
auto interrupt() -> void;
@@ -66,6 +72,7 @@ struct MOS6502 {
auto instructionIndirectXRead(fp alu, n8& data) -> void;
auto instructionIndirectXWrite(n8& data) -> void;
auto instructionIndirectYRead(fp alu, n8& data) -> void;
auto instructionIndirectYRead(fp, n8& data, n8& data2) -> void;
auto instructionIndirectYWrite(n8& data) -> void;
auto instructionJumpAbsolute() -> void;
auto instructionJumpIndirect() -> void;
+2 -1
View File
@@ -2,7 +2,8 @@ struct Accuracy {
//enable all accuracy flags
static constexpr bool Reference = 0;
static constexpr bool Interpreter = 0 | Reference;
static constexpr bool Interpreter = 0 | Reference | !recompiler::generic::supported;
static constexpr bool CachedInterpreter = 0 & !Interpreter;
static constexpr bool Recompiler = !Interpreter;
//exceptions when the CPU or DMA accesses unaligned memory addresses
-71
View File
@@ -1,71 +0,0 @@
auto SH2::Recompiler::invalidate(u32 address) -> void {
auto pool = pools[address >> 8 & 0xffffff];
if(!pool) return;
memory::jitprotect(false);
pool->blocks[address >> 1 & 0x7f] = nullptr;
memory::jitprotect(true);
}
auto SH2::Recompiler::pool(u32 address) -> Pool* {
auto& pool = pools[address >> 8 & 0xffffff];
if(!pool) pool = (Pool*)allocator.acquire(sizeof(Pool));
return pool;
}
auto SH2::Recompiler::block(u32 address) -> Block* {
if(auto block = pool(address)->blocks[address >> 1 & 0x7f]) return block;
auto block = emit(address);
pool(address)->blocks[address >> 1 & 0x7f] = block;
memory::jitprotect(true);
return block;
}
alwaysinline auto SH2::Recompiler::emitInstruction(u16 opcode) -> bool {
#define op(id, name, ...) \
case id: \
call(&SH2::name, &self, ##__VA_ARGS__); \
return 0;
#define br(id, name, ...) \
case id: \
call(&SH2::name, &self, ##__VA_ARGS__); \
return 1;
#include "decoder.hpp"
#undef op
#undef br
return 0;
}
#define CCR mem(sreg(1), offsetof(Registers, CCR))
auto SH2::Recompiler::emit(u32 address) -> Block* {
if(unlikely(allocator.available() < 1_MiB)) {
print("SH2 allocator flush\n");
memory::jitprotect(false);
allocator.release(bump_allocator::zero_fill);
memory::jitprotect(true);
reset();
}
auto block = (Block*)allocator.acquire(sizeof(Block));
beginFunction(2);
bool hasBranched = 0;
while(true) {
u16 instruction = self.readWord(address);
bool branched = emitInstruction(instruction);
add64(CCR, CCR, imm(1));
call(&SH2::instructionEpilogue);
address += 2;
if(hasBranched || (address & 0xfe) == 0) break; //block boundary
hasBranched = branched;
testJumpEpilog();
}
jumpEpilog();
memory::jitprotect(false);
block->code = endFunction();
return block;
}
#undef CCR
+64 -64
View File
@@ -6,68 +6,68 @@
#define d8 (opcode >> 0 & 0x0ff)
#define d12 (opcode >> 0 & 0xfff)
switch(opcode >> 8 & 0x00f0 | opcode & 0x000f) {
op(0x04, MOVBS0, m, n); //MOV.B Rm,@(R0,Rn)
op(0x05, MOVWS0, m, n); //MOV.W Rm,@(R0,Rn)
op(0x06, MOVLS0, m, n); //MOV.L Rm,@(R0,Rn)
op(0x07, MULL, m, n); //MUL.L Rm,Rn
op(0x0c, MOVBL0, m, n); //MOV.B @(R0,Rm),Rn
op(0x0d, MOVWL0, m, n); //MOV.W @(R0,Rm),Rn
op(0x0e, MOVLL0, m, n); //MOV.L @(R0,Rm),Rn
op(0x0f, MACL_, m, n); //MAC.L @Rm+,@Rn+
op(0x10 ... 0x1f, MOVLS4, m, d4, n); //MOV.L Rm,@(disp,Rn)
op(0x20, MOVBS, m, n); //MOV.B Rm,@Rn
op(0x21, MOVWS, m, n); //MOV.W Rm,@Rn
op(0x22, MOVLS, m, n); //MOV.L Rm,@Rn
op(0x24, MOVBM, m, n); //MOV.B Rm,@-Rn
op(0x25, MOVWM, m, n); //MOV.W Rm,@-Rn
op(0x26, MOVLM, m, n); //MOV.L Rm,@-Rn
op(0x27, DIV0S, m, n); //DIV0S Rm,Rn
op(0x28, TST, m, n); //TST Rm,Rn
op(0x29, AND, m, n); //AND Rm,Rn
op(0x2a, XOR, m, n); //XOR Rm,Rn
op(0x2b, OR, m, n); //OR Rm,Rn
op(0x2c, CMPSTR, m, n); //CMP/STR Rm,Rn
op(0x2d, XTRCT, m, n); //XTRCT Rm,Rn
op(0x2e, MULU, m, n); //MULU Rm,Rn
op(0x2f, MULS, m, n); //MULS Rm,Rn
op(0x30, CMPEQ, m, n); //CMP/EQ Rm,Rn
op(0x32, CMPHS, m, n); //CMP/HS Rm,Rn
op(0x33, CMPGE, m, n); //CMP/GE Rm,Rn
op(0x34, DIV1, m, n); //DIV1 Rm,Rn
op(0x35, DMULU, m, n); //DMULU.L Rm,Rn
op(0x36, CMPHI, m, n); //CMP/HI Rm,Rn
op(0x37, CMPGT, m, n); //CMP/GT Rm,Rn
op(0x38, SUB, m, n); //SUB Rm,Rn
op(0x3a, SUBC, m, n); //SUBC Rm,Rn
op(0x3b, SUBV, m, n); //SUBV Rm,Rn
op(0x3c, ADD, m, n); //ADD Rm,Rn
op(0x3d, DMULS, m, n); //DMULS.L Rm,Rn
op(0x3e, ADDC, m, n); //ADDC Rm,Rn
op(0x3f, ADDV, m, n); //ADDV Rm,Rn
op(0x4f, MACW, m, n); //MAC.W @Rm+,@Rn+
op(0x50 ... 0x5f, MOVLL4, m, d4, n); //MOV.L @(disp,Rm),Rn
op(0x60, MOVBL, m, n); //MOV.B @Rm,Rn
op(0x61, MOVWL, m, n); //MOV.W @Rm,Rn
op(0x62, MOVLL, m, n); //MOV.L @Rm,Rn
op(0x63, MOV, m, n); //MOV Rm,Rn
op(0x64, MOVBP, m, n); //MOV.B @Rm+,Rn
op(0x65, MOVWP, m, n); //MOV.W @Rm+,Rn
op(0x66, MOVLP, m, n); //MOV.L @Rm+,Rn
op(0x67, NOT, m, n); //NOT Rm,Rn
op(0x68, SWAPB, m, n); //SWAP.B Rm,Rn
op(0x69, SWAPW, m, n); //SWAP.W Rm,Rn
op(0x6a, NEGC, m, n); //NEGC Rm,Rn
op(0x6b, NEG, m, n); //NEG Rm,Rn
op(0x6c, EXTUB, m, n); //EXTU.B Rm,Rn
op(0x6d, EXTUW, m, n); //EXTU.W Rm,Rn
op(0x6e, EXTSB, m, n); //EXTS.B Rm,Rn
op(0x6f, EXTSW, m, n); //EXTS.W Rm,Rn
op(0x70 ... 0x7f, ADDI, i, n); //ADD #imm,Rn
op(0x90 ... 0x9f, MOVWI, d8, n); //MOV.W @(disp,PC),Rn
br(0xa0 ... 0xaf, BRA, d12); //BRA disp
br(0xb0 ... 0xbf, BSR, d12); //BSR disp
op(0xd0 ... 0xdf, MOVLI, d8, n); //MOV.L @(disp.PC),Rn
op(0xe0 ... 0xef, MOVI, i, n); //MOV #imm,Rn
op(0x04, MOVBS0, m, n); //MOV.B Rm,@(R0,Rn)
op(0x05, MOVWS0, m, n); //MOV.W Rm,@(R0,Rn)
op(0x06, MOVLS0, m, n); //MOV.L Rm,@(R0,Rn)
op(0x07, MULL, m, n); //MUL.L Rm,Rn
op(0x0c, MOVBL0, m, n); //MOV.B @(R0,Rm),Rn
op(0x0d, MOVWL0, m, n); //MOV.W @(R0,Rm),Rn
op(0x0e, MOVLL0, m, n); //MOV.L @(R0,Rm),Rn
op(0x0f, MACL_, m, n); //MAC.L @Rm+,@Rn+
op(range16(0x10, 0x1f), MOVLS4, m, d4, n); //MOV.L Rm,@(disp,Rn)
op(0x20, MOVBS, m, n); //MOV.B Rm,@Rn
op(0x21, MOVWS, m, n); //MOV.W Rm,@Rn
op(0x22, MOVLS, m, n); //MOV.L Rm,@Rn
op(0x24, MOVBM, m, n); //MOV.B Rm,@-Rn
op(0x25, MOVWM, m, n); //MOV.W Rm,@-Rn
op(0x26, MOVLM, m, n); //MOV.L Rm,@-Rn
op(0x27, DIV0S, m, n); //DIV0S Rm,Rn
op(0x28, TST, m, n); //TST Rm,Rn
op(0x29, AND, m, n); //AND Rm,Rn
op(0x2a, XOR, m, n); //XOR Rm,Rn
op(0x2b, OR, m, n); //OR Rm,Rn
op(0x2c, CMPSTR, m, n); //CMP/STR Rm,Rn
op(0x2d, XTRCT, m, n); //XTRCT Rm,Rn
op(0x2e, MULU, m, n); //MULU Rm,Rn
op(0x2f, MULS, m, n); //MULS Rm,Rn
op(0x30, CMPEQ, m, n); //CMP/EQ Rm,Rn
op(0x32, CMPHS, m, n); //CMP/HS Rm,Rn
op(0x33, CMPGE, m, n); //CMP/GE Rm,Rn
op(0x34, DIV1, m, n); //DIV1 Rm,Rn
op(0x35, DMULU, m, n); //DMULU.L Rm,Rn
op(0x36, CMPHI, m, n); //CMP/HI Rm,Rn
op(0x37, CMPGT, m, n); //CMP/GT Rm,Rn
op(0x38, SUB, m, n); //SUB Rm,Rn
op(0x3a, SUBC, m, n); //SUBC Rm,Rn
op(0x3b, SUBV, m, n); //SUBV Rm,Rn
op(0x3c, ADD, m, n); //ADD Rm,Rn
op(0x3d, DMULS, m, n); //DMULS.L Rm,Rn
op(0x3e, ADDC, m, n); //ADDC Rm,Rn
op(0x3f, ADDV, m, n); //ADDV Rm,Rn
op(0x4f, MACW, m, n); //MAC.W @Rm+,@Rn+
op(range16(0x50, 0x5f), MOVLL4, m, d4, n); //MOV.L @(disp,Rm),Rn
op(0x60, MOVBL, m, n); //MOV.B @Rm,Rn
op(0x61, MOVWL, m, n); //MOV.W @Rm,Rn
op(0x62, MOVLL, m, n); //MOV.L @Rm,Rn
op(0x63, MOV, m, n); //MOV Rm,Rn
op(0x64, MOVBP, m, n); //MOV.B @Rm+,Rn
op(0x65, MOVWP, m, n); //MOV.W @Rm+,Rn
op(0x66, MOVLP, m, n); //MOV.L @Rm+,Rn
op(0x67, NOT, m, n); //NOT Rm,Rn
op(0x68, SWAPB, m, n); //SWAP.B Rm,Rn
op(0x69, SWAPW, m, n); //SWAP.W Rm,Rn
op(0x6a, NEGC, m, n); //NEGC Rm,Rn
op(0x6b, NEG, m, n); //NEG Rm,Rn
op(0x6c, EXTUB, m, n); //EXTU.B Rm,Rn
op(0x6d, EXTUW, m, n); //EXTU.W Rm,Rn
op(0x6e, EXTSB, m, n); //EXTS.B Rm,Rn
op(0x6f, EXTSW, m, n); //EXTS.W Rm,Rn
op(range16(0x70, 0x7f), ADDI, i, n); //ADD #imm,Rn
op(range16(0x90, 0x9f), MOVWI, d8, n); //MOV.W @(disp,PC),Rn
br(range16(0xa0, 0xaf), BRA, d12); //BRA disp
br(range16(0xb0, 0xbf), BSR, d12); //BSR disp
op(range16(0xd0, 0xdf), MOVLI, d8, n); //MOV.L @(disp.PC),Rn
op(range16(0xe0, 0xef), MOVI, i, n); //MOV #imm,Rn
}
#undef n
#undef m
@@ -94,7 +94,7 @@
op(0xc0, MOVBSG, d8); //MOV.B R0,@(disp,GBR)
op(0xc1, MOVWSG, d8); //MOV.W R0,@(disp,GBR)
op(0xc2, MOVLSG, d8); //MOV.L R0,@(disp,GBR)
op(0xc3, TRAPA, i); //TRAPA #imm
br(0xc3, TRAPA, i); //TRAPA #imm
op(0xc4, MOVBLG, d8); //MOV.B @(disp,GBR),R0
op(0xc5, MOVWLG, d8); //MOV.W @(disp,GBR),R0
op(0xc6, MOVLLG, d8); //MOV.L @(disp,GBR),R0
@@ -174,7 +174,7 @@
br(0x000b, RTS); //RTS
op(0x0018, SETT); //SETT
op(0x0019, DIV0U); //DIV0U
op(0x001b, SLEEP); //SLEEP
br(0x001b, SLEEP); //SLEEP
op(0x0028, CLRMAC); //CLRMAC
br(0x002b, RTE); //RTE
}
+10 -10
View File
@@ -1,8 +1,8 @@
template<typename... P>
auto SH2::hint(P&&... p) const -> string {
if(1) return {};
if(1) return {"\e[0m\e[37m", forward<P>(p)..., "\e[0m"};
return {forward<P>(p)...};
if(1) return {terminal::csi, "0m", terminal::csi, "37m", std::forward<P>(p)..., terminal::csi, "0m"};
return {std::forward<P>(p)...};
}
auto SH2::disassembleInstruction() -> string {
@@ -81,7 +81,7 @@ auto SH2::disassembleInstruction() -> string {
case 0x0f: //MAC.L @Rm+,@Rn+
s = {"mac.l", postincrementIndirectRegister(m), postincrementIndirectRegister(n)};
break;
case 0x10 ... 0x1f: //MOV.L Rm,@(disp,Rn)
case range16(0x10, 0x1f): //MOV.L Rm,@(disp,Rn)
s = {"mov.l", registerValue(m), indirectRegisterDisplacement(n, d4, 4)};
break;
case 0x20: //MOV.B Rm,@Rn
@@ -174,7 +174,7 @@ auto SH2::disassembleInstruction() -> string {
case 0x4f: //MAC.W @Rm+,@Rn+
s = {"mac.w", postincrementIndirectRegister(m), postincrementIndirectRegister(n)};
break;
case 0x50 ... 0x5f: //MOV.L @(disp,Rm),Rn
case range16(0x50, 0x5f): //MOV.L @(disp,Rm),Rn
s = {"mov.l", indirectRegisterDisplacement(m, d4, 4), registerName(n)};
break;
case 0x60: //MOV.B @Rm,Rn
@@ -225,22 +225,22 @@ auto SH2::disassembleInstruction() -> string {
case 0x6f: //EXTS.W Rm,Rn
s = {"exts.w", registerValue(m), registerName(n)};
break;
case 0x70 ... 0x7f: //ADD #imm,Rn
case range16(0x70, 0x7f): //ADD #imm,Rn
s = {"add", immediate(i), registerValue(n)};
break;
case 0x90 ... 0x9f: //MOV.W @(disp,PC),Rn
case range16(0x90, 0x9f): //MOV.W @(disp,PC),Rn
s = {"mov.w", pcRelativeDisplacement(d8, 2), registerName(n)};
break;
case 0xa0 ... 0xaf: //BRA disp
case range16(0xa0, 0xaf): //BRA disp
s = {"bra", branch12(d12)};
break;
case 0xb0 ... 0xbf: //BSR disp
case range16(0xb0, 0xbf): //BSR disp
s = {"bsr", branch12(d12)};
break;
case 0xd0 ... 0xdf: //MOV.L @(disp,PC),Rn
case range16(0xd0, 0xdf): //MOV.L @(disp,PC),Rn
s = {"mov.l", pcRelativeDisplacement(d8, 4), registerName(n)};
break;
case 0xe0 ... 0xef: //MOV #imm,Rn
case range16(0xe0, 0xef): //MOV #imm,Rn
s = {"mov", immediate(i), registerName(n)};
break;
}
+8 -14
View File
@@ -1,6 +1,6 @@
auto SH2::exceptionHandler() -> void {
if(!exceptions) return;
if(inDelaySlot()) return;
if(inDelaySlot()) { cyclesUntilSync = 0; return; }
if(exceptions & ResetCold) {
exceptions &= ~ResetCold;
@@ -34,22 +34,16 @@ auto SH2::push(u32 data) -> void {
auto SH2::interrupt(u8 level, u8 vector) -> void {
push(SR);
push(PC);
push(PC - 4);
jump(readLong(VBR + vector * 4) + 4);
SR.I = level;
}
auto SH2::exception(u8 vector) -> void {
push(SR);
push(PC - 2);
jump(readLong(VBR + vector * 4) + 4);
}
auto SH2::addressErrorCPU() -> void {
static constexpr u8 vector = 0x09;
SP &= ~3; //not accurate; but prevents infinite recursion
push(SR);
push(PC);
push(PC - 4);
jump(readLong(VBR + vector * 4) + 4);
}
@@ -57,23 +51,23 @@ auto SH2::addressErrorDMA() -> void {
static constexpr u8 vector = 0x0a;
SP &= ~3; //not accurate; but prevents infinite recursion
push(SR);
push(PC);
push(PC - 4);
jump(readLong(VBR + vector * 4) + 4);
}
auto SH2::illegalInstruction() -> void {
if(inDelaySlot()) return illegalSlotInstruction();
debug(unusual, "[SH2] illegal instruction: 0x", hex(busReadWord(PC - 4), 4L), " @ 0x", hex(PC - 4));
static constexpr u8 vector = 0x04;
push(SR);
push(PC);
push(PC - 4);
jump(readLong(VBR + vector * 4) + 4);
debug(unusual, "[SH2] illegal instruction: 0x", hex(busReadWord(PC - 4), 4L), " @ 0x", hex(PC - 4));
}
auto SH2::illegalSlotInstruction() -> void {
debug(unusual, "[SH2] illegal slot instruction: 0x", hex(busReadWord(PC - 4), 4L));
static constexpr u8 vector = 0x06;
push(SR);
push(PC - 2);
push(PPC - 4);
jump(readLong(VBR + vector * 4) + 4);
debug(unusual, "[SH2] illegal slot instruction: 0x", hex(busReadWord(PC - 4), 4L));
}
+1 -3
View File
@@ -4,13 +4,11 @@ auto SH2::jump(u32 pc) -> void {
}
auto SH2::branch(u32 pc) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
PPC = pc;
PPM = Branch::Take;
}
auto SH2::delaySlot(u32 pc) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
PPC = pc;
PPM = Branch::Slot;
}
@@ -37,7 +35,7 @@ auto SH2::instruction() -> void {
do {
auto block = recompiler.block(PC - 4);
block->execute(*this);
} while (CCR <= recompiler.min_cycles);
} while (CCR < cyclesUntilSync);
step(CCR);
CCR = 0;
+25 -12
View File
@@ -43,6 +43,7 @@ auto SH2::ANDM(u32 i) -> void {
//BF disp
auto SH2::BF(u32 d) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
if(SR.T == 0) {
branch(PC + 4 + (s8)d * 2);
}
@@ -50,6 +51,7 @@ auto SH2::BF(u32 d) -> void {
//BF/S disp
auto SH2::BFS(u32 d) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
if(SR.T == 0) {
delaySlot(PC + 4 + (s8)d * 2);
}
@@ -57,28 +59,33 @@ auto SH2::BFS(u32 d) -> void {
//BRA disp
auto SH2::BRA(u32 d) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
delaySlot(PC + 4 + (i12)d * 2);
}
//BRAF disp
auto SH2::BRAF(u32 m) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
delaySlot(PC + 4 + R[m]);
}
//BSR disp
auto SH2::BSR(u32 d) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
PR = PC;
delaySlot(PC + 4 + (i12)d * 2);
}
//BSRF Rm
auto SH2::BSRF(u32 m) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
PR = PC;
delaySlot(PC + 4 + R[m]);
}
//BT disp
auto SH2::BT(u32 d) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
if(SR.T == 1) {
branch(PC + 4 + (s8)d * 2);
}
@@ -86,6 +93,7 @@ auto SH2::BT(u32 d) -> void {
//BT/S disp
auto SH2::BTS(u32 d) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
if(SR.T == 1) {
delaySlot(PC + 4 + (s8)d * 2);
}
@@ -221,11 +229,13 @@ auto SH2::ILLEGAL() -> void {
//JMP @Rm
auto SH2::JMP(u32 m) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
delaySlot(R[m] + 4);
}
//JSR @Rm
auto SH2::JSR(u32 m) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
PR = PC;
delaySlot(R[m] + 4);
}
@@ -503,18 +513,21 @@ auto SH2::MOVI(u32 i, u32 n) -> void {
}
//MOV.W @(disp,PC),Rn
auto SH2::MOVWI(u32 d, u32 n) -> void {
R[n] = (s16)readWord(PC + d * 2);
noinline auto SH2::MOVWI(u32 d, u32 n) -> void {
u32 pc = inDelaySlot() ? PPC - 2 : PC;
R[n] = (s16)readWord(pc + d * 2);
}
//MOV.L @(disp,PC),Rn
auto SH2::MOVLI(u32 d, u32 n) -> void {
R[n] = readLong((PC & ~3) + d * 4);
noinline auto SH2::MOVLI(u32 d, u32 n) -> void {
u32 pc = inDelaySlot() ? PPC - 2 : PC;
R[n] = readLong((pc & ~3) + d * 4);
}
//MOVA @(disp,PC),R0
auto SH2::MOVA(u32 d) -> void {
R[0] = (PC & ~3) + d * 4 - inDelaySlot() * 2;
noinline auto SH2::MOVA(u32 d) -> void {
u32 pc = inDelaySlot() ? PPC - 2 : PC;
R[0] = (pc & ~3) + d * 4;
}
//MOVT Rn
@@ -602,13 +615,15 @@ auto SH2::ROTR(u32 n) -> void {
//RTE
auto SH2::RTE() -> void {
delaySlot(readLong(SP + 0));
if(inDelaySlot()) return illegalSlotInstruction();
delaySlot(readLong(SP + 0) + 4);
SR = readLong(SP + 4);
SP += 8;
}
//RTS
auto SH2::RTS() -> void {
if(inDelaySlot()) return illegalSlotInstruction();
delaySlot(PR + 4);
}
@@ -800,18 +815,16 @@ auto SH2::TAS(u32 n) -> void {
) return (void)(exceptions |= AddressErrorCPU);
}
auto cacheEnable = cache.enable;
cache.enable = 0;
u8 b = readByte(R[n]);
cache.enable = cacheEnable;
u8 b = readByte<Bus::Internal>(R[n]);
SR.T = b == 0;
writeByte(R[n], b | 0x80);
}
//TRAPA #imm
auto SH2::TRAPA(u32 i) -> void {
if(inDelaySlot()) return illegalSlotInstruction();
push(SR);
push(PC + 2);
push(PC - 2);
branch(readLong(VBR + i * 4) + 4);
}
File diff suppressed because it is too large. Load diff
+5 -1
View File
@@ -1,3 +1,6 @@
#define XXH_INLINE_ALL
#include <xxhash.h>
#include <ares/ares.hpp>
#include "sh2.hpp"
@@ -45,11 +48,12 @@ auto SH2::power(bool reset) -> void {
ET = 0;
ID = 0;
exceptions = !reset ? ResetCold : ResetWarm;
cyclesUntilSync = 0;
cache = {*this};
intc = {*this};
dmac = {*this};
sci = {*this};
sci = {*this, reset ? sci.link : maybe<SH2&>()};
wdt = {};
ubc = {};
frt = {*this};
+32 -4
View File
@@ -29,7 +29,6 @@ struct SH2 {
auto exceptionHandler() -> void;
auto push(u32 data) -> void;
auto interrupt(u8 level, u8 vector) -> void;
auto exception(u8 vector) -> void;
auto addressErrorCPU() -> void;
auto addressErrorDMA() -> void;
auto illegalInstruction() -> void;
@@ -246,6 +245,9 @@ struct SH2 {
};
u32 exceptions = 0; //delayed exception flags
s32 cyclesUntilSync = 0;
s32 minCyclesBetweenSyncs = 0;
struct Recompiler : recompiler::generic {
SH2& self;
Recompiler(SH2& self) : self(self), generic(allocator) {}
@@ -256,27 +258,53 @@ struct SH2 {
}
u8* code;
u8 size;
};
struct Pool {
u32 generation;
u64 dirty;
Block* blocks[1 << 7];
};
struct BlockHashPair {
auto operator==(const BlockHashPair& source) const -> bool { return hashcode == source.hashcode; }
auto hash() const -> u32 { return hashcode; }
Block* block;
u64 hashcode;
};
auto reset() -> void {
generation = 0;
blocks.reset();
for(u32 index : range(1 << 24)) pools[index] = nullptr;
}
auto invalidate(u32 address) -> void;
auto invalidateCached() -> void {
generation++;
}
auto invalidate(u32 address, u8 size) -> void;
auto pool(u32 address) -> Pool*;
auto block(u32 address) -> Block*;
auto measure(u32 address) -> u8;
auto hash(u32 address, u8 size) -> u64;
auto emit(u32 address) -> Block*;
auto emitInstruction(u16 opcode) -> bool;
auto emitInstruction(u16 opcode) -> u32;
auto getSR(reg dst) -> void;
auto setSR(reg src) -> void;
template<typename F> auto checkDelaySlot(F body) -> void;
auto isTerminal(u16 instruction) -> bool;
static auto mask(u8 address, u8 size) -> u64;
bool inDelaySlot;
u32 generation;
bump_allocator allocator;
hashset<BlockHashPair> blocks;
u16 instructions[1 << 7];
Pool* pools[1 << 24];
int min_cycles = 0;
} recompiler{*this};
#include "sh7604/sh7604.hpp"
+74 -27
View File
@@ -1,8 +1,10 @@
auto SH2::readByte(u32 address) -> u32 {
template<u32 Origin> auto SH2::readByte(u32 address) -> u32 {
switch(address >> 29) {
case Area::Cached: {
if(likely(cache.enable)) return cache.read<Byte>(address);
if constexpr(Origin == Bus::Cache) {
if(likely(cache.enable)) return cache.read<Byte>(address);
}
return busReadByte(address & 0x1fff'ffff);
}
@@ -11,7 +13,10 @@ auto SH2::readByte(u32 address) -> u32 {
}
case Area::Data: {
return cache.readData<Byte>(address);
if constexpr(Origin == Bus::Cache) {
return cache.readData<Byte>(address);
}
break;
}
case Area::IO: {
@@ -28,7 +33,7 @@ auto SH2::readByte(u32 address) -> u32 {
return 0;
}
auto SH2::readWord(u32 address) -> u32 {
template<u32 Origin> auto SH2::readWord(u32 address) -> u32 {
if constexpr(Accuracy::AddressErrors) {
if(unlikely(address & 1)) return exceptions |= AddressErrorCPU, 0;
}
@@ -36,7 +41,9 @@ auto SH2::readWord(u32 address) -> u32 {
switch(address >> 29) {
case Area::Cached: {
if(likely(cache.enable)) return cache.read<Word>(address);
if constexpr(Origin == Bus::Cache) {
if(likely(cache.enable)) return cache.read<Word>(address);
}
return busReadWord(address & 0x1fff'fffe);
}
@@ -45,7 +52,10 @@ auto SH2::readWord(u32 address) -> u32 {
}
case Area::Data: {
return cache.readData<Word>(address);
if constexpr(Origin == Bus::Cache) {
return cache.readData<Word>(address);
}
break;
}
case Area::IO: {
@@ -60,7 +70,7 @@ auto SH2::readWord(u32 address) -> u32 {
return 0;
}
auto SH2::readLong(u32 address) -> u32 {
template<u32 Origin> auto SH2::readLong(u32 address) -> u32 {
if constexpr(Accuracy::AddressErrors) {
if(unlikely(address & 3)) return exceptions |= AddressErrorCPU, 0;
}
@@ -68,7 +78,9 @@ auto SH2::readLong(u32 address) -> u32 {
switch(address >> 29) {
case Area::Cached: {
if(likely(cache.enable)) return cache.read<Long>(address);
if constexpr(Origin == Bus::Cache) {
if(likely(cache.enable)) return cache.read<Long>(address);
}
return busReadLong(address & 0x1fff'fffc);
}
@@ -77,11 +89,17 @@ auto SH2::readLong(u32 address) -> u32 {
}
case Area::Address: {
return cache.readAddress(address);
if constexpr(Origin == Bus::Cache) {
return cache.readAddress(address);
}
break;
}
case Area::Data: {
return cache.readData<Long>(address);
if constexpr(Origin == Bus::Cache) {
return cache.readData<Long>(address);
}
break;
}
case Area::IO: {
@@ -104,28 +122,37 @@ auto SH2::readLong(u32 address) -> u32 {
return 0;
}
auto SH2::writeByte(u32 address, u32 data) -> void {
template<u32 Origin> auto SH2::writeByte(u32 address, u32 data) -> void {
if constexpr(Accuracy::Recompiler) {
recompiler.invalidate(address);
recompiler.invalidate(address, 1);
}
switch(address >> 29) {
case Area::Cached: {
if(likely(cache.enable)) cache.write<Byte>(address, data);
if constexpr(Origin == Bus::Cache) {
if(likely(cache.enable)) cache.write<Byte>(address, data);
}
return busWriteByte(address & 0x1fff'ffff, data);
}
case Area::Uncached: {
cyclesUntilSync = 0;
return busWriteByte(address & 0x1fff'ffff, data);
}
case Area::Purge: {
return cache.purge(address);
if constexpr(Origin == Bus::Cache) {
return cache.purge(address);
}
break;
}
case Area::Data: {
return cache.writeData<Byte>(address, data);
if constexpr(Origin == Bus::Cache) {
return cache.writeData<Byte>(address, data);
}
break;
}
case Area::IO: {
@@ -140,32 +167,41 @@ auto SH2::writeByte(u32 address, u32 data) -> void {
}
}
auto SH2::writeWord(u32 address, u32 data) -> void {
template<u32 Origin> auto SH2::writeWord(u32 address, u32 data) -> void {
if constexpr(Accuracy::AddressErrors) {
if(unlikely(address & 1)) return (void)(exceptions |= AddressErrorCPU);
}
if constexpr(Accuracy::Recompiler) {
recompiler.invalidate(address);
recompiler.invalidate(address, 2);
}
switch(address >> 29) {
case Area::Cached: {
if(likely(cache.enable)) cache.write<Word>(address, data);
if constexpr(Origin == Bus::Cache) {
if(likely(cache.enable)) cache.write<Word>(address, data);
}
return busWriteWord(address & 0x1fff'fffe, data);
}
case Area::Uncached: {
cyclesUntilSync = 0;
return busWriteWord(address & 0x1fff'fffe, data);
}
case Area::Purge: {
return cache.purge(address);
if constexpr(Origin == Bus::Cache) {
return cache.purge(address);
}
break;
}
case Area::Data: {
return cache.writeData<Word>(address, data);
if constexpr(Origin == Bus::Cache) {
return cache.writeData<Word>(address, data);
}
break;
}
case Area::IO: {
@@ -177,37 +213,48 @@ auto SH2::writeWord(u32 address, u32 data) -> void {
}
}
auto SH2::writeLong(u32 address, u32 data) -> void {
template<u32 Origin> auto SH2::writeLong(u32 address, u32 data) -> void {
if constexpr(Accuracy::AddressErrors) {
if(unlikely(address & 3)) return (void)(exceptions |= AddressErrorCPU);
}
if constexpr(Accuracy::Recompiler) {
recompiler.invalidate(address + 0);
recompiler.invalidate(address + 2);
recompiler.invalidate(address, 4);
}
switch(address >> 29) {
case Area::Cached: {
if(likely(cache.enable)) cache.write<Long>(address, data);
if constexpr(Origin == Bus::Cache) {
if(likely(cache.enable)) cache.write<Long>(address, data);
}
return busWriteLong(address & 0x1fff'fffc, data);
}
case Area::Uncached: {
cyclesUntilSync = 0;
return busWriteLong(address & 0x1fff'fffc, data);
}
case Area::Purge: {
return cache.purge(address);
if constexpr(Origin == Bus::Cache) {
return cache.purge(address);
}
break;
}
case Area::Address: {
return cache.writeAddress(address, data);
if constexpr(Origin == Bus::Cache) {
return cache.writeAddress(address, data);
}
break;
}
case Area::Data: {
return cache.writeData<Long>(address, data);
if constexpr(Origin == Bus::Cache) {
return cache.writeData<Long>(address, data);
}
break;
}
case Area::IO: {
@@ -88,12 +88,20 @@ auto SH2::Cache::purge(u32 address) -> void {
if(tags[Way1 | entry] == tag) tags[Way1 | entry] |= Invalid;
if(tags[Way2 | entry] == tag) tags[Way2 | entry] |= Invalid;
if(tags[Way3 | entry] == tag) tags[Way3 | entry] |= Invalid;
if constexpr(Accuracy::Recompiler) {
self->recompiler.invalidate(address & 0x1fff'fff0, 0x10);
}
}
template<u32 Ways>
auto SH2::Cache::purge() -> void {
for(auto index : range(64)) lrus[index] = 0;
for(auto index : range(64 * Ways)) tags[index] |= Invalid;
if constexpr(Accuracy::Recompiler) {
self->recompiler.invalidateCached();
}
}
auto SH2::Cache::power() -> void {
+12 -8
View File
@@ -4,12 +4,16 @@ auto SH2::DMAC::run() -> void {
if(chcr[c].ar) {
transfer(c);
} else if(drcr[c] == 0) {
if(dreq) transfer(c);
if(dreq[c]) transfer(c);
// Note: DACK is not implemented (not used by 32X)
} else if(drcr[c] == 1) {
debug(unimplemented, "[SH2] DMA RXI");
} else if(drcr[c] == 2) {
debug(unimplemented, "[SH2] DMA TXI");
} else {
continue;
}
break; // ignoring cycle-steal mode for now
}
}
}
@@ -18,7 +22,7 @@ auto SH2::DMAC::transfer(bool c) -> void {
switch(chcr[c].ts) {
case 0: //8-bit
self->writeByte(dar[c], self->readByte(sar[c]));
self->writeByte<Bus::Internal>(dar[c], self->readByte<Bus::Internal>(sar[c]));
break;
case 1: //16-bit
if constexpr(Accuracy::AddressErrors) {
@@ -27,7 +31,7 @@ auto SH2::DMAC::transfer(bool c) -> void {
break;
}
}
self->writeWord(dar[c], self->readWord(sar[c]));
self->writeWord<Bus::Internal>(dar[c], self->readWord<Bus::Internal>(sar[c]));
break;
case 2: //32-bit
if constexpr(Accuracy::AddressErrors) {
@@ -36,7 +40,7 @@ auto SH2::DMAC::transfer(bool c) -> void {
break;
}
}
self->writeLong(dar[c], self->readLong(sar[c]));
self->writeLong<Bus::Internal>(dar[c], self->readLong<Bus::Internal>(sar[c]));
break;
case 3: //32-bit x4
if constexpr(Accuracy::AddressErrors) {
@@ -45,10 +49,10 @@ auto SH2::DMAC::transfer(bool c) -> void {
break;
}
}
self->writeLong(dar[c] + 0, self->readLong(sar[c] + 0));
self->writeLong(dar[c] + 4, self->readLong(sar[c] + 4));
self->writeLong(dar[c] + 8, self->readLong(sar[c] + 8));
self->writeLong(dar[c] + 12, self->readLong(sar[c] + 12));
self->writeLong<Bus::Internal>(dar[c] + 0, self->readLong<Bus::Internal>(sar[c] + 0));
self->writeLong<Bus::Internal>(dar[c] + 4, self->readLong<Bus::Internal>(sar[c] + 4));
self->writeLong<Bus::Internal>(dar[c] + 8, self->readLong<Bus::Internal>(sar[c] + 8));
self->writeLong<Bus::Internal>(dar[c] + 12, self->readLong<Bus::Internal>(sar[c] + 12));
sar[c] += 16; //always increments regardless of chcr[c].sm
tcr[c] -= 3; //always decrements by four instead of by one
break;
@@ -1,5 +1,5 @@
auto SH2::INTC::run() -> void {
if(self->inDelaySlot()) return;
if(self->inDelaySlot()) { self->cyclesUntilSync = 0; return; }
if(self->frt.pendingOutputIRQ) {
if(self->SR.I < iprb.frtip) {
+7 -3
View File
@@ -177,6 +177,7 @@ auto SH2::internalReadByte(u32 address, n8 data) -> n8 {
//CCR: cache control register
case 0xffff'fe92:
case 0xffff'fe93:
data.bit(0) = cache.enable;
data.bit(1) = cache.disableCode;
data.bit(2) = cache.disableData;
@@ -553,7 +554,7 @@ auto SH2::internalWriteByte(u32 address, n8 data) -> void {
sci.scr.te = data.bit(5);
sci.scr.rie = data.bit(6);
sci.scr.tie = data.bit(7);
if(!te && sci.scr.te) sci.run();
if(te && !sci.scr.te) sci.ssr.tdre = 1;
return;
}
@@ -563,7 +564,8 @@ auto SH2::internalWriteByte(u32 address, n8 data) -> void {
return;
//SSR: serial status register
case 0xffff'fe04:
case 0xffff'fe04: {
bool tdre = sci.ssr.tdre;
sci.ssr.mpbt = data.bit(0);
//sci.ssr.mpb = data.bit(1) = readonly;
//sci.ssr.tend = data.bit(2) = readonly;
@@ -572,8 +574,9 @@ auto SH2::internalWriteByte(u32 address, n8 data) -> void {
sci.ssr.orer &= data.bit(5);
sci.ssr.rdrf &= data.bit(6);
sci.ssr.tdre &= data.bit(7);
if(sci.scr.te) sci.run();
if(tdre && !sci.ssr.tdre) sci.run();
return;
}
//RDR: receive data register
case 0xffff'fe05:
@@ -717,6 +720,7 @@ auto SH2::internalWriteByte(u32 address, n8 data) -> void {
//CCR: cache control register
case 0xffff'fe92:
case 0xffff'fe93:
cache.enable = data.bit(0);
cache.disableCode = data.bit(1);
cache.disableData = data.bit(2);
+13 -8
View File
@@ -5,6 +5,10 @@
//struct SH2 {
enum : u32 { Byte, Word, Long };
struct Bus {
enum : u32 { Cache, Internal, Peripheral };
};
struct Area { enum : u32 {
Cached = 0,
Uncached = 1,
@@ -15,12 +19,12 @@
};};
//bus.cpp
auto readByte(u32 address) -> u32;
auto readWord(u32 address) -> u32;
auto readLong(u32 address) -> u32;
auto writeByte(u32 address, u32 data) -> void;
auto writeWord(u32 address, u32 data) -> void;
auto writeLong(u32 address, u32 data) -> void;
template<u32 Origin = Bus::Cache> auto readByte(u32 address) -> u32;
template<u32 Origin = Bus::Cache> auto readWord(u32 address) -> u32;
template<u32 Origin = Bus::Cache> auto readLong(u32 address) -> u32;
template<u32 Origin = Bus::Cache> auto writeByte(u32 address, u32 data) -> void;
template<u32 Origin = Bus::Cache> auto writeWord(u32 address, u32 data) -> void;
template<u32 Origin = Bus::Cache> auto writeLong(u32 address, u32 data) -> void;
//io.cpp
auto internalReadByte(u32 address, n8 data = 0) -> n8;
@@ -155,8 +159,9 @@
n1 pr; //priority mode bit
} dmaor;
n1 dreq[2];
//internal:
n1 dreq;
n2 pendingIRQ;
} dmac;
@@ -197,7 +202,7 @@
n1 fer; //framing error
n1 orer; //overrun error
n1 rdrf; //receive data register full
n1 tdre; //transmit data register empty
n1 tdre = 1; //transmit data register empty
} ssr;
n8 brr = 0xff; //bit rate register
n8 tdr = 0xff; //transmit data register
@@ -27,7 +27,7 @@ auto SH2::FRT::run() -> void {
}
}
auto SH2::WDT::run() -> void {
static constexpr u32 frequencies[8] = {2, 64, 128, 256, 512, 1024, 2096, 8192};
static constexpr u32 frequencies[8] = {2, 64, 128, 256, 512, 1024, 4096, 8192};
if(!wtcsr.tme) return;
if(wtcsr.wtit) return; // Watchdog mode currently unsupported
+48 -48
View File
@@ -12,54 +12,54 @@ auto SM5K::disassembleInstruction() -> string {
string pc = {"0x", hex(n4(opcode) << 8 | operand, 3L)};
switch(opcode) {
case 0x00 ... 0x0f: s = {"adx ", p4}; break;
case 0x10 ... 0x1f: s = {"lax ", p4}; break;
case 0x20 ... 0x2f: s = {"lblx ", p4}; break;
case 0x30 ... 0x3f: s = {"lbmx ", p4}; break;
case 0x40 ... 0x43: s = {"rm ", p2}; break;
case 0x44 ... 0x47: s = {"sm ", p2}; break;
case 0x48 ... 0x4b: s = {"tm ", p2}; break;
case 0x4c ... 0x4f: s = {"tpb ", p2}; break;
case 0x50 ... 0x53: s = {"lda ", p2}; break;
case 0x54 ... 0x57: s = {"exc ", p2}; break;
case 0x58 ... 0x5b: s = {"exci ", p2}; break;
case 0x5c ... 0x5f: s = {"excd ", p2}; break;
case 0x60: s = {"rc " }; break;
case 0x61: s = {"sc " }; break;
case 0x62: s = {"id " }; break;
case 0x63: s = {"ie " }; break;
case 0x64: s = {"exax " }; break;
case 0x65: s = {"atx " }; break;
case 0x66: s = {"exbm " }; break;
case 0x67: s = {"exbl " }; break;
case 0x68: s = {"ex " }; break;
case 0x69: s = {"dta ", p8}; break;
case 0x6a: s = {"pat ", p8}; break;
case 0x6b: s = {"tabl " }; break;
case 0x6c: s = {"ta " }; break;
case 0x6d: s = {"tb " }; break;
case 0x6e: s = {"tc " }; break;
case 0x6f: s = {"tam " }; break;
case 0x70: s = {"inl " }; break;
case 0x71: s = {"outl " }; break;
case 0x72: s = {"anp " }; break;
case 0x73: s = {"orp " }; break;
case 0x74: s = {"in " }; break;
case 0x75: s = {"out " }; break;
case 0x76: s = {"stop " }; break;
case 0x77: s = {"halt " }; break;
case 0x78: s = {"incb " }; break;
case 0x79: s = {"coma " }; break;
case 0x7a: s = {"add " }; break;
case 0x7b: s = {"adc " }; break;
case 0x7c: s = {"decb " }; break;
case 0x7d: s = {"rtn " }; break;
case 0x7e: s = {"rtns " }; break;
case 0x7f: s = {"rtni " }; break;
case 0x80 ... 0xbf: s = {"tr ", p6}; break;
case 0xc0 ... 0xdf: s = {"trs ", p5}; break;
case 0xe0 ... 0xef: s = {"tl ", pc}; break;
case 0xf0 ... 0xff: s = {"call ", pc}; break;
case range16(0x00, 0x0f): s = {"adx ", p4}; break;
case range16(0x10, 0x1f): s = {"lax ", p4}; break;
case range16(0x20, 0x2f): s = {"lblx ", p4}; break;
case range16(0x30, 0x3f): s = {"lbmx ", p4}; break;
case range4 (0x40, 0x43): s = {"rm ", p2}; break;
case range4 (0x44, 0x47): s = {"sm ", p2}; break;
case range4 (0x48, 0x4b): s = {"tm ", p2}; break;
case range4 (0x4c, 0x4f): s = {"tpb ", p2}; break;
case range4 (0x50, 0x53): s = {"lda ", p2}; break;
case range4 (0x54, 0x57): s = {"exc ", p2}; break;
case range4 (0x58, 0x5b): s = {"exci ", p2}; break;
case range4 (0x5c, 0x5f): s = {"excd ", p2}; break;
case 0x60: s = {"rc " }; break;
case 0x61: s = {"sc " }; break;
case 0x62: s = {"id " }; break;
case 0x63: s = {"ie " }; break;
case 0x64: s = {"exax " }; break;
case 0x65: s = {"atx " }; break;
case 0x66: s = {"exbm " }; break;
case 0x67: s = {"exbl " }; break;
case 0x68: s = {"ex " }; break;
case 0x69: s = {"dta ", p8}; break;
case 0x6a: s = {"pat ", p8}; break;
case 0x6b: s = {"tabl " }; break;
case 0x6c: s = {"ta " }; break;
case 0x6d: s = {"tb " }; break;
case 0x6e: s = {"tc " }; break;
case 0x6f: s = {"tam " }; break;
case 0x70: s = {"inl " }; break;
case 0x71: s = {"outl " }; break;
case 0x72: s = {"anp " }; break;
case 0x73: s = {"orp " }; break;
case 0x74: s = {"in " }; break;
case 0x75: s = {"out " }; break;
case 0x76: s = {"stop " }; break;
case 0x77: s = {"halt " }; break;
case 0x78: s = {"incb " }; break;
case 0x79: s = {"coma " }; break;
case 0x7a: s = {"add " }; break;
case 0x7b: s = {"adc " }; break;
case 0x7c: s = {"decb " }; break;
case 0x7d: s = {"rtn " }; break;
case 0x7e: s = {"rtns " }; break;
case 0x7f: s = {"rtni " }; break;
case range64(0x80, 0xbf): s = {"tr ", p6}; break;
case range32(0xc0, 0xdf): s = {"trs ", p5}; break;
case range16(0xe0, 0xef): s = {"tl ", pc}; break;
case range16(0xf0, 0xff): s = {"call ", pc}; break;
}
while(s.size() < 10) s.append(" ");
+48 -48
View File
@@ -20,54 +20,54 @@ auto SM5K::instruction() -> void {
n8 opcode = fetch();
switch(opcode) {
op(0x00 ... 0x0f, ADX, n4(opcode));
op(0x10 ... 0x1f, LAX, n4(opcode));
op(0x20 ... 0x2f, LBLX, n4(opcode));
op(0x30 ... 0x3f, LBMX, n4(opcode));
op(0x40 ... 0x43, RM, n2(opcode));
op(0x44 ... 0x47, SM, n2(opcode));
op(0x48 ... 0x4b, TM, n2(opcode));
op(0x4c ... 0x4f, TPB, n2(opcode));
op(0x50 ... 0x53, LDA, n2(opcode));
op(0x54 ... 0x57, EXC, n2(opcode));
op(0x58 ... 0x5b, EXCI, n2(opcode));
op(0x5c ... 0x5f, EXCD, n2(opcode));
op(0x60, RC );
op(0x61, SC );
op(0x62, ID );
op(0x63, IE );
op(0x64, EXAX );
op(0x65, ATX );
op(0x66, EXBM );
op(0x67, EXBL );
op(0x68, EX );
op(0x69, DTA, fetch());
op(0x6a, PAT, fetch());
op(0x6b, TABL );
op(0x6c, TA );
op(0x6d, TB );
op(0x6e, TC );
op(0x6f, TAM );
op(0x70, INL );
op(0x71, OUTL );
op(0x72, ANP );
op(0x73, ORP );
op(0x74, IN );
op(0x75, OUT );
op(0x76, STOP );
op(0x77, HALT );
op(0x78, INCB );
op(0x79, COMA );
op(0x7a, ADD );
op(0x7b, ADC );
op(0x7c, DECB );
op(0x7d, RTN );
op(0x7e, RTNS );
op(0x7f, RTNI );
op(0x80 ... 0xbf, TR, n6(opcode));
op(0xc0 ... 0xdf, TRS, n5(opcode));
op(0xe0 ... 0xef, TL, n4(opcode) << 8 | fetch());
op(0xf0 ... 0xff, CALL, n4(opcode) << 8 | fetch());
op(range16(0x00, 0x0f), ADX, n4(opcode));
op(range16(0x10, 0x1f), LAX, n4(opcode));
op(range16(0x20, 0x2f), LBLX, n4(opcode));
op(range16(0x30, 0x3f), LBMX, n4(opcode));
op(range4 (0x40, 0x43), RM, n2(opcode));
op(range4 (0x44, 0x47), SM, n2(opcode));
op(range4 (0x48, 0x4b), TM, n2(opcode));
op(range4 (0x4c, 0x4f), TPB, n2(opcode));
op(range4 (0x50, 0x53), LDA, n2(opcode));
op(range4 (0x54, 0x57), EXC, n2(opcode));
op(range4 (0x58, 0x5b), EXCI, n2(opcode));
op(range4 (0x5c, 0x5f), EXCD, n2(opcode));
op(0x60, RC );
op(0x61, SC );
op(0x62, ID );
op(0x63, IE );
op(0x64, EXAX );
op(0x65, ATX );
op(0x66, EXBM );
op(0x67, EXBL );
op(0x68, EX );
op(0x69, DTA, fetch());
op(0x6a, PAT, fetch());
op(0x6b, TABL );
op(0x6c, TA );
op(0x6d, TB );
op(0x6e, TC );
op(0x6f, TAM );
op(0x70, INL );
op(0x71, OUTL );
op(0x72, ANP );
op(0x73, ORP );
op(0x74, IN );
op(0x75, OUT );
op(0x76, STOP );
op(0x77, HALT );
op(0x78, INCB );
op(0x79, COMA );
op(0x7a, ADD );
op(0x7b, ADC );
op(0x7c, DECB );
op(0x7d, RTN );
op(0x7e, RTNS );
op(0x7f, RTNI );
op(range64(0x80, 0xbf), TR, n6(opcode));
op(range32(0xc0, 0xdf), TRS, n5(opcode));
op(range16(0xe0, 0xef), TL, n4(opcode) << 8 | fetch());
op(range16(0xf0, 0xff), CALL, n4(opcode) << 8 | fetch());
}
}
@@ -45,13 +45,13 @@ auto SSP1601::cmp(u32 source) -> void {
N = result >> 31;
}
auto SSP1601::and(u32 v) -> void {
auto SSP1601::and_(u32 v) -> void {
A &= v;
Z = A == 0;
N = A >> 31;
}
auto SSP1601::or(u32 v) -> void {
auto SSP1601::or_(u32 v) -> void {
A |= v;
Z = A == 0;
N = A >> 31;
@@ -210,7 +210,7 @@ auto SSP1601::disassembleInstruction(u16 pc, u16 op, u16 imm) -> string {
}
//ldi ri,simm
case 0x0c ... 0x0f: {
case range4(0x0c, 0x0f): {
o = "ldi";
p = {"r", (op >> 8 & 7), ",0x", hex(op & 0xff, 2L)};
break;
@@ -95,7 +95,7 @@ auto SSP1601::instruction() -> void {
}
//ldi ri,simm
case 0x0c ... 0x0f: {
case range4(0x0c, 0x0f): {
R[n3(op >> 8)] = n8(op);
break;
}
@@ -173,56 +173,56 @@ auto SSP1601::instruction() -> void {
case 0x10: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); sub(v); break; }
case 0x30: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); cmp(v); break; }
case 0x40: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); add(v); break; }
case 0x50: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); and(v); break; }
case 0x60: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); or (v); break; }
case 0x50: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); and_(v); break; }
case 0x60: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); or_(v); break; }
case 0x70: { auto v = n4(op) == 3 ? A : n4(op) == 7 ? updateP() : n32(readGR(n4(op)) << 16); eor(v); break; }
//alu a,(ri)
case 0x11: { auto v = readPR1(op) << 16; sub(v); break; }
case 0x31: { auto v = readPR1(op) << 16; cmp(v); break; }
case 0x41: { auto v = readPR1(op) << 16; add(v); break; }
case 0x51: { auto v = readPR1(op) << 16; and(v); break; }
case 0x61: { auto v = readPR1(op) << 16; or (v); break; }
case 0x51: { auto v = readPR1(op) << 16; and_(v); break; }
case 0x61: { auto v = readPR1(op) << 16; or_(v); break; }
case 0x71: { auto v = readPR1(op) << 16; eor(v); break; }
//alu a,addr
case 0x13: { auto v = RAM[n9(op)] << 16; sub(v); break; }
case 0x33: { auto v = RAM[n9(op)] << 16; cmp(v); break; }
case 0x43: { auto v = RAM[n9(op)] << 16; add(v); break; }
case 0x53: { auto v = RAM[n9(op)] << 16; and(v); break; }
case 0x63: { auto v = RAM[n9(op)] << 16; or (v); break; }
case 0x53: { auto v = RAM[n9(op)] << 16; and_(v); break; }
case 0x63: { auto v = RAM[n9(op)] << 16; or_(v); break; }
case 0x73: { auto v = RAM[n9(op)] << 16; eor(v); break; }
//alu a,imm
case 0x14: { auto v = fetch() << 16; sub(v); break; }
case 0x34: { auto v = fetch() << 16; cmp(v); break; }
case 0x44: { auto v = fetch() << 16; add(v); break; }
case 0x54: { auto v = fetch() << 16; and(v); break; }
case 0x64: { auto v = fetch() << 16; or (v); break; }
case 0x54: { auto v = fetch() << 16; and_(v); break; }
case 0x64: { auto v = fetch() << 16; or_(v); break; }
case 0x74: { auto v = fetch() << 16; eor(v); break; }
//alu a,((ri))
case 0x15: { auto v = readPR2(op) << 16; sub(v); break; }
case 0x35: { auto v = readPR2(op) << 16; cmp(v); break; }
case 0x45: { auto v = readPR2(op) << 16; add(v); break; }
case 0x55: { auto v = readPR2(op) << 16; and(v); break; }
case 0x65: { auto v = readPR2(op) << 16; or (v); break; }
case 0x55: { auto v = readPR2(op) << 16; and_(v); break; }
case 0x65: { auto v = readPR2(op) << 16; or_(v); break; }
case 0x75: { auto v = readPR2(op) << 16; eor(v); break; }
//alu a,ri
case 0x19: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; sub(v); break; }
case 0x39: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; cmp(v); break; }
case 0x49: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; add(v); break; }
case 0x59: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; and(v); break; }
case 0x69: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; or (v); break; }
case 0x59: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; and_(v); break; }
case 0x69: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; or_(v); break; }
case 0x79: { auto v = R[n2(op) | (op >> 6 & 4)] << 16; eor(v); break; }
//alu simm
case 0x1c: { auto v = u8(op) << 16; sub(v); break; }
case 0x3c: { auto v = u8(op) << 16; cmp(v); break; }
case 0x4c: { auto v = u8(op) << 16; add(v); break; }
case 0x5c: { auto v = u8(op) << 16; and(v); break; }
case 0x6c: { auto v = u8(op) << 16; or (v); break; }
case 0x5c: { auto v = u8(op) << 16; and_(v); break; }
case 0x6c: { auto v = u8(op) << 16; or_(v); break; }
case 0x7c: { auto v = u8(op) << 16; eor(v); break; }
}
+2 -2
View File
@@ -18,8 +18,8 @@ struct SSP1601 {
auto add(u32) -> void;
auto sub(u32) -> void;
auto cmp(u32) -> void;
auto and(u32) -> void;
auto or (u32) -> void;
auto and_(u32) -> void;
auto or_(u32) -> void;
auto eor(u32) -> void;
auto shr() -> void;
auto shl() -> void;
+103 -103
View File
@@ -144,23 +144,23 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
case 0x1d: name = "call"; lhs.immediate(24, read24()); break;
case 0x1e: name = "calr"; lhs.displacementPC(16, read16()); break;
case 0x1f: break;
case 0x20 ... 0x27: name = "ld"; lhs.register3(8, fetch); rhs.immediate(8, read8()); break;
case 0x28 ... 0x2f: name = "push"; lhs.register3(16, fetch); break;
case 0x30 ... 0x37: name = "ld"; lhs.register3(16, fetch); rhs.immediate(16, read16()); break;
case 0x38 ... 0x3f: name = "push"; lhs.register3(32, fetch); break;
case 0x40 ... 0x47: name = "ld"; lhs.register3(32, fetch); rhs.immediate(32, read32()); break;
case 0x48 ... 0x4f: name = "pop"; lhs.register3(16, fetch); break;
case 0x50 ... 0x5f: name = "pop"; lhs.register3(32, fetch); break;
case 0x60 ... 0x6f: name = "jr"; lhs.condition(fetch); rhs.displacementPC(8, read8()); break;
case 0x70 ... 0x7f: name = "jrl"; lhs.condition(fetch); rhs.displacementPC(16, read16()); break;
case 0x80 ... 0x87: opSourceMemory = true; lhs.indirectRegister3(8, fetch); break;
case 0x88 ... 0x8f: opSourceMemory = true; lhs.indirectRegister3Displacement8(8, fetch, read8()); break;
case 0x90 ... 0x97: opSourceMemory = true; lhs.indirectRegister3(16, fetch); break;
case 0x98 ... 0x9f: opSourceMemory = true; lhs.indirectRegister3Displacement8(16, fetch, read8()); break;
case 0xa0 ... 0xa7: opSourceMemory = true; lhs.indirectRegister3(32, fetch); break;
case 0xa8 ... 0xaf: opSourceMemory = true; lhs.indirectRegister3Displacement8(32, fetch, read8()); break;
case 0xb0 ... 0xb7: opTargetMemory = true; lhs.indirectRegister3(0, fetch); break;
case 0xb8 ... 0xbf: opTargetMemory = true; lhs.indirectRegister3Displacement8(0, fetch, read8()); break;
case range8(0x20, 0x27): name = "ld"; lhs.register3(8, fetch); rhs.immediate(8, read8()); break;
case range8(0x28, 0x2f): name = "push"; lhs.register3(16, fetch); break;
case range8(0x30, 0x37): name = "ld"; lhs.register3(16, fetch); rhs.immediate(16, read16()); break;
case range8(0x38, 0x3f): name = "push"; lhs.register3(32, fetch); break;
case range8(0x40, 0x47): name = "ld"; lhs.register3(32, fetch); rhs.immediate(32, read32()); break;
case range8(0x48, 0x4f): name = "pop"; lhs.register3(16, fetch); break;
case range16(0x50, 0x5f): name = "pop"; lhs.register3(32, fetch); break;
case range16(0x60, 0x6f): name = "jr"; lhs.condition(fetch); rhs.displacementPC(8, read8()); break;
case range16(0x70, 0x7f): name = "jrl"; lhs.condition(fetch); rhs.displacementPC(16, read16()); break;
case range8(0x80, 0x87): opSourceMemory = true; lhs.indirectRegister3(8, fetch); break;
case range8(0x88, 0x8f): opSourceMemory = true; lhs.indirectRegister3Displacement8(8, fetch, read8()); break;
case range8(0x90, 0x97): opSourceMemory = true; lhs.indirectRegister3(16, fetch); break;
case range8(0x98, 0x9f): opSourceMemory = true; lhs.indirectRegister3Displacement8(16, fetch, read8()); break;
case range8(0xa0, 0xa7): opSourceMemory = true; lhs.indirectRegister3(32, fetch); break;
case range8(0xa8, 0xaf): opSourceMemory = true; lhs.indirectRegister3Displacement8(32, fetch, read8()); break;
case range8(0xb0, 0xb7): opTargetMemory = true; lhs.indirectRegister3(0, fetch); break;
case range8(0xb8, 0xbf): opTargetMemory = true; lhs.indirectRegister3Displacement8(0, fetch, read8()); break;
case 0xc0: case 0xd0: case 0xe0: case 0xf0:
opSourceMemory = fetch < 0xf0; opTargetMemory = !opSourceMemory;
lhs.indirectImmediate8(opSize, read8()); break;
@@ -203,10 +203,10 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
read8(); lhs.indirectImmediate8(8, read8());
read8(); rhs.immediate(8, read8());
read8(); break;
case 0xc8 ... 0xcf: opRegister = true; lhs.register3(8, fetch); break;
case 0xd8 ... 0xdf: opRegister = true; lhs.register3(16, fetch); break;
case 0xe8 ... 0xef: opRegister = true; lhs.register3(32, fetch); break;
case 0xf8 ... 0xff: name = "swi"; lhs.immediate(3, (n3)fetch); break;
case range8(0xc8, 0xcf): opRegister = true; lhs.register3(8, fetch); break;
case range8(0xd8, 0xdf): opRegister = true; lhs.register3(16, fetch); break;
case range8(0xe8, 0xef): opRegister = true; lhs.register3(32, fetch); break;
case range8(0xf8, 0xff): name = "swi"; lhs.immediate(3, (n3)fetch); break;
}
#undef opSize
@@ -221,7 +221,7 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
//size defined
if(opRegister)
switch(auto fetch = read8()) {
case 0x00 ... 0x02: break;
case range3(0x00, 0x02): break;
case 0x03: name = "ld"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x04: name = "push"; break;
case 0x05: name = "pop"; break;
@@ -242,17 +242,17 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
case 0x14: name = "paa"; break;
case 0x15: break;
case 0x16: name = "mirr"; break;
case 0x17 ... 0x18: break;
case range2(0x17, 0x18): break;
case 0x19: name = "mula"; break;
case 0x1a ... 0x1b: break;
case range2(0x1a, 0x1b): break;
case 0x1c: name = "djnz"; rhs.displacementPC(8, read8()); break;
case 0x1d ... 0x1f: break;
case range3(0x1d, 0x1f): break;
case 0x20: name = "andcf"; rhs.immediate(4, (n4)read8()); break;
case 0x21: name = "orcf"; rhs.immediate(4, (n4)read8()); break;
case 0x22: name = "xorcf"; rhs.immediate(4, (n4)read8()); break;
case 0x23: name = "ldcf"; rhs.immediate(4, (n4)read8()); break;
case 0x24: name = "stcf"; rhs.immediate(4, (n4)read8()); break;
case 0x25 ... 0x27: break;
case range3(0x25, 0x27): break;
case 0x28: name = "andcf"; rhs.register(8, A.id); break;
case 0x29: name = "orcf"; rhs.register(8, A.id); break;
case 0x2a: name = "xorcf"; rhs.register(8, A.id); break;
@@ -266,7 +266,7 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
case 0x32: name = "chg"; rhs.immediate(4, (n4)read8()); break;
case 0x33: name = "bit"; rhs.immediate(4, (n4)read8()); break;
case 0x34: name = "tset"; rhs.immediate(4, (n4)read8()); break;
case 0x35 ... 0x37: break;
case range3(0x35, 0x37): break;
case 0x38: name = "minc1"; rhs.immediate(16, read16()); break;
case 0x39: name = "minc2"; rhs.immediate(16, read16()); break;
case 0x3a: name = "minc4"; rhs.immediate(16, read16()); break;
@@ -275,22 +275,22 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
case 0x3d: name = "mdec2"; rhs.immediate(16, read16()); break;
case 0x3e: name = "mdec4"; rhs.immediate(16, read16()); break;
case 0x3f: break;
case 0x40 ... 0x47: name = "mul"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x48 ... 0x4f: name = "muls"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x50 ... 0x57: name = "div"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x58 ... 0x5f: name = "divs"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x60 ... 0x67: name = "inc"; rhs.immediate(4, fetch ? natural((n3)fetch) : 8_n); break;
case 0x68 ... 0x6f: name = "dec"; rhs.immediate(4, fetch ? natural((n3)fetch) : 8_n); break;
case 0x70 ... 0x7f: name = "scc"; rhs = lhs; lhs.condition(fetch); break;
case 0x80 ... 0x87: name = "add"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x88 ... 0x8f: name = "ld"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x90 ... 0x97: name = "adc"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x98 ... 0x9f: name = "ld"; rhs.register3(lhs.size(), fetch); break;
case 0xa0 ... 0xa7: name = "sub"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xa8 ... 0xaf: name = "ld"; rhs.immediate(3, (n3)fetch); break;
case 0xb0 ... 0xb7: name = "sbb"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xb8 ... 0xbf: name = "ex"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xc0 ... 0xc7: name = "and"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x40, 0x47): name = "mul"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x48, 0x4f): name = "muls"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x50, 0x57): name = "div"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x58, 0x5f): name = "divs"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x60, 0x67): name = "inc"; rhs.immediate(4, fetch ? natural((n3)fetch) : 8_n); break;
case range8(0x68, 0x6f): name = "dec"; rhs.immediate(4, fetch ? natural((n3)fetch) : 8_n); break;
case range16(0x70, 0x7f): name = "scc"; rhs = lhs; lhs.condition(fetch); break;
case range8(0x80, 0x87): name = "add"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x88, 0x8f): name = "ld"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x90, 0x97): name = "adc"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x98, 0x9f): name = "ld"; rhs.register3(lhs.size(), fetch); break;
case range8(0xa0, 0xa7): name = "sub"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xa8, 0xaf): name = "ld"; rhs.immediate(3, (n3)fetch); break;
case range8(0xb0, 0xb7): name = "sbb"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xb8, 0xbf): name = "ex"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xc0, 0xc7): name = "and"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xc8: name = "add"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xc9: name = "adc"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xca: name = "sub"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
@@ -299,9 +299,9 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
case 0xcd: name = "xor"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xce: name = "or"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xcf: name = "cp"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0xd0 ... 0xd7: name = "xor"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xd8 ... 0xdf: name = "cp"; rhs.immediate(3, (n3)fetch); break;
case 0xe0 ... 0xe7: name = "or"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xd0, 0xd7): name = "xor"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xd8, 0xdf): name = "cp"; rhs.immediate(3, (n3)fetch); break;
case range8(0xe0, 0xe7): name = "or"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xe8: name = "rlc"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xe9: name = "rrc"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xea: name = "rl"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
@@ -310,7 +310,7 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
case 0xed: name = "sra"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xee: name = "sll"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xef: name = "srl"; { auto data = read8(); rhs.immediate(5, data ? natural(data) : 16_n); } break;
case 0xf0 ... 0xf7: name = "cp"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xf0, 0xf7): name = "cp"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xf8: name = "rlc"; rhs.register(8, A.id); break;
case 0xf9: name = "rrc"; rhs.register(8, A.id); break;
case 0xfa: name = "rl"; rhs.register(8, A.id); break;
@@ -324,12 +324,12 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
//size defined
if(opSourceMemory)
switch(auto fetch = read8()) {
case 0x00 ... 0x03: break;
case range4(0x00, 0x03): break;
case 0x04: name = lhs.size() == 8 ? "push" : "pushw"; break;
case 0x05: break;
case 0x06: name = "rld"; rhs = lhs; lhs.register(8, A.id); break;
case 0x07: name = "rrd"; rhs = lhs; lhs.register(8, A.id); break;
case 0x08 ... 0x0f: break;
case range8(0x08, 0x0f): break;
case 0x10:
name = lhs.size() == 8 ? "ldi" : "ldiw";
lhs.indirectRegisterIncrement(32, (n3)op[0] != 5 ? XDE.id : XIX.id);
@@ -372,10 +372,10 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
break;
case 0x18: break;
case 0x19: name = "ld"; rhs = lhs; lhs.indirectImmediate16(16, read16()); break;
case 0x1a ... 0x1f: break;
case 0x20 ... 0x27: name = "ld"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x28 ... 0x2f: break;
case 0x30 ... 0x37: name = "ex"; rhs.register3(lhs.size(), fetch); break;
case range6(0x1a, 0x1f): break;
case range8(0x20, 0x27): name = "ld"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x28, 0x2f): break;
case range8(0x30, 0x37): name = "ex"; rhs.register3(lhs.size(), fetch); break;
case 0x38: name = "add"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x39: name = "adc"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x3a: name = "sub"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
@@ -384,13 +384,13 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
case 0x3d: name = "xor"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x3e: name = "or"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x3f: name = "cp"; rhs.immediate(lhs.size(), reads(lhs.size())); break;
case 0x40 ... 0x47: name = "mul"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x48 ... 0x4f: name = "muls"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x50 ... 0x57: name = "div"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x58 ... 0x5f: name = "divs"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x60 ... 0x67: name = "inc"; rhs.immediate(4, (n3)fetch ? natural((n3)fetch) : 8_n); break;
case 0x68 ... 0x6f: name = "dec"; rhs.immediate(4, (n3)fetch ? natural((n3)fetch) : 8_n); break;
case 0x70 ... 0x77: break;
case range8(0x40, 0x47): name = "mul"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x48, 0x4f): name = "muls"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x50, 0x57): name = "div"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x58, 0x5f): name = "divs"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x60, 0x67): name = "inc"; rhs.immediate(4, (n3)fetch ? natural((n3)fetch) : 8_n); break;
case range8(0x68, 0x6f): name = "dec"; rhs.immediate(4, (n3)fetch ? natural((n3)fetch) : 8_n); break;
case range8(0x70, 0x77): break;
case 0x78: name = "rlc"; break;
case 0x79: name = "rrc"; break;
case 0x7a: name = "rl"; break;
@@ -399,22 +399,22 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
case 0x7d: name = "sra"; break;
case 0x7e: name = "sll"; break;
case 0x7f: name = "srl"; break;
case 0x80 ... 0x87: name = "add"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x88 ... 0x8f: name = "add"; rhs.register3(lhs.size(), fetch); break;
case 0x90 ... 0x97: name = "adc"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x98 ... 0x9f: name = "adc"; rhs.register3(lhs.size(), fetch); break;
case 0xa0 ... 0xa7: name = "sub"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xa8 ... 0xaf: name = "sub"; rhs.register3(lhs.size(), fetch); break;
case 0xb0 ... 0xb7: name = "sbb"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xb8 ... 0xbf: name = "sbb"; rhs.register3(lhs.size(), fetch); break;
case 0xc0 ... 0xc7: name = "and"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xc8 ... 0xcf: name = "and"; rhs.register3(lhs.size(), fetch); break;
case 0xd0 ... 0xd7: name = "xor"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xd8 ... 0xdf: name = "xor"; rhs.register3(lhs.size(), fetch); break;
case 0xe0 ... 0xe7: name = "or"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xe8 ... 0xef: name = "or"; rhs.register3(lhs.size(), fetch); break;
case 0xf0 ... 0xf7: name = "cp"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0xf8 ... 0xff: name = "cp"; rhs.register3(lhs.size(), fetch); break;
case range8(0x80, 0x87): name = "add"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x88, 0x8f): name = "add"; rhs.register3(lhs.size(), fetch); break;
case range8(0x90, 0x97): name = "adc"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x98, 0x9f): name = "adc"; rhs.register3(lhs.size(), fetch); break;
case range8(0xa0, 0xa7): name = "sub"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xa8, 0xaf): name = "sub"; rhs.register3(lhs.size(), fetch); break;
case range8(0xb0, 0xb7): name = "sbb"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xb8, 0xbf): name = "sbb"; rhs.register3(lhs.size(), fetch); break;
case range8(0xc0, 0xc7): name = "and"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xc8, 0xcf): name = "and"; rhs.register3(lhs.size(), fetch); break;
case range8(0xd0, 0xd7): name = "xor"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xd8, 0xdf): name = "xor"; rhs.register3(lhs.size(), fetch); break;
case range8(0xe0, 0xe7): name = "or"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xe8, 0xef): name = "or"; rhs.register3(lhs.size(), fetch); break;
case range8(0xf0, 0xf7): name = "cp"; rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0xf8, 0xff): name = "cp"; rhs.register3(lhs.size(), fetch); break;
}
//size undefined
@@ -427,41 +427,41 @@ noinline auto TLCS900H::disassembleInstruction() -> string {
case 0x04: name = "pop"; lhs.size(8); break;
case 0x05: break;
case 0x06: name = "pop"; lhs.size(16); break;
case 0x07 ... 0x13: break;
case range13(0x07, 0x13): break;
case 0x14: name = "ld"; lhs.size(8); rhs.indirectImmediate16(16, read16()); break;
case 0x15: break;
case 0x16: name = "ld"; lhs.size(16); rhs.indirectImmediate16(16, read16()); break;
case 0x17 ... 0x1f: break;
case 0x20 ... 0x27: name = "lda"; lhs.size(16); rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range9(0x17, 0x1f): break;
case range8(0x20, 0x27): name = "lda"; lhs.size(16); rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x28: name = "andcf"; lhs.size(8); rhs.register3(8, A.id); break;
case 0x29: name = "orcf"; lhs.size(8); rhs.register3(8, A.id); break;
case 0x2a: name = "xorcf"; lhs.size(8); rhs.register3(8, A.id); break;
case 0x2b: name = "ldcf"; lhs.size(8); rhs.register3(8, A.id); break;
case 0x2c: name = "stcf"; lhs.size(8); rhs.register3(8, A.id); break;
case 0x2d ... 0x2f: break;
case 0x30 ... 0x37: name = "lda"; lhs.size(32); rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case 0x38 ... 0x3f: break;
case 0x40 ... 0x47: name = "ld"; lhs.size(8); rhs.register3(lhs.size(), fetch); break;
case 0x48 ... 0x4f: break;
case 0x50 ... 0x57: name = "ld"; lhs.size(16); rhs.register3(lhs.size(), fetch); break;
case 0x58 ... 0x5f: break;
case 0x60 ... 0x67: name = "ld"; lhs.size(32); rhs.register3(lhs.size(), fetch); break;
case 0x68 ... 0x6f: break;
case 0x70 ... 0x77: break;
case 0x78 ... 0x7f: break;
case 0x80 ... 0x87: name = "andcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case 0x88 ... 0x8f: name = "orcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case 0x90 ... 0x97: name = "xorcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case 0x98 ... 0x9f: name = "ldcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case 0xa0 ... 0xa7: name = "stcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case 0xa8 ... 0xaf: name = "tset"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case 0xb0 ... 0xb7: name = "res"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case 0xb8 ... 0xbf: name = "set"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case 0xc0 ... 0xc7: name = "chg"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case 0xc8 ... 0xcf: name = "bit"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case 0xd0 ... 0xdf: name = "jp"; lhs.size(32); rhs = lhs; lhs.condition(fetch); break;
case 0xe0 ... 0xef: name = "call"; lhs.size(32); rhs = lhs; lhs.condition(fetch); break;
case 0xf0 ... 0xff: name = "ret"; lhs.condition(fetch); break;
case range3(0x2d, 0x2f): break;
case range8(0x30, 0x37): name = "lda"; lhs.size(32); rhs = lhs; lhs.register3(rhs.size(), fetch); break;
case range8(0x38, 0x3f): break;
case range8(0x40, 0x47): name = "ld"; lhs.size(8); rhs.register3(lhs.size(), fetch); break;
case range8(0x48, 0x4f): break;
case range8(0x50, 0x57): name = "ld"; lhs.size(16); rhs.register3(lhs.size(), fetch); break;
case range8(0x58, 0x5f): break;
case range8(0x60, 0x67): name = "ld"; lhs.size(32); rhs.register3(lhs.size(), fetch); break;
case range8(0x68, 0x6f): break;
case range8(0x70, 0x77): break;
case range8(0x78, 0x7f): break;
case range8(0x80, 0x87): name = "andcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case range8(0x88, 0x8f): name = "orcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case range8(0x90, 0x97): name = "xorcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case range8(0x98, 0x9f): name = "ldcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case range8(0xa0, 0xa7): name = "stcf"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case range8(0xa8, 0xaf): name = "tset"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case range8(0xb0, 0xb7): name = "res"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case range8(0xb8, 0xbf): name = "set"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case range8(0xc0, 0xc7): name = "chg"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case range8(0xc8, 0xcf): name = "bit"; lhs.size(8); rhs.immediate(3, (n3)fetch); break;
case range16(0xd0, 0xdf): name = "jp"; lhs.size(32); rhs = lhs; lhs.condition(fetch); break;
case range16(0xe0, 0xef): name = "call"; lhs.size(32); rhs = lhs; lhs.condition(fetch); break;
case range16(0xf0, 0xff): name = "ret"; lhs.condition(fetch); break;
}
auto operand = [&](Operand& operand) -> string {
+104 -104
View File
@@ -187,41 +187,41 @@ auto TLCS900H::instruction() -> void {
case 0x1f: {
return undefined();
}
case 0x20 ... 0x27: { //LD R,n
case range8(0x20, 0x27): { //LD R,n
auto immediate = fetchImmediate<n8>();
prefetch(4);
return instructionLoad(toRegister3<n8>(data), immediate);
}
case 0x28 ... 0x2f: { //PUSH.W rr
case range8(0x28, 0x2f): { //PUSH.W rr
prefetch(4);
return instructionPush(toRegister3<n16>(data));
}
case 0x30 ... 0x37: { //LD RR,nn
case range8(0x30, 0x37): { //LD RR,nn
auto immediate = fetchImmediate<n16>();
prefetch(6);
return instructionLoad(toRegister3<n16>(data), immediate);
}
case 0x38 ... 0x3f: { //PUSH.L XRR
case range8(0x38, 0x3f): { //PUSH.L XRR
prefetch(6);
return instructionPush(toRegister3<n32>(data));
}
case 0x40 ... 0x47: { //LD XRR,nnnn
case range8(0x40, 0x47): { //LD XRR,nnnn
auto immediate = fetchImmediate<n32>();
prefetch(10);
return instructionLoad(toRegister3<n32>(data), immediate);
}
case 0x48 ... 0x4f: { //POP.W RR
case range8(0x48, 0x4f): { //POP.W RR
prefetch(6);
return instructionPop(toRegister3<n16>(data));
}
case 0x50 ... 0x57: {
case range8(0x50, 0x57): {
return undefined();
}
case 0x58 ... 0x5f: { //POP.L XRR
case range8(0x58, 0x5f): { //POP.L XRR
prefetch(8);
return instructionPop(toRegister3<n32>(data));
}
case 0x60 ... 0x6f: { //JR cc,PC+d
case range16(0x60, 0x6f): { //JR cc,PC+d
auto immediate = fetchImmediate<i8>();
prefetch(4);
if(!condition((n4)data)) return;
@@ -229,7 +229,7 @@ auto TLCS900H::instruction() -> void {
instructionJumpRelative(immediate);
return prefetch(2);
}
case 0x70 ... 0x7f: { //JRL cc,PC+dd
case range16(0x70, 0x7f): { //JRL cc,PC+dd
auto immediate = fetchImmediate<i16>();
prefetch(4);
if(!condition((n4)data)) return;
@@ -237,34 +237,34 @@ auto TLCS900H::instruction() -> void {
instructionJumpRelative(immediate);
return prefetch(2);
}
case 0x80 ... 0x87: { //src.B
case range8(0x80, 0x87): { //src.B
return instructionSourceMemory(toMemory<n8>(load(toRegister3<n32>(data))));
}
case 0x88 ... 0x8f: { //src.B
case range8(0x88, 0x8f): { //src.B
auto immediate = fetch<i8>();
prefetch(2);
return instructionSourceMemory(toMemory<n8>(load(toRegister3<n32>(data)) + immediate));
}
case 0x90 ... 0x97: { //src.W
case range8(0x90, 0x97): { //src.W
return instructionSourceMemory(toMemory<n16>(load(toRegister3<n32>(data))));
}
case 0x98 ... 0x9f: { //src.W
case range8(0x98, 0x9f): { //src.W
auto immediate = fetch<i8>();
prefetch(2);
return instructionSourceMemory(toMemory<n16>(load(toRegister3<n32>(data)) + immediate));
}
case 0xa0 ... 0xa7: { //src.L
case range8(0xa0, 0xa7): { //src.L
return instructionSourceMemory(toMemory<n32>(load(toRegister3<n32>(data))));
}
case 0xa8 ... 0xaf: { //src.L
case range8(0xa8, 0xaf): { //src.L
auto immediate = fetch<i8>();
prefetch(2);
return instructionSourceMemory(toMemory<n32>(load(toRegister3<n32>(data)) + immediate));
}
case 0xb0 ... 0xb7: { //dst
case range8(0xb0, 0xb7): { //dst
return instructionTargetMemory(load(toRegister3<n32>(data)));
}
case 0xb8 ... 0xbf: { //dst
case range8(0xb8, 0xbf): { //dst
auto immediate = fetch<i8>();
prefetch(2);
return instructionTargetMemory(load(toRegister3<n32>(data)) + immediate);
@@ -342,7 +342,7 @@ auto TLCS900H::instruction() -> void {
prefetch(2);
return instructionRegister(register);
}
case 0xc8 ... 0xcf: { //reg.B
case range8(0xc8, 0xcf): { //reg.B
return instructionRegister(toRegister3<n8>(data));
}
case 0xd0: { //src.W
@@ -418,7 +418,7 @@ auto TLCS900H::instruction() -> void {
prefetch(2);
return instructionRegister(register);
}
case 0xd8 ... 0xdf: { //reg.W
case range8(0xd8, 0xdf): { //reg.W
return instructionRegister(toRegister3<n16>(data));
}
case 0xe0: { //src.L
@@ -494,7 +494,7 @@ auto TLCS900H::instruction() -> void {
prefetch(2);
return instructionRegister(register);
}
case 0xe8 ... 0xef: { //reg.L
case range8(0xe8, 0xef): { //reg.L
return instructionRegister(toRegister3<n32>(data));
}
case 0xf0: { //dst
@@ -542,10 +542,10 @@ auto TLCS900H::instruction() -> void {
auto address = load(PC) + immediate; //load PC before final byte fetch
data = fetch();
switch(data) {
case 0x20 ... 0x27:
case range8(0x20, 0x27):
prefetch(14);
return instructionLoad(toRegister3<n16>(data), toImmediate<n16>(address));
case 0x30 ... 0x37:
case range8(0x30, 0x37):
prefetch(14);
return instructionLoad(toRegister3<n32>(data), toImmediate<n32>(address));
}
@@ -587,7 +587,7 @@ auto TLCS900H::instruction() -> void {
prefetch(14);
return instructionLoad(memory, immediate);
}
case 0xf8 ... 0xff: { //SWI n
case range8(0xf8, 0xff): { //SWI n
return instructionSoftwareInterrupt((n3)data);
}
@@ -602,7 +602,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
switch(data) {
case 0x00 ... 0x02: {
case range3(0x00, 0x02): {
return undefined();
}
case 0x03: { //LD r,#
@@ -744,7 +744,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
}
return undefined();
}
case 0x17 ... 0x18: {
case range2(0x17, 0x18): {
return undefined();
}
case 0x19: { //MULA r
@@ -754,7 +754,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
}
return undefined();
}
case 0x1a ... 0x1b: {
case range2(0x1a, 0x1b): {
return undefined();
}
case 0x1c: { //DJNZ r,d
@@ -765,7 +765,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
}
return undefined();
}
case 0x1d ... 0x1f: {
case range3(0x1d, 0x1f): {
return undefined();
}
case 0x20: { //ANDCF #,r
@@ -808,7 +808,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
}
return undefined();
}
case 0x25 ... 0x27: {
case range3(0x25, 0x27): {
return undefined();
}
case 0x28: { //ANDCF A,r
@@ -899,7 +899,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
}
return undefined();
}
case 0x35 ... 0x37: {
case range3(0x35, 0x37): {
return undefined();
}
case 0x38: { //MINC1 #,r
@@ -956,7 +956,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
case 0x3f: {
return undefined();
}
case 0x40 ... 0x47: { //MUL R,r
case range8(0x40, 0x47): { //MUL R,r
if constexpr(!Long) {
if constexpr(Byte) prefetch(22);
if constexpr(Word) prefetch(28);
@@ -964,7 +964,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
}
return undefined();
}
case 0x48 ... 0x4f: { //MULS R,r
case range8(0x48, 0x4f): { //MULS R,r
if constexpr(!Long) {
if constexpr(Byte) prefetch(18);
if constexpr(Word) prefetch(24);
@@ -972,7 +972,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
}
return undefined();
}
case 0x50 ... 0x57: { //DIV R,r
case range8(0x50, 0x57): { //DIV R,r
if constexpr(!Long) {
if constexpr(Byte) prefetch(30);
if constexpr(Word) prefetch(46);
@@ -980,7 +980,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
}
return undefined();
}
case 0x58 ... 0x5f: { //DIVS R,r
case range8(0x58, 0x5f): { //DIVS R,r
if constexpr(!Long) {
if constexpr(Byte) prefetch(36);
if constexpr(Word) prefetch(52);
@@ -988,57 +988,57 @@ auto TLCS900H::instructionRegister(R register) -> void {
}
return undefined();
}
case 0x60 ... 0x67: { //INC #3,r
case range8(0x60, 0x67): { //INC #3,r
prefetch(4);
return instructionIncrement(register, toImmediate<T>((n3)data));
}
case 0x68 ... 0x6f: { //DEC #3,r
case range8(0x68, 0x6f): { //DEC #3,r
prefetch(4);
return instructionDecrement(register, toImmediate<T>((n3)data));
}
case 0x70 ... 0x7f: { //SCC cc,r
case range16(0x70, 0x7f): { //SCC cc,r
if constexpr(!Long) {
prefetch(4);
return instructionSetConditionCode((n4)data, register);
}
return undefined();
}
case 0x80 ... 0x87: { //ADD R,r
case range8(0x80, 0x87): { //ADD R,r
prefetch(4);
return instructionAdd(toRegister3<T>(data), register);
}
case 0x88 ... 0x8f: { //LD R,r
case range8(0x88, 0x8f): { //LD R,r
prefetch(4);
return instructionLoad(toRegister3<T>(data), register);
}
case 0x90 ... 0x97: { //ADC R,r
case range8(0x90, 0x97): { //ADC R,r
prefetch(4);
return instructionAddCarry(toRegister3<T>(data), register);
}
case 0x98 ... 0x9f: { //LD r,R
case range8(0x98, 0x9f): { //LD r,R
prefetch(4);
return instructionLoad(register, toRegister3<T>(data));
}
case 0xa0 ... 0xa7: { //SUB R,r
case range8(0xa0, 0xa7): { //SUB R,r
prefetch(4);
return instructionSubtract(toRegister3<T>(data), register);
}
case 0xa8 ... 0xaf: { //LD r,#3
case range8(0xa8, 0xaf): { //LD r,#3
prefetch(4);
return instructionLoad(register, toImmediate<T>((n3)data));
}
case 0xb0 ... 0xb7: { //SBC R,r
case range8(0xb0, 0xb7): { //SBC R,r
prefetch(4);
return instructionSubtractBorrow(toRegister3<T>(data), register);
}
case 0xb8 ... 0xbf: { //EX R,r
case range8(0xb8, 0xbf): { //EX R,r
if constexpr(!Long) {
prefetch(6);
return instructionExchange(toRegister3<T>(data), register);
}
return undefined();
}
case 0xc0 ... 0xc7: { //AND R,r
case range8(0xc0, 0xc7): { //AND R,r
prefetch(4);
return instructionAnd(toRegister3<T>(data), register);
}
@@ -1098,18 +1098,18 @@ auto TLCS900H::instructionRegister(R register) -> void {
if constexpr(Long) prefetch(12);
return instructionCompare(register, immediate);
}
case 0xd0 ... 0xd7: { //XOR R,r
case range8(0xd0, 0xd7): { //XOR R,r
prefetch(4);
return instructionXor(toRegister3<T>(data), register);
}
case 0xd8 ... 0xdf: { //CP r,#3
case range8(0xd8, 0xdf): { //CP r,#3
if constexpr(!Long) {
prefetch(4);
return instructionCompare(register, toImmediate<T>((n3)data));
}
return undefined();
}
case 0xe0 ... 0xe7: { //OR R,r
case range8(0xe0, 0xe7): { //OR R,r
prefetch(4);
return instructionOr(toRegister3<T>(data), register);
}
@@ -1153,7 +1153,7 @@ auto TLCS900H::instructionRegister(R register) -> void {
prefetch(6);
return instructionShiftRightLogical(register, immediate);
}
case 0xf0 ... 0xf7: { //CP R,r
case range8(0xf0, 0xf7): { //CP R,r
prefetch(4);
return instructionCompare(toRegister3<T>(data), register);
}
@@ -1201,7 +1201,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
switch(data) {
case 0x00 ... 0x03: {
case range4(0x00, 0x03): {
return undefined();
}
case 0x04: { //PUSH (mem)
@@ -1228,7 +1228,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
}
return undefined();
}
case 0x08 ... 0x0f: {
case range8(0x08, 0x0f): {
return undefined();
}
case 0x10: { //LDI
@@ -1301,19 +1301,19 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
}
return undefined();
}
case 0x1a ... 0x1f: {
case range6(0x1a, 0x1f): {
return undefined();
}
case 0x20 ... 0x27: { //LD R,(mem)
case range8(0x20, 0x27): { //LD R,(mem)
if constexpr(Byte) prefetch(6);
if constexpr(Word) prefetch(6);
if constexpr(Long) prefetch(8);
return instructionLoad(toRegister3<T>(data), memory);
}
case 0x28 ... 0x2f: {
case range8(0x28, 0x2f): {
return undefined();
}
case 0x30 ... 0x37: { //EX (mem),R
case range8(0x30, 0x37): { //EX (mem),R
if constexpr(!Long) {
prefetch(8);
return instructionExchange(memory, toRegister3<T>(data));
@@ -1391,7 +1391,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
}
return undefined();
}
case 0x40 ... 0x47: { //MUL R,(mem)
case range8(0x40, 0x47): { //MUL R,(mem)
if constexpr(!Long) {
if constexpr(Byte) prefetch(24);
if constexpr(Word) prefetch(30);
@@ -1399,7 +1399,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
}
return undefined();
}
case 0x48 ... 0x4f: { //MULS R,(mem)
case range8(0x48, 0x4f): { //MULS R,(mem)
if constexpr(!Long) {
if constexpr(Byte) prefetch(20);
if constexpr(Word) prefetch(26);
@@ -1407,7 +1407,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
}
return undefined();
}
case 0x50 ... 0x57: { //DIV R,(mem)
case range8(0x50, 0x57): { //DIV R,(mem)
if constexpr(!Long) {
if constexpr(Byte) prefetch(30);
if constexpr(Word) prefetch(46);
@@ -1415,7 +1415,7 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
}
return undefined();
}
case 0x58 ... 0x5f: { //DIVS R,(mem)
case range8(0x58, 0x5f): { //DIVS R,(mem)
if constexpr(!Long) {
if constexpr(Byte) prefetch(36);
if constexpr(Word) prefetch(52);
@@ -1423,21 +1423,21 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
}
return undefined();
}
case 0x60 ... 0x67: { //INC #3,(mem)
case range8(0x60, 0x67): { //INC #3,(mem)
if constexpr(!Long) {
prefetch(8);
return instructionIncrement(memory, toImmediate<T>((n3)data));
}
return undefined();
}
case 0x68 ... 0x6f: { //DEC #3,(mem)
case range8(0x68, 0x6f): { //DEC #3,(mem)
if constexpr(!Long) {
prefetch(8);
return instructionDecrement(memory, toImmediate<T>((n3)data));
}
return undefined();
}
case 0x70 ... 0x77: {
case range8(0x70, 0x77): {
return undefined();
}
case 0x78: { //RLC (mem)
@@ -1496,97 +1496,97 @@ auto TLCS900H::instructionSourceMemory(M memory) -> void {
}
return undefined();
}
case 0x80 ... 0x87: { //ADD R,(mem)
case range8(0x80, 0x87): { //ADD R,(mem)
if constexpr(Byte) prefetch(6);
if constexpr(Word) prefetch(6);
if constexpr(Long) prefetch(8);
return instructionAdd(toRegister3<T>(data), memory);
}
case 0x88 ... 0x8f: { //ADD (mem),R
case range8(0x88, 0x8f): { //ADD (mem),R
if constexpr(Byte) prefetch(8);
if constexpr(Word) prefetch(8);
if constexpr(Long) prefetch(12);
return instructionAdd(memory, toRegister3<T>(data));
}
case 0x90 ... 0x97: { //ADC R,(mem)
case range8(0x90, 0x97): { //ADC R,(mem)
if constexpr(Byte) prefetch(6);
if constexpr(Word) prefetch(6);
if constexpr(Long) prefetch(8);
return instructionAddCarry(toRegister3<T>(data), memory);
}
case 0x98 ... 0x9f: { //ADC (mem),R
case range8(0x98, 0x9f): { //ADC (mem),R
if constexpr(Byte) prefetch(8);
if constexpr(Word) prefetch(8);
if constexpr(Long) prefetch(12);
return instructionAddCarry(memory, toRegister3<T>(data));
}
case 0xa0 ... 0xa7: { //SUB R,(mem)
case range8(0xa0, 0xa7): { //SUB R,(mem)
if constexpr(Byte) prefetch(6);
if constexpr(Word) prefetch(6);
if constexpr(Long) prefetch(8);
return instructionSubtract(toRegister3<T>(data), memory);
}
case 0xa8 ... 0xaf: { //SUB (mem),R
case range8(0xa8, 0xaf): { //SUB (mem),R
if constexpr(Byte) prefetch(8);
if constexpr(Word) prefetch(8);
if constexpr(Long) prefetch(12);
return instructionSubtract(memory, toRegister3<T>(data));
}
case 0xb0 ... 0xb7: { //SBC R,(mem)
case range8(0xb0, 0xb7): { //SBC R,(mem)
if constexpr(Byte) prefetch(6);
if constexpr(Word) prefetch(6);
if constexpr(Long) prefetch(8);
return instructionSubtractBorrow(toRegister3<T>(data), memory);
}
case 0xb8 ... 0xbf: { //SBC (mem),R
case range8(0xb8, 0xbf): { //SBC (mem),R
if constexpr(Byte) prefetch(8);
if constexpr(Word) prefetch(8);
if constexpr(Long) prefetch(12);
return instructionSubtractBorrow(memory, toRegister3<T>(data));
}
case 0xc0 ... 0xc7: { //AND R,(mem)
case range8(0xc0, 0xc7): { //AND R,(mem)
if constexpr(Byte) prefetch(6);
if constexpr(Word) prefetch(6);
if constexpr(Long) prefetch(8);
return instructionAnd(toRegister3<T>(data), memory);
}
case 0xc8 ... 0xcf: { //AND (mem),R
case range8(0xc8, 0xcf): { //AND (mem),R
if constexpr(Byte) prefetch(8);
if constexpr(Word) prefetch(8);
if constexpr(Long) prefetch(12);
return instructionAnd(memory, toRegister3<T>(data));
}
case 0xd0 ... 0xd7: { //XOR R,(mem)
case range8(0xd0, 0xd7): { //XOR R,(mem)
if constexpr(Byte) prefetch(6);
if constexpr(Word) prefetch(6);
if constexpr(Long) prefetch(8);
return instructionXor(toRegister3<T>(data), memory);
}
case 0xd8 ... 0xdf: { //XOR (mem),R
case range8(0xd8, 0xdf): { //XOR (mem),R
if constexpr(Byte) prefetch(8);
if constexpr(Word) prefetch(8);
if constexpr(Long) prefetch(12);
return instructionXor(memory, toRegister3<T>(data));
}
case 0xe0 ... 0xe7: { //OR R,(mem)
case range8(0xe0, 0xe7): { //OR R,(mem)
if constexpr(Byte) prefetch(6);
if constexpr(Word) prefetch(6);
if constexpr(Long) prefetch(8);
return instructionOr(toRegister3<T>(data), memory);
}
case 0xe8 ... 0xef: { //OR (mem),R
case range8(0xe8, 0xef): { //OR (mem),R
if constexpr(Byte) prefetch(8);
if constexpr(Word) prefetch(8);
if constexpr(Long) prefetch(12);
return instructionOr(memory, toRegister3<T>(data));
}
case 0xf0 ... 0xf7: { //CP R,(mem)
case range8(0xf0, 0xf7): { //CP R,(mem)
if constexpr(Byte) prefetch(6);
if constexpr(Word) prefetch(6);
if constexpr(Long) prefetch(8);
return instructionCompare(toRegister3<T>(data), memory);
}
case 0xf8 ... 0xff: { //CP (mem),R
case range8(0xf8, 0xff): { //CP (mem),R
if constexpr(Byte) prefetch(6);
if constexpr(Word) prefetch(6);
if constexpr(Long) prefetch(8);
@@ -1628,7 +1628,7 @@ auto TLCS900H::instructionTargetMemory(n32 address) -> void {
prefetch(10);
return instructionPop(toMemory<n16>(address));
}
case 0x07 ... 0x13: {
case range13(0x07, 0x13): {
return undefined();
}
case 0x14: { //LD.B (m),(nn)
@@ -1644,10 +1644,10 @@ auto TLCS900H::instructionTargetMemory(n32 address) -> void {
prefetch(12);
return instructionLoad(toMemory<n16>(address), source);
}
case 0x17 ... 0x1f: {
case range9(0x17, 0x1f): {
return undefined();
}
case 0x20 ... 0x27: { //LDA.W R,mem
case range8(0x20, 0x27): { //LDA.W R,mem
prefetch(8);
return instructionLoad(toRegister3<n16>(data), toImmediate<n16>(address));
}
@@ -1671,91 +1671,91 @@ auto TLCS900H::instructionTargetMemory(n32 address) -> void {
prefetch(12);
return instructionStoreCarry(toMemory<n8>(address), A);
}
case 0x2d ... 0x2f: {
case range3(0x2d, 0x2f): {
return undefined();
}
case 0x30 ... 0x37: { //LDA.L R,mem
case range8(0x30, 0x37): { //LDA.L R,mem
prefetch(8);
return instructionLoad(toRegister3<n32>(data), toImmediate<n32>(address));
}
case 0x38 ... 0x3f: {
case range8(0x38, 0x3f): {
return undefined();
}
case 0x40 ... 0x47: { //LD.B (mem),R
case range8(0x40, 0x47): { //LD.B (mem),R
prefetch(6);
return instructionLoad(toMemory<n8>(address), toRegister3<n8>(data));
}
case 0x48 ... 0x4f: {
case range8(0x48, 0x4f): {
return undefined();
}
case 0x50 ... 0x57: { //LD.W (mem),R
case range8(0x50, 0x57): { //LD.W (mem),R
prefetch(6);
return instructionLoad(toMemory<n16>(address), toRegister3<n16>(data));
}
case 0x58 ... 0x5f: {
case range8(0x58, 0x5f): {
return undefined();
}
case 0x60 ... 0x67: { //LD.L (mem),R
case range8(0x60, 0x67): { //LD.L (mem),R
prefetch(8);
return instructionLoad(toMemory<n32>(address), toRegister3<n32>(data));
}
case 0x68 ... 0x7f: {
case range24(0x68, 0x7f): {
return undefined();
}
case 0x80 ... 0x87: { //ANDCF #3,(mem)
case range8(0x80, 0x87): { //ANDCF #3,(mem)
prefetch(10);
return instructionAndCarry(toMemory<n8>(address), toImmediate<n3>(data));
}
case 0x88 ... 0x8f: { //ORCF #3,(mem)
case range8(0x88, 0x8f): { //ORCF #3,(mem)
prefetch(10);
return instructionOrCarry(toMemory<n8>(address), toImmediate<n3>(data));
}
case 0x90 ... 0x97: { //XORCF #3,(mem)
case range8(0x90, 0x97): { //XORCF #3,(mem)
prefetch(10);
return instructionXorCarry(toMemory<n8>(address), toImmediate<n3>(data));
}
case 0x98 ... 0x9f: { //LDCF #3,(mem)
case range8(0x98, 0x9f): { //LDCF #3,(mem)
prefetch(10);
return instructionLoadCarry(toMemory<n8>(address), toImmediate<n3>(data));
}
case 0xa0 ... 0xa7: { //STCF #3,(mem)
case range8(0xa0, 0xa7): { //STCF #3,(mem)
prefetch(10);
return instructionStoreCarry(toMemory<n8>(address), toImmediate<n3>(data));
}
case 0xa8 ... 0xaf: { //TSET #3,(mem)
case range8(0xa8, 0xaf): { //TSET #3,(mem)
prefetch(10);
return instructionTestSet(toMemory<n8>(address), toImmediate<n3>(data));
}
case 0xb0 ... 0xb7: { //RES #3,(mem)
case range8(0xb0, 0xb7): { //RES #3,(mem)
prefetch(10);
return instructionReset(toMemory<n8>(address), toImmediate<n3>(data));
}
case 0xb8 ... 0xbf: { //SET #3,(mem)
case range8(0xb8, 0xbf): { //SET #3,(mem)
prefetch(10);
return instructionSet(toMemory<n8>(address), toImmediate<n3>(data));
}
case 0xc0 ... 0xc7: { //CHG #3,(mem)
case range8(0xc0, 0xc7): { //CHG #3,(mem)
prefetch(10);
return instructionChange(toMemory<n8>(address), toImmediate<n3>(data));
}
case 0xc8 ... 0xcf: { //BIT #3,(mem)
case range8(0xc8, 0xcf): { //BIT #3,(mem)
prefetch(10);
return instructionBit(toMemory<n8>(address), toImmediate<n3>(data));
}
case 0xd0 ... 0xdf: { //JP cc,mem
case range16(0xd0, 0xdf): { //JP cc,mem
prefetch(8);
if(!condition((n4)data)) return;
prefetch(4);
instructionJump(toImmediate<n32>(address));
return prefetch(2);
}
case 0xe0 ... 0xef: { //CALL cc,mem
case range16(0xe0, 0xef): { //CALL cc,mem
if(!condition((n4)data)) return prefetch(8);
prefetch(20);
instructionCall(toImmediate<n32>(address));
return prefetch(2);
}
case 0xf0 ... 0xff: { //RET cc
case range16(0xf0, 0xff): { //RET cc
if(!condition((n4)data)) return prefetch(8);
prefetch(20);
instructionReturn();
+66 -49
View File
@@ -11,18 +11,23 @@ auto V30MZ::parity(u8 value) const -> bool {
#define sign (size == Byte ? 0x80 : 0x8000)
template<u32 size> auto V30MZ::ADC(u16 x, u16 y) -> u16 {
return ADD<size>(x, y + PSW.CY);
return ADD<size>(x, y, PSW.CY);
}
template<u32 size> auto V30MZ::ADD(u16 x, u16 y) -> u16 {
u16 result = (x + y) & mask;
PSW.CY = x + y > mask;
return ADD<size>(x, y, 0);
}
template<u32 size> auto V30MZ::ADD(u16 x, u16 y, u16 c) -> u16 {
u32 result = x + y + c;
PSW.CY = result > mask;
result &= mask;
PSW.P = parity(result);
PSW.AC = (u4)x + (u4)y >= 16;
PSW.AC = (u4)x + (u4)y + (u4)c >= 16;
PSW.Z = result == 0;
PSW.S = result & sign;
PSW.V = (result ^ x) & (result ^ y) & sign;
return result;
return result & mask;
}
template<u32 size> auto V30MZ::AND(u16 x, u16 y) -> u16 {
@@ -47,20 +52,20 @@ template<u32 size> auto V30MZ::DEC(u16 x) -> u16 {
}
template<u32 size> auto V30MZ::DIVI(s32 x, s32 y) -> u32 {
if(y == 0) return interrupt(0), x;
if(y == 0) return interrupt(0, InterruptSource::CPU), x;
x = size == Byte ? (s16)x : (s32)x;
y = size == Byte ? ( s8)y : (s16)y;
s32 quotient = x / y;
s32 remainder = x % y;
if(quotient > mask >> 1 || quotient < -sign) return interrupt(0), x;
if(quotient > mask >> 1 || quotient < -sign) return interrupt(0, InterruptSource::CPU), x;
return (remainder & mask) << bits | (quotient & mask);
}
template<u32 size> auto V30MZ::DIVU(u32 x, u32 y) -> u32 {
if(y == 0) return interrupt(0), x;
if(y == 0) return interrupt(0, InterruptSource::CPU), x;
u32 quotient = x / y;
u32 remainder = x % y;
if(quotient > mask) return interrupt(0), x;
if(quotient > mask) return interrupt(0, InterruptSource::CPU), x;
return (remainder & mask) << bits | (quotient & mask);
}
@@ -77,9 +82,14 @@ template<u32 size> auto V30MZ::INC(u16 x) -> u16 {
template<u32 size> auto V30MZ::MULI(s16 x, s16 y) -> u32 {
x = size == Byte ? (s8)x : (s16)x;
y = size == Byte ? (s8)y : (s16)y;
u32 result = x * y;
PSW.CY = result >> bits;
PSW.V = result >> bits;
s32 result = x * y;
s32 truncatedResult = size == Byte ? (s8)result : (s16)result;
PSW.CY = result != truncatedResult;
PSW.V = result != truncatedResult;
PSW.P = 0; // undefined
PSW.AC = 0; // undefined
PSW.Z = 1; // undefined
PSW.S = 0; // undefined
return result;
}
@@ -87,6 +97,10 @@ template<u32 size> auto V30MZ::MULU(u16 x, u16 y) -> u32 {
u32 result = x * y;
PSW.CY = result >> bits;
PSW.V = result >> bits;
PSW.P = 0; // undefined
PSW.AC = 0; // undefined
PSW.Z = 1; // undefined
PSW.S = 0; // undefined
return result;
}
@@ -124,7 +138,7 @@ template<u32 size> auto V30MZ::RCL(u16 x, u5 y) -> u16 {
result = (result << 1) | PSW.CY;
PSW.CY = carry;
}
PSW.V = (x ^ result) & sign;
PSW.V = (result ^ (PSW.CY << (bits - 1))) & sign;
return result & mask;
}
@@ -135,78 +149,81 @@ template<u32 size> auto V30MZ::RCR(u16 x, u5 y) -> u16 {
result = (PSW.CY ? sign : 0) | (result >> 1);
PSW.CY = carry;
}
PSW.V = (x ^ result) & sign;
PSW.V = (result ^ (result << 1)) & sign;
return result & mask;
}
template<u32 size> auto V30MZ::ROL(u16 x, u4 y) -> u16 {
PSW.CY = (x << y) & (1 << bits);
u16 result = ((x << y) | (x >> (bits - y))) & mask;
PSW.V = (x ^ result) & sign;
return result;
template<u32 size> auto V30MZ::ROL(u16 x, u5 y) -> u16 {
u16 result = x;
for(u32 n = 0; n < y; n++) {
PSW.CY = result & sign;
result = (result << 1) | PSW.CY;
}
PSW.V = (result ^ (PSW.CY << (bits - 1))) & sign;
return result & mask;
}
template<u32 size> auto V30MZ::ROR(u16 x, u4 y) -> u16 {
PSW.CY = (x >> (y - 1)) & 1;
u16 result = ((x >> y) | (x << (bits - y))) & mask;
PSW.V = (x ^ result) & sign;
return result;
}
template<u32 size> auto V30MZ::SAL(u16 x, u5 y) -> u16 {
PSW.CY = (x << y) & (1 << bits);
u16 result = (x << y) & mask;
PSW.P = parity(result);
PSW.Z = result == 0;
PSW.S = result & sign;
PSW.V = 0;
return result;
template<u32 size> auto V30MZ::ROR(u16 x, u5 y) -> u16 {
u16 result = x;
for(u32 n = 0; n < y; n++) {
PSW.CY = result & 1;
result = (PSW.CY ? sign : 0) | (result >> 1);
}
PSW.V = (result ^ (result << 1)) & sign;
return result & mask;
}
template<u32 size> auto V30MZ::SAR(u16 x, u5 y) -> u16 {
if(y & 16) {
PSW.CY = x & sign;
return 0 - PSW.CY;
u16 result = x;
for(u32 n = 0; n < y; n++) {
PSW.CY = result & 1;
result = (result & sign) | (result >> 1);
}
PSW.CY = (x >> (y - 1)) & 1;
u16 result = (x >> y) & mask;
if(x & sign) result |= mask << (bits - y);
result &= mask;
PSW.AC = 0;
PSW.P = parity(result);
PSW.Z = result == 0;
PSW.S = result & sign;
PSW.V = 0;
PSW.V = (result ^ (result << 1)) & sign;
return result;
}
template<u32 size> auto V30MZ::SBB(u16 x, u16 y) -> u16 {
return SUB<size>(x, y + PSW.CY);
return SUB<size>(x, y, PSW.CY);
}
template<u32 size> auto V30MZ::SHL(u16 x, u5 y) -> u16 {
PSW.CY = (x << y) & (1 << bits);
if(y != 0) PSW.CY = (x << y) & (1 << bits);
u16 result = (x << y) & mask;
PSW.AC = 0;
PSW.P = parity(result);
PSW.Z = result == 0;
PSW.S = result & sign;
PSW.V = (x ^ result) & sign;
PSW.V = (result ^ (PSW.CY << (bits - 1))) & sign;
return result;
}
template<u32 size> auto V30MZ::SHR(u16 x, u5 y) -> u16 {
PSW.CY = (x >> (y - 1)) & 1;
if(y != 0) PSW.CY = (x >> (y - 1)) & 1;
u16 result = (x >> y) & mask;
PSW.AC = 0;
PSW.P = parity(result);
PSW.Z = result == 0;
PSW.S = result & sign;
PSW.V = (x ^ result) & sign;
PSW.V = (result ^ (result << 1)) & sign;
return result;
}
template<u32 size> auto V30MZ::SUB(u16 x, u16 y) -> u16 {
u16 result = (x - y) & mask;
PSW.CY = y > x;
return SUB<size>(x, y, 0);
}
template<u32 size> auto V30MZ::SUB(u16 x, u16 y, u16 c) -> u16 {
s32 result = ((s32)x - (s32)y - (s32)c);
PSW.CY = result < 0;
result &= mask;
PSW.P = parity(result);
PSW.AC = (u4)y > (u4)x;
PSW.AC = (((s16)(x & 0xF)) - ((s16)(y & 0xF)) - ((s16)(c & 0xF))) < 0;
PSW.Z = result == 0;
PSW.S = result & sign;
PSW.V = (x ^ y) & (x ^ result) & sign;
@@ -6,7 +6,7 @@ auto V30MZ::disassembleInstruction(u16 ps, u16 pc) -> string {
string output, repeat, prefix;
auto read = [&](u32 offset) -> n8 {
return V30MZ::read<Byte>(ps, pc + offset);
return this->read(ps * 16 + ((pc + offset) & 0xFFFF));
};
auto modRM = [&](u32 offset = 1) -> u32 {
@@ -379,7 +379,7 @@ auto V30MZ::disassembleInstruction(u16 ps, u16 pc) -> string {
op(0xd3, group2(), memoryWord(), "cl");
op(0xd4, "aam", immediateByte());
op(0xd5, "aad", immediateByte());
op(0xd6, "xlat"); //undocumented mirror
op(0xd6, "salc");
op(0xd7, "xlat");
//op(0xd8);
//op(0xd9);
@@ -394,9 +394,9 @@ auto V30MZ::disassembleInstruction(u16 ps, u16 pc) -> string {
op(0xe2, "loop");
op(0xe3, "jcwz", relativeByte());
op(0xe4, "in", "al", immediateByte());
op(0xe5, "in", "aw", immediateWord());
op(0xe5, "in", "aw", immediateByte());
op(0xe6, "out", immediateByte(), "al");
op(0xe7, "out", immediateWord(), "aw");
op(0xe7, "out", immediateByte(), "aw");
op(0xe8, "call", relativeWord());
op(0xe9, "jmp", relativeWord());
op(0xea, "jmp", immediateLong());
+39 -24
View File
@@ -1,5 +1,7 @@
auto V30MZ::interrupt(u8 vector) -> void {
wait(32);
auto V30MZ::interrupt(u8 vector, InterruptSource source) -> bool {
if(source == InterruptSource::INT) wait(32);
else if (source == InterruptSource::NMI) wait(26);
else wait(25);
state.halt = 0;
state.poll = 1;
@@ -17,16 +19,28 @@ auto V30MZ::interrupt(u8 vector) -> void {
auto ps = read<Word>(0x0000, vector * 4 + 2);
push(PSW);
push(PS);
push(PC);
PSW.MD = 1;
PSW.IE = 0;
PSW.BRK = 0;
PC = pc;
push(PS);
PS = ps;
push(PC);
PC = pc;
flush();
return true;
}
auto V30MZ::interrupt(u8 vector) -> bool {
state.halt = false;
if(!PSW.IE) return false;
return interrupt(vector, InterruptSource::INT);
}
auto V30MZ::nonMaskableInterrupt() -> bool {
return interrupt(2, InterruptSource::NMI);
}
#define op(id, name, ...) case id: instruction##name(__VA_ARGS__); break;
@@ -52,7 +66,7 @@ auto V30MZ::instruction() -> void {
op(0x0c, OrAccImm<Byte>)
op(0x0d, OrAccImm<Word>)
op(0x0e, PushSeg, PS)
op(0x0f, PopSeg, PS)
op(0x0f, Undefined)
op(0x10, AdcMemReg<Byte>)
op(0x11, AdcMemReg<Word>)
op(0x12, AdcRegMem<Byte>)
@@ -136,11 +150,11 @@ auto V30MZ::instruction() -> void {
op(0x60, PushAll)
op(0x61, PopAll)
op(0x62, Bound)
//op(0x63, ...)
//op(0x64, ...) repnc
//op(0x65, ...) repc
//op(0x66, ...) fpo2
//op(0x67, ...) fpo2
op(0x63, Undefined)
op(0x64, Undefined)
op(0x65, Undefined)
op(0x66, Undefined)
op(0x67, Undefined)
op(0x68, PushImm<Word>)
op(0x69, MultiplySignedRegMemImm<Word>)
op(0x6a, PushImm<Byte>)
@@ -156,13 +170,13 @@ auto V30MZ::instruction() -> void {
op(0x74, JumpIf, PSW.Z == 1)
op(0x75, JumpIf, PSW.Z == 0)
op(0x76, JumpIf, PSW.Z == 1 || PSW.CY == 1)
op(0x77, JumpIf, PSW.Z != 1 && PSW.CY != 1)
op(0x77, JumpIf, PSW.Z == 0 && PSW.CY == 0)
op(0x78, JumpIf, PSW.S == 1)
op(0x79, JumpIf, PSW.S == 0)
op(0x7a, JumpIf, PSW.P == 1)
op(0x7b, JumpIf, PSW.P == 0)
op(0x7c, JumpIf, PSW.S != PSW.V && PSW.Z == 0)
op(0x7d, JumpIf, PSW.S == PSW.V || PSW.Z == 1)
op(0x7c, JumpIf, PSW.S != PSW.V)
op(0x7d, JumpIf, PSW.S == PSW.V)
op(0x7e, JumpIf, PSW.S != PSW.V || PSW.Z == 1)
op(0x7f, JumpIf, PSW.S == PSW.V && PSW.Z == 0)
op(0x80, Group1MemImm<Byte>, 0)
@@ -251,16 +265,16 @@ auto V30MZ::instruction() -> void {
op(0xd3, Group2MemImm<Word>, 3, (u8)CL)
op(0xd4, AdjustAfterMultiply)
op(0xd5, AdjustAfterDivide)
op(0xd6, Translate, 7) //xlat (undocumented mirror)
op(0xd7, Translate, 4) //xlat
//op(0xd8, ...) //fpo1
//op(0xd9, ...) //fpo1
//op(0xda, ...) //fpo1
//op(0xdb, ...) //fpo1
//op(0xdc, ...) //fpo1
//op(0xdd, ...) //fpo1
//op(0xde, ...) //fpo1
//op(0xdf, ...) //fpo1
op(0xd6, SetALCarry) //salc
op(0xd7, Translate) //xlat
op(0xd8, Undefined1)
op(0xd9, Undefined1)
op(0xda, Undefined1)
op(0xdb, Undefined1)
op(0xdc, Undefined1)
op(0xdd, Undefined1)
op(0xde, Undefined1)
op(0xdf, Undefined1)
op(0xe0, LoopWhile, 0) //loopnz
op(0xe1, LoopWhile, 1) //loopz
op(0xe2, Loop)
@@ -296,6 +310,7 @@ auto V30MZ::instruction() -> void {
}
if(!state.prefix) prefixes.flush();
if(PSW.BRK) interrupt(1, InterruptSource::SingleStep);
}
#undef op
@@ -1,13 +1,23 @@
auto V30MZ::instructionDecimalAdjust(bool negate) -> void {
wait(10 + negate);
n8 al = AL;
PSW.V = 0; // undefined
if(PSW.AC || ((al & 0x0f) > 0x09)) {
AL += negate ? -0x06 : 0x06;
PSW.AC = 1;
if(negate) PSW.V |= (al ^ 0x06) & (al ^ AL) & 0x80; // undefined
else PSW.V |= (AL ^ al) & (AL ^ 0x06) & 0x80; // undefined
} else {
PSW.AC = 0;
}
if(PSW.CY || (al > 0x99)) {
al = AL;
AL += negate ? -0x60 : 0x60;
PSW.CY = 1;
if(negate) PSW.V |= (al ^ 0x06) & (al ^ AL) & 0x80; // undefined
else PSW.V |= (AL ^ al) & (AL ^ 0x60) & 0x80; // undefined
} else {
PSW.CY = 0;
}
PSW.S = AL & 0x80;
PSW.Z = AL == 0;
@@ -21,19 +31,25 @@ auto V30MZ::instructionAsciiAdjust(bool negate) -> void {
AH += negate ? -0x01 : 0x01;
PSW.AC = 1;
PSW.CY = 1;
PSW.S = 0; // undefined
PSW.Z = 1; // undefined
} else {
AL &= 0x0f;
PSW.AC = 0;
PSW.CY = 0;
PSW.S = 1; // undefined
PSW.Z = 0; // undefined
}
AL &= 0x0f;
PSW.V = 0; // undefined
PSW.P = 1; // undefined
}
auto V30MZ::instructionAdjustAfterMultiply() -> void {
wait(16);
auto imm = fetch<Byte>();
if(imm == 0) return interrupt(0);
//NEC CPUs do not honor the immediate and always use (base) 10
AH = AL / 10;
if(imm == 0) { interrupt(0, InterruptSource::CPU); return; }
AH = AL / imm;
AL %= imm;
PSW.P = parity(AL);
PSW.S = AW & 0x8000;
@@ -43,10 +59,6 @@ auto V30MZ::instructionAdjustAfterMultiply() -> void {
auto V30MZ::instructionAdjustAfterDivide() -> void {
wait(6);
auto imm = fetch<Byte>();
//NEC CPUs do not honor the immediate and always use (base) 10
AL += AH * 10;
AL = ADD<Byte>(AL, MULU<Byte>(AH, imm) & 0xFF, 0);
AH = 0;
PSW.P = parity(AL);
PSW.S = AW & 0x8000;
PSW.Z = AW == 0;
}
@@ -146,7 +146,7 @@ template<u32 size> auto V30MZ::instructionTestMemReg() -> void {
}
template<u32 size> auto V30MZ::instructionMultiplySignedRegMemImm() -> void {
wait(5);
wait(3);
modRM();
setRegister<Word>(MULI<Word>(getMemory<Word>(), size == Word ? (s16)fetch<Word>() : (s8)fetch<Byte>()));
}
@@ -29,7 +29,7 @@ auto V30MZ::instructionJumpIf(bool condition) -> void {
wait(1);
auto offset = (i8)fetch<Byte>();
if(condition) {
wait(3);
wait(2);
PC += offset;
flush();
}
@@ -51,7 +51,7 @@ auto V30MZ::instructionJumpFar() -> void {
}
auto V30MZ::instructionCallNear() -> void {
wait(4);
wait(2);
auto offset = (i16)fetch<Word>();
push(PC);
PC += offset;
@@ -59,7 +59,7 @@ auto V30MZ::instructionCallNear() -> void {
}
auto V30MZ::instructionCallFar() -> void {
wait(9);
wait(6);
auto pc = fetch<Word>();
auto ps = fetch<Word>();
push(PS);
@@ -70,13 +70,13 @@ auto V30MZ::instructionCallFar() -> void {
}
auto V30MZ::instructionReturn() -> void {
wait(5);
wait(4);
PC = pop();
flush();
}
auto V30MZ::instructionReturnImm() -> void {
wait(5);
wait(4);
auto offset = fetch<Word>();
PC = pop();
SP += offset;
@@ -84,14 +84,14 @@ auto V30MZ::instructionReturnImm() -> void {
}
auto V30MZ::instructionReturnFar() -> void {
wait(7);
wait(5);
PC = pop();
PS = pop();
flush();
}
auto V30MZ::instructionReturnFarImm() -> void {
wait(8);
wait(6);
auto offset = fetch<Word>();
PC = pop();
PS = pop();
@@ -100,7 +100,7 @@ auto V30MZ::instructionReturnFarImm() -> void {
}
auto V30MZ::instructionReturnInt() -> void {
wait(9);
wait(6);
PC = pop();
PS = pop();
PSW = pop();
@@ -109,18 +109,21 @@ auto V30MZ::instructionReturnInt() -> void {
}
auto V30MZ::instructionInt3() -> void {
wait(8);
interrupt(3);
wait(9);
interrupt(3, InterruptSource::CPU);
}
auto V30MZ::instructionIntImm() -> void {
wait(9);
interrupt(fetch<Byte>());
wait(10);
interrupt(fetch<Byte>(), InterruptSource::CPU);
}
auto V30MZ::instructionInto() -> void {
wait(5);
interrupt(4);
wait(6);
if(PSW.V) {
wait(7);
interrupt(4, InterruptSource::CPU);
}
}
auto V30MZ::instructionEnter() -> void {
@@ -143,13 +146,15 @@ auto V30MZ::instructionEnter() -> void {
}
auto V30MZ::instructionLeave() -> void {
wait(1);
wait(2);
SP = BP;
BP = pop();
}
auto V30MZ::instructionPushReg(u16& reg) -> void {
push(reg);
// Emulate the 8086/80186 "PUSH SP" bug.
if(&reg == &SP) push(reg - 2);
else push(reg);
}
auto V30MZ::instructionPushSeg(u16& seg) -> void {
@@ -30,7 +30,7 @@ template<u32 size> auto V30MZ::instructionGroup2MemImm(u8 clocks, maybe<u8> imm)
case 3: setMemory<size>(RCR<size>(mem, *imm)); break;
case 4: setMemory<size>(SHL<size>(mem, *imm)); break;
case 5: setMemory<size>(SHR<size>(mem, *imm)); break;
case 6: setMemory<size>(SAL<size>(mem, *imm)); break;
case 6: setMemory<size>(0); break; // undefined opcode
case 7: setMemory<size>(SAR<size>(mem, *imm)); break;
}
}
@@ -40,7 +40,7 @@ template<u32 size> auto V30MZ::instructionGroup3MemImm() -> void {
auto mem = getMemory<size>();
switch(modrm.reg) {
case 0: wait(1); AND<size>(mem, fetch<size>()); break; //TEST
case 1: wait(1); AND<size>(mem, fetch<size>()); break; //TEST (undocumented mirror)
case 1: wait(1); break; // undefined (acts as NOP)
case 2: wait(1); setMemory<size>(NOT<size>(mem)); break;
case 3: wait(1); setMemory<size>(NEG<size>(mem)); break;
case 4: wait(3); setAccumulator<size * 2>(MULU<size>(getAccumulator<size>(), mem)); break;
@@ -62,13 +62,13 @@ template<u32 size> auto V30MZ::instructionGroup4MemImm() -> void {
setMemory<size>(DEC<size>(getMemory<size>()));
break;
case 2: //CALL
wait(5);
wait(3);
push(PC);
PC = getMemory<Word>();
flush();
break;
case 3: //CALLF
wait(11);
wait(7);
push(PS);
push(PC);
PC = getMemory<Word>(0);
@@ -89,8 +89,8 @@ template<u32 size> auto V30MZ::instructionGroup4MemImm() -> void {
case 6: //PUSH
push(getMemory<Word>());
break;
case 7: //PUSH (undocumented mirror)
push(getMemory<Word>());
case 7: //undefined opcode
wait(1);
break;
}
}
@@ -21,11 +21,11 @@ auto V30MZ::instructionLock() -> void {
}
auto V30MZ::instructionWait() -> void {
wait(1);
wait(10);
}
auto V30MZ::instructionHalt() -> void {
wait(8);
wait(9);
state.halt = 1;
}
@@ -33,6 +33,15 @@ auto V30MZ::instructionNop() -> void {
wait(1);
}
auto V30MZ::instructionUndefined() -> void {
wait(1);
}
auto V30MZ::instructionUndefined1() -> void {
wait(1);
fetch<Byte>();
}
template<u32 size> auto V30MZ::instructionIn() -> void {
wait(6);
setAccumulator<size>(in<size>(fetch<Byte>()));
@@ -44,17 +53,22 @@ template<u32 size> auto V30MZ::instructionOut() -> void {
}
template<u32 size> auto V30MZ::instructionInDW() -> void {
wait(4);
wait(5);
setAccumulator<size>(in<size>(DW));
}
template<u32 size> auto V30MZ::instructionOutDW() -> void {
wait(4);
wait(5);
out<size>(DW, getAccumulator<size>());
}
auto V30MZ::instructionTranslate(u8 clocks) -> void {
wait(clocks);
auto V30MZ::instructionSetALCarry() -> void {
wait(8);
AL = PSW.CY ? 0xFF : 0x00;
}
auto V30MZ::instructionTranslate() -> void {
wait(4);
AL = read<Byte>(segment(DS0), BW + AL);
}
@@ -64,5 +78,5 @@ auto V30MZ::instructionBound() -> void {
auto lo = getMemory<Word>(0);
auto hi = getMemory<Word>(2);
auto reg = getRegister<Word>();
if(reg < lo || reg > hi) interrupt(5);
if(reg < lo || reg > hi) interrupt(5, InterruptSource::CPU);
}
@@ -1,5 +1,5 @@
template<u32 size> auto V30MZ::instructionInString() -> void {
wait(5);
wait(3);
if(!repeat() || CW) {
auto data = in<size>(DW);
write<size>(DS1, IY, data);
@@ -14,7 +14,7 @@ template<u32 size> auto V30MZ::instructionInString() -> void {
}
template<u32 size> auto V30MZ::instructionOutString() -> void {
wait(6);
wait(3);
if(!repeat() || CW) {
auto data = read<size>(segment(DS0), IX);
out<size>(DW, data);
+14 -7
View File
@@ -1,36 +1,41 @@
template<> auto V30MZ::read<Byte>(u16 segment, u16 address) -> u32 {
step(1);
step(speed(segment * 16 + address));
u32 data = 0;
data |= read(segment * 16 + address++) << 0;
return data;
}
template<> auto V30MZ::read<Word>(u16 segment, u16 address) -> u32 {
step(1 + (address & 1));
u32 data = 0;
step(speed(segment * 16 + address));
data |= read(segment * 16 + address++) << 0;
if(width(address) == Byte || !(address & 1)) step(speed(segment * 16 + address));
data |= read(segment * 16 + address++) << 8;
return data;
}
template<> auto V30MZ::read<Long>(u16 segment, u16 address) -> u32 {
step(2 + (address & 1));
u32 data = 0;
step(speed(segment * 16 + address));
data |= read(segment * 16 + address++) << 0;
if(width(address) == Byte || !(address & 1)) step(speed(segment * 16 + address));
data |= read(segment * 16 + address++) << 8;
if(width(address) == Byte || !(address & 1)) step(speed(segment * 16 + address));
data |= read(segment * 16 + address++) << 16;
if(width(address) == Byte || !(address & 1)) step(speed(segment * 16 + address));
data |= read(segment * 16 + address++) << 24;
return data;
}
template<> auto V30MZ::write<Byte>(u16 segment, u16 address, u16 data) -> void {
step(1);
step(speed(segment * 16 + address));
write(segment * 16 + address++, data >> 0);
}
template<> auto V30MZ::write<Word>(u16 segment, u16 address, u16 data) -> void {
step(1 + (address & 1));
step(speed(segment * 16 + address));
write(segment * 16 + address++, data >> 0);
if(width(address) == Byte || !(address & 1)) step(speed(segment * 16 + address));
write(segment * 16 + address++, data >> 8);
}
@@ -42,9 +47,10 @@ template<> auto V30MZ::in<Byte>(u16 address) -> u16 {
}
template<> auto V30MZ::in<Word>(u16 address) -> u16 {
step(1 + (address & 1));
u16 data = 0;
step(1);
data |= in(address++) << 0;
if(!(address & 1)) step(1);
data |= in(address++) << 8;
return data;
}
@@ -55,8 +61,9 @@ template<> auto V30MZ::out<Byte>(u16 address, u16 data) -> void {
}
template<> auto V30MZ::out<Word>(u16 address, u16 data) -> void {
step(1 + (address & 1));
step(1);
out(address++, data >> 0);
if(!(address & 1)) step(1);
out(address++, data >> 8);
}
+5 -4
View File
@@ -4,15 +4,16 @@ auto V30MZ::modRM() -> void {
modrm.reg = data >> 3 & 7;
modrm.mod = data >> 6 & 3;
if(modrm.mod == 3) return;
if(modrm.mod == 0 && modrm.mem == 6) {
modrm.segment = segment(DS0);
modrm.address = fetch<Word>();
} else {
switch(modrm.mem) {
case 0: modrm.segment = segment(DS0); modrm.address = BW + IX; break;
case 1: modrm.segment = segment(DS0); modrm.address = BW + IY; break;
case 2: modrm.segment = segment(SS ); modrm.address = BP + IX; break;
case 3: modrm.segment = segment(SS ); modrm.address = BP + IY; break;
case 0: modrm.segment = segment(DS0); modrm.address = BW + IX; wait(1); break;
case 1: modrm.segment = segment(DS0); modrm.address = BW + IY; wait(1); break;
case 2: modrm.segment = segment(SS ); modrm.address = BP + IX; wait(1); break;
case 3: modrm.segment = segment(SS ); modrm.address = BP + IY; wait(1); break;
case 4: modrm.segment = segment(DS0); modrm.address = IX; break;
case 5: modrm.segment = segment(DS0); modrm.address = IY; break;
case 6: modrm.segment = segment(SS ); modrm.address = BP; break;
+13 -8
View File
@@ -15,25 +15,30 @@ auto V30MZ::loop() -> void {
auto V30MZ::flush() -> void {
PF.flush();
PFP = PC;
if(PFP & 1) step(1);
PFW = 0;
}
auto V30MZ::prefetch() -> void {
step(1);
switch(PFP & 1) {
case 0: if(PF.full()) break; PF.write(read(PS * 16 + PFP++)); //fallthrough
case 1: if(PF.full()) break; PF.write(read(PS * 16 + PFP++));
}
auto address = PS * 16 + PFP;
auto size = width(address);
auto wait = speed(address);
if(++PFW < wait) return;
PFW -= wait;
if(size == Word && !(PFP & 1)) if(!PF.full()) PF.write(read(PS * 16 + PFP++));
if(!PF.full()) PF.write(read(PS * 16 + PFP++));
}
template<> auto V30MZ::fetch<Byte>() -> u16 {
PC++;
if(PF.empty()) prefetch();
while(PF.size() < 2) prefetch();
return PF.read(0);
}
template<> auto V30MZ::fetch<Word>() -> u16 {
u8 lo = fetch<Byte>();
u8 hi = fetch<Byte>();
PC += 2;
while(PF.size() < 2) prefetch();
u8 lo = PF.read(0);
u8 hi = PF.read(0);
return lo << 0 | hi << 8;
}
+30 -39
View File
@@ -1,45 +1,14 @@
//NEC V30MZ (reduced functionality NEC V30 for embedded use)
//NEC V30MZ (optimized and more 80186-compatible NEC V30)
//V30 missing instructions:
// 0f 10,11,18,19 test1
// 0f 12,13,1a,1b clr1
// 0f 14,15,1c,1d set1
// 0f 16,17,1e,1f not1
// 0f 20 add4s
// 0f 22 sub4s
// 0f 26 cmp4s
// 0f 28 rol4
// 0f 2a ror4
// 0f 31,39 ins
// 0f 33,3b ext
// 0f ff brkem (8080 emulation mode) [retem, calln]
// 64 repnc
// 65 repc
// 66,67 fpo2
// d8-df fpo1
//x86 variant instructions:
// 8f c0-c7 pop reg [CPU bug: pops from stack; fails to set register]
// d4 xx aam [ignores the immediate; always uses (base) 10]
// d5 xx aad [ignores the immediate; always uses (base) 10]
// d6 xlat (mirror of d7) [this is salc on x86 CPUs]
// f1 ??? [this is int 0x1 on x86 CPUs; said to be a two-byte NOP on V20; unknown on V30/V30MZ]
// ff f8-ff push (mirror of ff f0-f7)
//does not contain V20/V30 extended instructions
//x86 unemulated variation:
// after interrupts, NEC V20/V30 CPUs resume string instructions with prefixes intact. unlike x86 CPUs
// I need more information on this behavior in order to emulate it ...
// also, the opcode f1 behavior is not currently known
//V30 opcode prefix functionality:
//V30MZ opcode prefix functionality:
// there is a seven-level stack for opcode prefixes. once full, older prefixes are pushed off the stack
//other notes:
// 0f pop cs (not nop) [on the V20; the V30 uses this for instruction extensions; unsure on the V30MZ]
// 8e xx mov cs,modRM (works as expected; able to set CS)
//I currently emulate opcode 0f as pop cs, although it's unknown if that is correct.
#pragma once
namespace ares {
@@ -57,6 +26,8 @@ struct V30MZ {
};
virtual auto step(u32 clocks = 1) -> void = 0;
virtual auto width(n20 address) -> u32 = 0;
virtual auto speed(n20 address) -> n32 = 0;
virtual auto read(n20 address) -> n8 = 0;
virtual auto write(n20 address, n8 data) -> void = 0;
virtual auto in(n16 port) -> n8 = 0;
@@ -66,7 +37,8 @@ struct V30MZ {
auto power() -> void;
//instruction.cpp
auto interrupt(u8 vector) -> void;
auto interrupt(u8 vector) -> bool;
auto nonMaskableInterrupt() -> bool;
auto instruction() -> void;
//registers.cpp
@@ -121,9 +93,8 @@ struct V30MZ {
template<u32> auto OR (u16, u16) -> u16;
template<u32> auto RCL (u16, u5 ) -> u16;
template<u32> auto RCR (u16, u5 ) -> u16;
template<u32> auto ROL (u16, u4 ) -> u16;
template<u32> auto ROR (u16, u4 ) -> u16;
template<u32> auto SAL (u16, u5 ) -> u16;
template<u32> auto ROL (u16, u5 ) -> u16;
template<u32> auto ROR (u16, u5 ) -> u16;
template<u32> auto SAR (u16, u5 ) -> u16;
template<u32> auto SBB (u16, u16) -> u16;
template<u32> auto SUB (u16, u16) -> u16;
@@ -220,11 +191,14 @@ struct V30MZ {
auto instructionWait() -> void;
auto instructionHalt() -> void;
auto instructionNop() -> void;
auto instructionUndefined() -> void;
auto instructionUndefined1() -> void;
template<u32> auto instructionIn() -> void;
template<u32> auto instructionOut() -> void;
template<u32> auto instructionInDW() -> void;
template<u32> auto instructionOutDW() -> void;
auto instructionTranslate(u8) -> void;
auto instructionTranslate() -> void;
auto instructionSetALCarry() -> void;
auto instructionBound() -> void;
//instructions-move.cpp
@@ -292,6 +266,7 @@ struct V30MZ {
u16 PC; //IP
u16 PFP; //prefetch pointer
queue<u8[16]> PF; //prefetch queue
n8 PFW; //prefetch wait time
struct ProgramStatusWord {
u16 data;
@@ -316,6 +291,22 @@ struct V30MZ {
u8* const RB[8]{&AL, &CL, &DL, &BL, &AH, &CH, &DH, &BH };
u16* const RW[8]{&AW, &CW, &DW, &BW, &SP, &BP, &IX, &IY };
u16* const RS[8]{&DS1, &PS, &SS, &DS0, &DS1, &PS, &SS, &DS0};
protected:
// TODO: implement interrupt priorities
enum class InterruptSource : u32 {
CPU = 1, // internal request
NMI = 2, // external NMI
INT = 3, // external interrupt request
SingleStep = 4 // internal request - single step
};
// algorithms.cpp
template<u32> auto ADD (u16, u16, u16) -> u16;
template<u32> auto SUB (u16, u16, u16) -> u16;
// instruction.cpp
auto interrupt(u8 vector, InterruptSource source) -> bool;
};
}
+145 -140
View File
@@ -17,9 +17,10 @@ auto Z80::instruction() -> void {
if(code == 0xcb && prefix != Prefix::hl) {
WZ = HL + (i8)operand();
wait(2); //+1 fetch, +1 memory read
n8 opcd = operand(); // pseudo opcode fetch (3 cycles)
wait(2);
//R is not incremented here
instructionCBd(WZ, opcode());
instructionCBd(WZ, opcd);
} else if(code == 0xcb) {
R.bit(0,6)++;
instructionCB(opcode());
@@ -242,7 +243,7 @@ auto Z80::instruction(n8 code) -> void {
op(0xca, JP_c_nn, ZF == 1)
//op(0xcb, cb:)
op(0xcc, CALL_c_nn, ZF == 1)
op(0xcd, CALL_nn)
op(0xcd, CALL_c_nn, true)
op(0xce, ADC_a_n)
op(0xcf, RST_o, 1)
op(0xd0, RET_c, CF == 0)
@@ -297,6 +298,8 @@ auto Z80::instruction(n8 code) -> void {
}
auto Z80::instructionCB(n8 code) -> void {
n8 _;
switch(code) {
op(0x00, RLC_r, B)
op(0x01, RLC_r, C)
@@ -304,7 +307,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x03, RLC_r, E)
op(0x04, RLC_r, H)
op(0x05, RLC_r, L)
op(0x06, RLC_irr, _HL)
op(0x06, RLC_irr_r, _HL, _)
op(0x07, RLC_r, A)
op(0x08, RRC_r, B)
op(0x09, RRC_r, C)
@@ -312,7 +315,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x0b, RRC_r, E)
op(0x0c, RRC_r, H)
op(0x0d, RRC_r, L)
op(0x0e, RRC_irr, _HL)
op(0x0e, RRC_irr_r, _HL, _)
op(0x0f, RRC_r, A)
op(0x10, RL_r, B)
op(0x11, RL_r, C)
@@ -320,7 +323,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x13, RL_r, E)
op(0x14, RL_r, H)
op(0x15, RL_r, L)
op(0x16, RL_irr, _HL)
op(0x16, RL_irr_r, _HL, _)
op(0x17, RL_r, A)
op(0x18, RR_r, B)
op(0x19, RR_r, C)
@@ -328,7 +331,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x1b, RR_r, E)
op(0x1c, RR_r, H)
op(0x1d, RR_r, L)
op(0x1e, RR_irr, _HL)
op(0x1e, RR_irr_r, _HL, _)
op(0x1f, RR_r, A)
op(0x20, SLA_r, B)
op(0x21, SLA_r, C)
@@ -336,7 +339,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x23, SLA_r, E)
op(0x24, SLA_r, H)
op(0x25, SLA_r, L)
op(0x26, SLA_irr, _HL)
op(0x26, SLA_irr_r, _HL, _)
op(0x27, SLA_r, A)
op(0x28, SRA_r, B)
op(0x29, SRA_r, C)
@@ -344,7 +347,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x2b, SRA_r, E)
op(0x2c, SRA_r, H)
op(0x2d, SRA_r, L)
op(0x2e, SRA_irr, _HL)
op(0x2e, SRA_irr_r, _HL, _)
op(0x2f, SRA_r, A)
op(0x30, SLL_r, B)
op(0x31, SLL_r, C)
@@ -352,7 +355,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x33, SLL_r, E)
op(0x34, SLL_r, H)
op(0x35, SLL_r, L)
op(0x36, SLL_irr, _HL)
op(0x36, SLL_irr_r, _HL, _)
op(0x37, SLL_r, A)
op(0x38, SRL_r, B)
op(0x39, SRL_r, C)
@@ -360,7 +363,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x3b, SRL_r, E)
op(0x3c, SRL_r, H)
op(0x3d, SRL_r, L)
op(0x3e, SRL_irr, _HL)
op(0x3e, SRL_irr_r, _HL, _)
op(0x3f, SRL_r, A)
op(0x40, BIT_o_r, 0, B)
op(0x41, BIT_o_r, 0, C)
@@ -368,7 +371,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x43, BIT_o_r, 0, E)
op(0x44, BIT_o_r, 0, H)
op(0x45, BIT_o_r, 0, L)
op(0x46, BIT_o_irr, 0, _HL)
op(0x46, BIT_o_irr_r, 0, _HL, _)
op(0x47, BIT_o_r, 0, A)
op(0x48, BIT_o_r, 1, B)
op(0x49, BIT_o_r, 1, C)
@@ -376,7 +379,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x4b, BIT_o_r, 1, E)
op(0x4c, BIT_o_r, 1, H)
op(0x4d, BIT_o_r, 1, L)
op(0x4e, BIT_o_irr, 1, _HL)
op(0x4e, BIT_o_irr_r, 1, _HL, _)
op(0x4f, BIT_o_r, 1, A)
op(0x50, BIT_o_r, 2, B)
op(0x51, BIT_o_r, 2, C)
@@ -384,7 +387,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x53, BIT_o_r, 2, E)
op(0x54, BIT_o_r, 2, H)
op(0x55, BIT_o_r, 2, L)
op(0x56, BIT_o_irr, 2, _HL)
op(0x56, BIT_o_irr_r, 2, _HL, _)
op(0x57, BIT_o_r, 2, A)
op(0x58, BIT_o_r, 3, B)
op(0x59, BIT_o_r, 3, C)
@@ -392,7 +395,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x5b, BIT_o_r, 3, E)
op(0x5c, BIT_o_r, 3, H)
op(0x5d, BIT_o_r, 3, L)
op(0x5e, BIT_o_irr, 3, _HL)
op(0x5e, BIT_o_irr_r, 3, _HL, _)
op(0x5f, BIT_o_r, 3, A)
op(0x60, BIT_o_r, 4, B)
op(0x61, BIT_o_r, 4, C)
@@ -400,7 +403,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x63, BIT_o_r, 4, E)
op(0x64, BIT_o_r, 4, H)
op(0x65, BIT_o_r, 4, L)
op(0x66, BIT_o_irr, 4, _HL)
op(0x66, BIT_o_irr_r, 4, _HL, _)
op(0x67, BIT_o_r, 4, A)
op(0x68, BIT_o_r, 5, B)
op(0x69, BIT_o_r, 5, C)
@@ -408,7 +411,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x6b, BIT_o_r, 5, E)
op(0x6c, BIT_o_r, 5, H)
op(0x6d, BIT_o_r, 5, L)
op(0x6e, BIT_o_irr, 5, _HL)
op(0x6e, BIT_o_irr_r, 5, _HL, _)
op(0x6f, BIT_o_r, 5, A)
op(0x70, BIT_o_r, 6, B)
op(0x71, BIT_o_r, 6, C)
@@ -416,7 +419,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x73, BIT_o_r, 6, E)
op(0x74, BIT_o_r, 6, H)
op(0x75, BIT_o_r, 6, L)
op(0x76, BIT_o_irr, 6, _HL)
op(0x76, BIT_o_irr_r, 6, _HL, _)
op(0x77, BIT_o_r, 6, A)
op(0x78, BIT_o_r, 7, B)
op(0x79, BIT_o_r, 7, C)
@@ -424,7 +427,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x7b, BIT_o_r, 7, E)
op(0x7c, BIT_o_r, 7, H)
op(0x7d, BIT_o_r, 7, L)
op(0x7e, BIT_o_irr, 7, _HL)
op(0x7e, BIT_o_irr_r, 7, _HL, _)
op(0x7f, BIT_o_r, 7, A)
op(0x80, RES_o_r, 0, B)
op(0x81, RES_o_r, 0, C)
@@ -432,7 +435,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x83, RES_o_r, 0, E)
op(0x84, RES_o_r, 0, H)
op(0x85, RES_o_r, 0, L)
op(0x86, RES_o_irr, 0, _HL)
op(0x86, RES_o_irr_r, 0, _HL, _)
op(0x87, RES_o_r, 0, A)
op(0x88, RES_o_r, 1, B)
op(0x89, RES_o_r, 1, C)
@@ -440,7 +443,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x8b, RES_o_r, 1, E)
op(0x8c, RES_o_r, 1, H)
op(0x8d, RES_o_r, 1, L)
op(0x8e, RES_o_irr, 1, _HL)
op(0x8e, RES_o_irr_r, 1, _HL, _)
op(0x8f, RES_o_r, 1, A)
op(0x90, RES_o_r, 2, B)
op(0x91, RES_o_r, 2, C)
@@ -448,7 +451,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x93, RES_o_r, 2, E)
op(0x94, RES_o_r, 2, H)
op(0x95, RES_o_r, 2, L)
op(0x96, RES_o_irr, 2, _HL)
op(0x96, RES_o_irr_r, 2, _HL, _)
op(0x97, RES_o_r, 2, A)
op(0x98, RES_o_r, 3, B)
op(0x99, RES_o_r, 3, C)
@@ -456,7 +459,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0x9b, RES_o_r, 3, E)
op(0x9c, RES_o_r, 3, H)
op(0x9d, RES_o_r, 3, L)
op(0x9e, RES_o_irr, 3, _HL)
op(0x9e, RES_o_irr_r, 3, _HL, _)
op(0x9f, RES_o_r, 3, A)
op(0xa0, RES_o_r, 4, B)
op(0xa1, RES_o_r, 4, C)
@@ -464,7 +467,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xa3, RES_o_r, 4, E)
op(0xa4, RES_o_r, 4, H)
op(0xa5, RES_o_r, 4, L)
op(0xa6, RES_o_irr, 4, _HL)
op(0xa6, RES_o_irr_r, 4, _HL, _)
op(0xa7, RES_o_r, 4, A)
op(0xa8, RES_o_r, 5, B)
op(0xa9, RES_o_r, 5, C)
@@ -472,7 +475,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xab, RES_o_r, 5, E)
op(0xac, RES_o_r, 5, H)
op(0xad, RES_o_r, 5, L)
op(0xae, RES_o_irr, 5, _HL)
op(0xae, RES_o_irr_r, 5, _HL, _)
op(0xaf, RES_o_r, 5, A)
op(0xb0, RES_o_r, 6, B)
op(0xb1, RES_o_r, 6, C)
@@ -480,7 +483,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xb3, RES_o_r, 6, E)
op(0xb4, RES_o_r, 6, H)
op(0xb5, RES_o_r, 6, L)
op(0xb6, RES_o_irr, 6, _HL)
op(0xb6, RES_o_irr_r, 6, _HL, _)
op(0xb7, RES_o_r, 6, A)
op(0xb8, RES_o_r, 7, B)
op(0xb9, RES_o_r, 7, C)
@@ -488,7 +491,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xbb, RES_o_r, 7, E)
op(0xbc, RES_o_r, 7, H)
op(0xbd, RES_o_r, 7, L)
op(0xbe, RES_o_irr, 7, _HL)
op(0xbe, RES_o_irr_r, 7, _HL, _)
op(0xbf, RES_o_r, 7, A)
op(0xc0, SET_o_r, 0, B)
op(0xc1, SET_o_r, 0, C)
@@ -496,7 +499,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xc3, SET_o_r, 0, E)
op(0xc4, SET_o_r, 0, H)
op(0xc5, SET_o_r, 0, L)
op(0xc6, SET_o_irr, 0, _HL)
op(0xc6, SET_o_irr_r, 0, _HL, _)
op(0xc7, SET_o_r, 0, A)
op(0xc8, SET_o_r, 1, B)
op(0xc9, SET_o_r, 1, C)
@@ -504,7 +507,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xcb, SET_o_r, 1, E)
op(0xcc, SET_o_r, 1, H)
op(0xcd, SET_o_r, 1, L)
op(0xce, SET_o_irr, 1, _HL)
op(0xce, SET_o_irr_r, 1, _HL, _)
op(0xcf, SET_o_r, 1, A)
op(0xd0, SET_o_r, 2, B)
op(0xd1, SET_o_r, 2, C)
@@ -512,7 +515,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xd3, SET_o_r, 2, E)
op(0xd4, SET_o_r, 2, H)
op(0xd5, SET_o_r, 2, L)
op(0xd6, SET_o_irr, 2, _HL)
op(0xd6, SET_o_irr_r, 2, _HL, _)
op(0xd7, SET_o_r, 2, A)
op(0xd8, SET_o_r, 3, B)
op(0xd9, SET_o_r, 3, C)
@@ -520,7 +523,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xdb, SET_o_r, 3, E)
op(0xdc, SET_o_r, 3, H)
op(0xdd, SET_o_r, 3, L)
op(0xde, SET_o_irr, 3, _HL)
op(0xde, SET_o_irr_r, 3, _HL, _)
op(0xdf, SET_o_r, 3, A)
op(0xe0, SET_o_r, 4, B)
op(0xe1, SET_o_r, 4, C)
@@ -528,7 +531,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xe3, SET_o_r, 4, E)
op(0xe4, SET_o_r, 4, H)
op(0xe5, SET_o_r, 4, L)
op(0xe6, SET_o_irr, 4, _HL)
op(0xe6, SET_o_irr_r, 4, _HL, _)
op(0xe7, SET_o_r, 4, A)
op(0xe8, SET_o_r, 5, B)
op(0xe9, SET_o_r, 5, C)
@@ -536,7 +539,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xeb, SET_o_r, 5, E)
op(0xec, SET_o_r, 5, H)
op(0xed, SET_o_r, 5, L)
op(0xee, SET_o_irr, 5, _HL)
op(0xee, SET_o_irr_r, 5, _HL, _)
op(0xef, SET_o_r, 5, A)
op(0xf0, SET_o_r, 6, B)
op(0xf1, SET_o_r, 6, C)
@@ -544,7 +547,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xf3, SET_o_r, 6, E)
op(0xf4, SET_o_r, 6, H)
op(0xf5, SET_o_r, 6, L)
op(0xf6, SET_o_irr, 6, _HL)
op(0xf6, SET_o_irr_r, 6, _HL, _)
op(0xf7, SET_o_r, 6, A)
op(0xf8, SET_o_r, 7, B)
op(0xf9, SET_o_r, 7, C)
@@ -552,7 +555,7 @@ auto Z80::instructionCB(n8 code) -> void {
op(0xfb, SET_o_r, 7, E)
op(0xfc, SET_o_r, 7, H)
op(0xfd, SET_o_r, 7, L)
op(0xfe, SET_o_irr, 7, _HL)
op(0xfe, SET_o_irr_r, 7, _HL, _)
op(0xff, SET_o_r, 7, A)
}
}
@@ -565,262 +568,264 @@ auto Z80::instructionCBd(n16 addr, n8 code) -> void {
op(0x01, RLC_irr_r, addr, C)
op(0x02, RLC_irr_r, addr, D)
op(0x03, RLC_irr_r, addr, E)
op(0x04, RLC_irr_r, addr, H)
op(0x05, RLC_irr_r, addr, L)
op(0x04, RLC_irr_r, addr, _H)
op(0x05, RLC_irr_r, addr, _L)
op(0x06, RLC_irr_r, addr, _)
op(0x07, RLC_irr_r, addr, A)
op(0x08, RRC_irr_r, addr, B)
op(0x09, RRC_irr_r, addr, C)
op(0x0a, RRC_irr_r, addr, D)
op(0x0b, RRC_irr_r, addr, E)
op(0x0c, RRC_irr_r, addr, H)
op(0x0d, RRC_irr_r, addr, L)
op(0x0c, RRC_irr_r, addr, _H)
op(0x0d, RRC_irr_r, addr, _L)
op(0x0e, RRC_irr_r, addr, _)
op(0x0f, RRC_irr_r, addr, A)
op(0x10, RL_irr_r, addr, B)
op(0x11, RL_irr_r, addr, C)
op(0x12, RL_irr_r, addr, D)
op(0x13, RL_irr_r, addr, E)
op(0x14, RL_irr_r, addr, H)
op(0x15, RL_irr_r, addr, L)
op(0x14, RL_irr_r, addr, _H)
op(0x15, RL_irr_r, addr, _L)
op(0x16, RL_irr_r, addr, _)
op(0x17, RL_irr_r, addr, A)
op(0x18, RR_irr_r, addr, B)
op(0x19, RR_irr_r, addr, C)
op(0x1a, RR_irr_r, addr, D)
op(0x1b, RR_irr_r, addr, E)
op(0x1c, RR_irr_r, addr, H)
op(0x1d, RR_irr_r, addr, L)
op(0x1c, RR_irr_r, addr, _H)
op(0x1d, RR_irr_r, addr, _L)
op(0x1e, RR_irr_r, addr, _)
op(0x1f, RR_irr_r, addr, A)
op(0x20, SLA_irr_r, addr, B)
op(0x21, SLA_irr_r, addr, C)
op(0x22, SLA_irr_r, addr, D)
op(0x23, SLA_irr_r, addr, E)
op(0x24, SLA_irr_r, addr, H)
op(0x25, SLA_irr_r, addr, L)
op(0x24, SLA_irr_r, addr, _H)
op(0x25, SLA_irr_r, addr, _L)
op(0x26, SLA_irr_r, addr, _)
op(0x27, SLA_irr_r, addr, A)
op(0x28, SRA_irr_r, addr, B)
op(0x29, SRA_irr_r, addr, C)
op(0x2a, SRA_irr_r, addr, D)
op(0x2b, SRA_irr_r, addr, E)
op(0x2c, SRA_irr_r, addr, H)
op(0x2d, SRA_irr_r, addr, L)
op(0x2c, SRA_irr_r, addr, _H)
op(0x2d, SRA_irr_r, addr, _L)
op(0x2e, SRA_irr_r, addr, _)
op(0x2f, SRA_irr_r, addr, A)
op(0x30, SLL_irr_r, addr, B)
op(0x31, SLL_irr_r, addr, C)
op(0x32, SLL_irr_r, addr, D)
op(0x33, SLL_irr_r, addr, E)
op(0x34, SLL_irr_r, addr, H)
op(0x35, SLL_irr_r, addr, L)
op(0x34, SLL_irr_r, addr, _H)
op(0x35, SLL_irr_r, addr, _L)
op(0x36, SLL_irr_r, addr, _)
op(0x37, SLL_irr_r, addr, A)
op(0x38, SRL_irr_r, addr, B)
op(0x39, SRL_irr_r, addr, C)
op(0x3a, SRL_irr_r, addr, D)
op(0x3b, SRL_irr_r, addr, E)
op(0x3c, SRL_irr_r, addr, H)
op(0x3d, SRL_irr_r, addr, L)
op(0x3c, SRL_irr_r, addr, _H)
op(0x3d, SRL_irr_r, addr, _L)
op(0x3e, SRL_irr_r, addr, _)
op(0x3f, SRL_irr_r, addr, A)
op(0x40, BIT_o_irr_r, 0, addr, B)
op(0x41, BIT_o_irr_r, 0, addr, C)
op(0x42, BIT_o_irr_r, 0, addr, D)
op(0x43, BIT_o_irr_r, 0, addr, E)
op(0x44, BIT_o_irr_r, 0, addr, H)
op(0x45, BIT_o_irr_r, 0, addr, L)
op(0x40, BIT_o_irr_r, 0, addr, _)
op(0x41, BIT_o_irr_r, 0, addr, _)
op(0x42, BIT_o_irr_r, 0, addr, _)
op(0x43, BIT_o_irr_r, 0, addr, _)
op(0x44, BIT_o_irr_r, 0, addr, _)
op(0x45, BIT_o_irr_r, 0, addr, _)
op(0x46, BIT_o_irr_r, 0, addr, _)
op(0x47, BIT_o_irr_r, 0, addr, A)
op(0x48, BIT_o_irr_r, 1, addr, B)
op(0x49, BIT_o_irr_r, 1, addr, C)
op(0x4a, BIT_o_irr_r, 1, addr, D)
op(0x4b, BIT_o_irr_r, 1, addr, E)
op(0x4c, BIT_o_irr_r, 1, addr, H)
op(0x4d, BIT_o_irr_r, 1, addr, L)
op(0x47, BIT_o_irr_r, 0, addr, _)
op(0x48, BIT_o_irr_r, 1, addr, _)
op(0x49, BIT_o_irr_r, 1, addr, _)
op(0x4a, BIT_o_irr_r, 1, addr, _)
op(0x4b, BIT_o_irr_r, 1, addr, _)
op(0x4c, BIT_o_irr_r, 1, addr, _)
op(0x4d, BIT_o_irr_r, 1, addr, _)
op(0x4e, BIT_o_irr_r, 1, addr, _)
op(0x4f, BIT_o_irr_r, 1, addr, A)
op(0x50, BIT_o_irr_r, 2, addr, B)
op(0x51, BIT_o_irr_r, 2, addr, C)
op(0x52, BIT_o_irr_r, 2, addr, D)
op(0x53, BIT_o_irr_r, 2, addr, E)
op(0x54, BIT_o_irr_r, 2, addr, H)
op(0x55, BIT_o_irr_r, 2, addr, L)
op(0x4f, BIT_o_irr_r, 1, addr, _)
op(0x50, BIT_o_irr_r, 2, addr, _)
op(0x51, BIT_o_irr_r, 2, addr, _)
op(0x52, BIT_o_irr_r, 2, addr, _)
op(0x53, BIT_o_irr_r, 2, addr, _)
op(0x54, BIT_o_irr_r, 2, addr, _)
op(0x55, BIT_o_irr_r, 2, addr, _)
op(0x56, BIT_o_irr_r, 2, addr, _)
op(0x57, BIT_o_irr_r, 2, addr, A)
op(0x58, BIT_o_irr_r, 3, addr, B)
op(0x59, BIT_o_irr_r, 3, addr, C)
op(0x5a, BIT_o_irr_r, 3, addr, D)
op(0x5b, BIT_o_irr_r, 3, addr, E)
op(0x5c, BIT_o_irr_r, 3, addr, H)
op(0x5d, BIT_o_irr_r, 3, addr, L)
op(0x57, BIT_o_irr_r, 2, addr, _)
op(0x58, BIT_o_irr_r, 3, addr, _)
op(0x59, BIT_o_irr_r, 3, addr, _)
op(0x5a, BIT_o_irr_r, 3, addr, _)
op(0x5b, BIT_o_irr_r, 3, addr, _)
op(0x5c, BIT_o_irr_r, 3, addr, _)
op(0x5d, BIT_o_irr_r, 3, addr, _)
op(0x5e, BIT_o_irr_r, 3, addr, _)
op(0x5f, BIT_o_irr_r, 3, addr, A)
op(0x60, BIT_o_irr_r, 4, addr, B)
op(0x61, BIT_o_irr_r, 4, addr, C)
op(0x62, BIT_o_irr_r, 4, addr, D)
op(0x63, BIT_o_irr_r, 4, addr, E)
op(0x64, BIT_o_irr_r, 4, addr, H)
op(0x65, BIT_o_irr_r, 4, addr, L)
op(0x5f, BIT_o_irr_r, 3, addr, _)
op(0x60, BIT_o_irr_r, 4, addr, _)
op(0x61, BIT_o_irr_r, 4, addr, _)
op(0x62, BIT_o_irr_r, 4, addr, _)
op(0x63, BIT_o_irr_r, 4, addr, _)
op(0x64, BIT_o_irr_r, 4, addr, _)
op(0x65, BIT_o_irr_r, 4, addr, _)
op(0x66, BIT_o_irr_r, 4, addr, _)
op(0x67, BIT_o_irr_r, 4, addr, A)
op(0x68, BIT_o_irr_r, 5, addr, B)
op(0x69, BIT_o_irr_r, 5, addr, C)
op(0x6a, BIT_o_irr_r, 5, addr, D)
op(0x6b, BIT_o_irr_r, 5, addr, E)
op(0x6c, BIT_o_irr_r, 5, addr, H)
op(0x6d, BIT_o_irr_r, 5, addr, L)
op(0x67, BIT_o_irr_r, 4, addr, _)
op(0x68, BIT_o_irr_r, 5, addr, _)
op(0x69, BIT_o_irr_r, 5, addr, _)
op(0x6a, BIT_o_irr_r, 5, addr, _)
op(0x6b, BIT_o_irr_r, 5, addr, _)
op(0x6c, BIT_o_irr_r, 5, addr, _)
op(0x6d, BIT_o_irr_r, 5, addr, _)
op(0x6e, BIT_o_irr_r, 5, addr, _)
op(0x6f, BIT_o_irr_r, 5, addr, A)
op(0x70, BIT_o_irr_r, 6, addr, B)
op(0x71, BIT_o_irr_r, 6, addr, C)
op(0x72, BIT_o_irr_r, 6, addr, D)
op(0x73, BIT_o_irr_r, 6, addr, E)
op(0x74, BIT_o_irr_r, 6, addr, H)
op(0x75, BIT_o_irr_r, 6, addr, L)
op(0x6f, BIT_o_irr_r, 5, addr, _)
op(0x70, BIT_o_irr_r, 6, addr, _)
op(0x71, BIT_o_irr_r, 6, addr, _)
op(0x72, BIT_o_irr_r, 6, addr, _)
op(0x73, BIT_o_irr_r, 6, addr, _)
op(0x74, BIT_o_irr_r, 6, addr, _)
op(0x75, BIT_o_irr_r, 6, addr, _)
op(0x76, BIT_o_irr_r, 6, addr, _)
op(0x77, BIT_o_irr_r, 6, addr, A)
op(0x78, BIT_o_irr_r, 7, addr, B)
op(0x79, BIT_o_irr_r, 7, addr, C)
op(0x7a, BIT_o_irr_r, 7, addr, D)
op(0x7b, BIT_o_irr_r, 7, addr, E)
op(0x7c, BIT_o_irr_r, 7, addr, H)
op(0x7d, BIT_o_irr_r, 7, addr, L)
op(0x77, BIT_o_irr_r, 6, addr, _)
op(0x78, BIT_o_irr_r, 7, addr, _)
op(0x79, BIT_o_irr_r, 7, addr, _)
op(0x7a, BIT_o_irr_r, 7, addr, _)
op(0x7b, BIT_o_irr_r, 7, addr, _)
op(0x7c, BIT_o_irr_r, 7, addr, _)
op(0x7d, BIT_o_irr_r, 7, addr, _)
op(0x7e, BIT_o_irr_r, 7, addr, _)
op(0x7f, BIT_o_irr_r, 7, addr, A)
op(0x7f, BIT_o_irr_r, 7, addr, _)
op(0x80, RES_o_irr_r, 0, addr, B)
op(0x81, RES_o_irr_r, 0, addr, C)
op(0x82, RES_o_irr_r, 0, addr, D)
op(0x83, RES_o_irr_r, 0, addr, E)
op(0x84, RES_o_irr_r, 0, addr, H)
op(0x85, RES_o_irr_r, 0, addr, L)
op(0x84, RES_o_irr_r, 0, addr, _H)
op(0x85, RES_o_irr_r, 0, addr, _L)
op(0x86, RES_o_irr_r, 0, addr, _)
op(0x87, RES_o_irr_r, 0, addr, A)
op(0x88, RES_o_irr_r, 1, addr, B)
op(0x89, RES_o_irr_r, 1, addr, C)
op(0x8a, RES_o_irr_r, 1, addr, D)
op(0x8b, RES_o_irr_r, 1, addr, E)
op(0x8c, RES_o_irr_r, 1, addr, H)
op(0x8d, RES_o_irr_r, 1, addr, L)
op(0x8c, RES_o_irr_r, 1, addr, _H)
op(0x8d, RES_o_irr_r, 1, addr, _L)
op(0x8e, RES_o_irr_r, 1, addr, _)
op(0x8f, RES_o_irr_r, 1, addr, A)
op(0x90, RES_o_irr_r, 2, addr, B)
op(0x91, RES_o_irr_r, 2, addr, C)
op(0x92, RES_o_irr_r, 2, addr, D)
op(0x93, RES_o_irr_r, 2, addr, E)
op(0x94, RES_o_irr_r, 2, addr, H)
op(0x95, RES_o_irr_r, 2, addr, L)
op(0x94, RES_o_irr_r, 2, addr, _H)
op(0x95, RES_o_irr_r, 2, addr, _L)
op(0x96, RES_o_irr_r, 2, addr, _)
op(0x97, RES_o_irr_r, 2, addr, A)
op(0x98, RES_o_irr_r, 3, addr, B)
op(0x99, RES_o_irr_r, 3, addr, C)
op(0x9a, RES_o_irr_r, 3, addr, D)
op(0x9b, RES_o_irr_r, 3, addr, E)
op(0x9c, RES_o_irr_r, 3, addr, H)
op(0x9d, RES_o_irr_r, 3, addr, L)
op(0x9c, RES_o_irr_r, 3, addr, _H)
op(0x9d, RES_o_irr_r, 3, addr, _L)
op(0x9e, RES_o_irr_r, 3, addr, _)
op(0x9f, RES_o_irr_r, 3, addr, A)
op(0xa0, RES_o_irr_r, 4, addr, B)
op(0xa1, RES_o_irr_r, 4, addr, C)
op(0xa2, RES_o_irr_r, 4, addr, D)
op(0xa3, RES_o_irr_r, 4, addr, E)
op(0xa4, RES_o_irr_r, 4, addr, H)
op(0xa5, RES_o_irr_r, 4, addr, L)
op(0xa4, RES_o_irr_r, 4, addr, _H)
op(0xa5, RES_o_irr_r, 4, addr, _L)
op(0xa6, RES_o_irr_r, 4, addr, _)
op(0xa7, RES_o_irr_r, 4, addr, A)
op(0xa8, RES_o_irr_r, 5, addr, B)
op(0xa9, RES_o_irr_r, 5, addr, C)
op(0xaa, RES_o_irr_r, 5, addr, D)
op(0xab, RES_o_irr_r, 5, addr, E)
op(0xac, RES_o_irr_r, 5, addr, H)
op(0xad, RES_o_irr_r, 5, addr, L)
op(0xac, RES_o_irr_r, 5, addr, _H)
op(0xad, RES_o_irr_r, 5, addr, _L)
op(0xae, RES_o_irr_r, 5, addr, _)
op(0xaf, RES_o_irr_r, 5, addr, A)
op(0xb0, RES_o_irr_r, 6, addr, B)
op(0xb1, RES_o_irr_r, 6, addr, C)
op(0xb2, RES_o_irr_r, 6, addr, D)
op(0xb3, RES_o_irr_r, 6, addr, E)
op(0xb4, RES_o_irr_r, 6, addr, H)
op(0xb5, RES_o_irr_r, 6, addr, L)
op(0xb4, RES_o_irr_r, 6, addr, _H)
op(0xb5, RES_o_irr_r, 6, addr, _L)
op(0xb6, RES_o_irr_r, 6, addr, _)
op(0xb7, RES_o_irr_r, 6, addr, A)
op(0xb8, RES_o_irr_r, 7, addr, B)
op(0xb9, RES_o_irr_r, 7, addr, C)
op(0xba, RES_o_irr_r, 7, addr, D)
op(0xbb, RES_o_irr_r, 7, addr, E)
op(0xbc, RES_o_irr_r, 7, addr, H)
op(0xbd, RES_o_irr_r, 7, addr, L)
op(0xbc, RES_o_irr_r, 7, addr, _H)
op(0xbd, RES_o_irr_r, 7, addr, _L)
op(0xbe, RES_o_irr_r, 7, addr, _)
op(0xbf, RES_o_irr_r, 7, addr, A)
op(0xc0, SET_o_irr_r, 0, addr, B)
op(0xc1, SET_o_irr_r, 0, addr, C)
op(0xc2, SET_o_irr_r, 0, addr, D)
op(0xc3, SET_o_irr_r, 0, addr, E)
op(0xc4, SET_o_irr_r, 0, addr, H)
op(0xc5, SET_o_irr_r, 0, addr, L)
op(0xc4, SET_o_irr_r, 0, addr, _H)
op(0xc5, SET_o_irr_r, 0, addr, _L)
op(0xc6, SET_o_irr_r, 0, addr, _)
op(0xc7, SET_o_irr_r, 0, addr, A)
op(0xc8, SET_o_irr_r, 1, addr, B)
op(0xc9, SET_o_irr_r, 1, addr, C)
op(0xca, SET_o_irr_r, 1, addr, D)
op(0xcb, SET_o_irr_r, 1, addr, E)
op(0xcc, SET_o_irr_r, 1, addr, H)
op(0xcd, SET_o_irr_r, 1, addr, L)
op(0xcc, SET_o_irr_r, 1, addr, _H)
op(0xcd, SET_o_irr_r, 1, addr, _L)
op(0xce, SET_o_irr_r, 1, addr, _)
op(0xcf, SET_o_irr_r, 1, addr, A)
op(0xd0, SET_o_irr_r, 2, addr, B)
op(0xd1, SET_o_irr_r, 2, addr, C)
op(0xd2, SET_o_irr_r, 2, addr, D)
op(0xd3, SET_o_irr_r, 2, addr, E)
op(0xd4, SET_o_irr_r, 2, addr, H)
op(0xd5, SET_o_irr_r, 2, addr, L)
op(0xd4, SET_o_irr_r, 2, addr, _H)
op(0xd5, SET_o_irr_r, 2, addr, _L)
op(0xd6, SET_o_irr_r, 2, addr, _)
op(0xd7, SET_o_irr_r, 2, addr, A)
op(0xd8, SET_o_irr_r, 3, addr, B)
op(0xd9, SET_o_irr_r, 3, addr, C)
op(0xda, SET_o_irr_r, 3, addr, D)
op(0xdb, SET_o_irr_r, 3, addr, E)
op(0xdc, SET_o_irr_r, 3, addr, H)
op(0xdd, SET_o_irr_r, 3, addr, L)
op(0xdc, SET_o_irr_r, 3, addr, _H)
op(0xdd, SET_o_irr_r, 3, addr, _L)
op(0xde, SET_o_irr_r, 3, addr, _)
op(0xdf, SET_o_irr_r, 3, addr, A)
op(0xe0, SET_o_irr_r, 4, addr, B)
op(0xe1, SET_o_irr_r, 4, addr, C)
op(0xe2, SET_o_irr_r, 4, addr, D)
op(0xe3, SET_o_irr_r, 4, addr, E)
op(0xe4, SET_o_irr_r, 4, addr, H)
op(0xe5, SET_o_irr_r, 4, addr, L)
op(0xe4, SET_o_irr_r, 4, addr, _H)
op(0xe5, SET_o_irr_r, 4, addr, _L)
op(0xe6, SET_o_irr_r, 4, addr, _)
op(0xe7, SET_o_irr_r, 4, addr, A)
op(0xe8, SET_o_irr_r, 5, addr, B)
op(0xe9, SET_o_irr_r, 5, addr, C)
op(0xea, SET_o_irr_r, 5, addr, D)
op(0xeb, SET_o_irr_r, 5, addr, E)
op(0xec, SET_o_irr_r, 5, addr, H)
op(0xed, SET_o_irr_r, 5, addr, L)
op(0xec, SET_o_irr_r, 5, addr, _H)
op(0xed, SET_o_irr_r, 5, addr, _L)
op(0xee, SET_o_irr_r, 5, addr, _)
op(0xef, SET_o_irr_r, 5, addr, A)
op(0xf0, SET_o_irr_r, 6, addr, B)
op(0xf1, SET_o_irr_r, 6, addr, C)
op(0xf2, SET_o_irr_r, 6, addr, D)
op(0xf3, SET_o_irr_r, 6, addr, E)
op(0xf4, SET_o_irr_r, 6, addr, H)
op(0xf5, SET_o_irr_r, 6, addr, L)
op(0xf4, SET_o_irr_r, 6, addr, _H)
op(0xf5, SET_o_irr_r, 6, addr, _L)
op(0xf6, SET_o_irr_r, 6, addr, _)
op(0xf7, SET_o_irr_r, 6, addr, A)
op(0xf8, SET_o_irr_r, 7, addr, B)
op(0xf9, SET_o_irr_r, 7, addr, C)
op(0xfa, SET_o_irr_r, 7, addr, D)
op(0xfb, SET_o_irr_r, 7, addr, E)
op(0xfc, SET_o_irr_r, 7, addr, H)
op(0xfd, SET_o_irr_r, 7, addr, L)
op(0xfc, SET_o_irr_r, 7, addr, _H)
op(0xfd, SET_o_irr_r, 7, addr, _L)
op(0xfe, SET_o_irr_r, 7, addr, _)
op(0xff, SET_o_irr_r, 7, addr, A)
}
}
auto Z80::instructionED(n8 code) -> void {
n8 _;
switch(code) {
op(0x40, IN_r_ic, B)
op(0x41, OUT_ic_r, B)
@@ -870,7 +875,7 @@ auto Z80::instructionED(n8 code) -> void {
op(0x6d, RETI)
op(0x6e, IM_o, 0)
op(0x6f, RLD)
op(0x70, IN_ic)
op(0x70, IN_r_ic, _)
op(0x71, OUT_ic)
op(0x72, SBC_hl_rr, SP)
op(0x73, LD_inn_rr, SP)
+120 -91
View File
@@ -24,9 +24,9 @@ auto Z80::instructionADC_a_r(n8& x) -> void { Q = 1;
auto Z80::instructionADC_hl_rr(n16& x) -> void { Q = 1;
WZ = HL + 1;
wait(4);
auto lo = ADD(HL >> 0, x >> 0, CF);
wait(3);
auto lo = ADD(HL >> 0, x >> 0, CF);
wait(4);
auto hi = ADD(HL >> 8, x >> 8, CF);
HL = hi << 8 | lo << 0;
ZF = HL == 0;
@@ -47,9 +47,9 @@ auto Z80::instructionADD_a_r(n8& x) -> void { Q = 1;
auto Z80::instructionADD_hl_rr(n16& x) -> void { Q = 1;
WZ = HL + 1;
bool vf = VF, zf = ZF, sf = SF;
wait(4);
auto lo = ADD(HL >> 0, x >> 0);
wait(3);
auto lo = ADD(HL >> 0, x >> 0);
wait(4);
auto hi = ADD(HL >> 8, x >> 8, CF);
HL = hi << 8 | lo << 0;
VF = vf, ZF = zf, SF = sf; //restore unaffected flags
@@ -67,14 +67,9 @@ auto Z80::instructionAND_a_r(n8& x) -> void { Q = 1;
A = AND(A, x);
}
auto Z80::instructionBIT_o_irr(n3 bit, n16& addr) -> void { Q = 1;
BIT(bit, read(addr));
XF = WZH.bit(3);
YF = WZH.bit(5);
}
auto Z80::instructionBIT_o_irr_r(n3 bit, n16& addr, n8& x) -> void { Q = 1;
x = BIT(bit, read(addr));
wait(1);
XF = WZH.bit(3);
YF = WZH.bit(5);
}
@@ -91,13 +86,6 @@ auto Z80::instructionCALL_c_nn(bool c) -> void { Q = 0;
PC = WZ;
}
auto Z80::instructionCALL_nn() -> void { Q = 0;
WZ = operands();
wait(1);
push(PC);
PC = WZ;
}
auto Z80::instructionCCF() -> void {
if(Q) XF = 0, YF = 0;
HF = CF;
@@ -140,6 +128,8 @@ auto Z80::instructionCPDR() -> void { Q = 1;
wait(5);
PC -= 2;
WZ = PC + 1;
XF = PC.bit(11);
YF = PC.bit(13);
}
auto Z80::instructionCPI() -> void { Q = 1;
@@ -162,6 +152,8 @@ auto Z80::instructionCPIR() -> void { Q = 1;
wait(5);
PC -= 2;
WZ = PC + 1;
XF = PC.bit(11);
YF = PC.bit(13);
}
auto Z80::instructionCPL() -> void { Q = 1;
@@ -225,8 +217,10 @@ auto Z80::instructionEI() -> void { Q = 0;
auto Z80::instructionEX_irr_rr(n16& x, n16& y) -> void { Q = 0;
WZL = read(x + 0);
WZH = read(x + 1);
wait(1);
write(x + 0, y >> 0);
write(x + 1, y >> 8);
wait(2);
y = WZ;
}
@@ -245,7 +239,6 @@ auto Z80::instructionHALT() -> void { Q = 0;
}
auto Z80::instructionIM_o(n2 code) -> void { Q = 0;
wait(4);
IM = code;
}
@@ -260,11 +253,6 @@ auto Z80::instructionIN_r_ic(n8& x) -> void { Q = 1;
WZ = BC + 1;
}
auto Z80::instructionIN_ic() -> void { Q = 1;
IN(in(BC));
WZ = BC + 1;
}
auto Z80::instructionINC_irr(n16& x) -> void { Q = 1;
auto addr = displace(x);
auto data = read(addr);
@@ -302,6 +290,20 @@ auto Z80::instructionINDR() -> void { Q = 1;
if(!B) return;
wait(5);
PC -= 2;
XF = PC.bit(11);
YF = PC.bit(13);
if(CF && NF) {
PF = PF == parity(B-1 & 7);
HF = (B & 0xf) == 0;
}
if(CF && !NF) {
PF = PF == parity(B+1 & 7);
HF = (B & 0xf) == 0xf;
}
if(!CF) {
PF = PF == parity(B+0 & 7);
}
}
auto Z80::instructionINI() -> void { Q = 1;
@@ -325,6 +327,20 @@ auto Z80::instructionINIR() -> void { Q = 1;
if(!B) return;
wait(5);
PC -= 2;
XF = PC.bit(11);
YF = PC.bit(13);
if(CF && NF) {
PF = PF == parity(B-1 & 7);
HF = (B & 0xf) == 0;
}
if(CF && !NF) {
PF = PF == parity(B+1 & 7);
HF = (B & 0xf) == 0xf;
}
if(!CF) {
PF = PF == parity(B+0 & 7);
}
}
auto Z80::instructionJP_c_nn(bool c) -> void { Q = 0;
@@ -351,7 +367,7 @@ auto Z80::instructionLD_a_inn() -> void { Q = 0;
auto Z80::instructionLD_a_irr(n16& x) -> void { Q = 0;
WZ = x;
A = read(displace(WZ));
A = read(x);
WZ++;
}
@@ -370,14 +386,16 @@ auto Z80::instructionLD_inn_rr(n16& x) -> void { Q = 0;
auto Z80::instructionLD_irr_a(n16& x) -> void { Q = 0;
WZ = x;
write(displace(WZ), A);
write(x, A);
WZL++;
WZH = A;
}
auto Z80::instructionLD_irr_n(n16& x) -> void { Q = 0;
auto addr = displace(x);
write(addr, operand());
auto addr = displace(x,0); // special case: defer wait cycles (overlap with n fetch)
auto data = operand();
if(&x == &ix.word || &x == &iy.word) wait(2);
write(addr, data);
}
auto Z80::instructionLD_irr_r(n16& x, n8& y) -> void { Q = 0;
@@ -417,9 +435,10 @@ auto Z80::instructionLD_r_r2(n8& x, n8& y) -> void { Q = 1;
}
auto Z80::instructionLD_rr_inn(n16& x) -> void { Q = 0;
auto addr = operands();
x.byte(0) = read(addr + 0);
x.byte(1) = read(addr + 1);
WZ = operands();
x.byte(0) = read(WZ);
WZ++;
x.byte(1) = read(WZ);
}
auto Z80::instructionLD_rr_nn(n16& x) -> void { Q = 0;
@@ -448,6 +467,8 @@ auto Z80::instructionLDDR() -> void { Q = 1;
wait(5);
PC -= 2;
WZ = PC + 1;
XF = PC.bit(11);
YF = PC.bit(13);
}
auto Z80::instructionLDI() -> void { Q = 1;
@@ -467,6 +488,8 @@ auto Z80::instructionLDIR() -> void { Q = 1;
wait(5);
PC -= 2;
WZ = PC + 1;
XF = PC.bit(11);
YF = PC.bit(13);
}
auto Z80::instructionNEG() -> void { Q = 1;
@@ -493,6 +516,20 @@ auto Z80::instructionOTDR() -> void { Q = 1;
if(!B) return;
wait(5);
PC -= 2;
XF = PC.bit(11);
YF = PC.bit(13);
if(CF && NF) {
PF = PF == parity(B-1 & 7);
HF = (B & 0xf) == 0;
}
if(CF && !NF) {
PF = PF == parity(B+1 & 7);
HF = (B & 0xf) == 0xf;
}
if(!CF) {
PF = PF == parity(B+0 & 7);
}
}
auto Z80::instructionOTIR() -> void { Q = 1;
@@ -500,6 +537,20 @@ auto Z80::instructionOTIR() -> void { Q = 1;
if(!B) return;
wait(5);
PC -= 2;
XF = PC.bit(11);
YF = PC.bit(13);
if(CF && NF) {
PF = PF == parity(B-1 & 7);
HF = (B & 0xf) == 0;
}
if(CF && !NF) {
PF = PF == parity(B+1 & 7);
HF = (B & 0xf) == 0xf;
}
if(!CF) {
PF = PF == parity(B+0 & 7);
}
}
auto Z80::instructionOUT_ic_r(n8& x) -> void { Q = 0;
@@ -510,6 +561,7 @@ auto Z80::instructionOUT_ic_r(n8& x) -> void { Q = 0;
auto Z80::instructionOUT_ic() -> void { Q = 0;
if(mosfet == MOSFET::NMOS) out(BC, 0x00);
if(mosfet == MOSFET::CMOS) out(BC, 0xff);
WZ = BC + 1;
}
auto Z80::instructionOUT_in_a() -> void { Q = 0;
@@ -561,20 +613,17 @@ auto Z80::instructionPUSH_rr(n16& x) -> void { Q = 0;
push(x);
}
auto Z80::instructionRES_o_irr(n3 bit, n16& addr) -> void { Q = 1;
write(addr, RES(bit, read(addr)));
auto Z80::instructionRES_o_irr_r(n3 bit, n16& addr, n8& x) -> void { Q = 0;
auto data = read(addr);
wait(1);
write(addr, x = RES(bit, data));
}
auto Z80::instructionRES_o_irr_r(n3 bit, n16& addr, n8& x) -> void { Q = 1;
write(addr, x = RES(bit, read(addr)));
}
auto Z80::instructionRES_o_r(n3 bit, n8& x) -> void { Q = 1;
auto Z80::instructionRES_o_r(n3 bit, n8& x) -> void { Q = 0;
x = RES(bit, x);
}
auto Z80::instructionRET() -> void { Q = 0;
wait(1);
WZ = pop();
PC = WZ;
}
@@ -598,12 +647,10 @@ auto Z80::instructionRETN() -> void { Q = 0;
IFF1 = IFF2;
}
auto Z80::instructionRL_irr(n16& addr) -> void { Q = 1;
write(addr, RL(read(addr)));
}
auto Z80::instructionRL_irr_r(n16& addr, n8& x) -> void { Q = 1;
write(addr, x = RL(read(addr)));
auto data = read(addr);
wait(1);
write(addr, x = RL(data));
}
auto Z80::instructionRL_r(n8& x) -> void { Q = 1;
@@ -621,12 +668,10 @@ auto Z80::instructionRLA() -> void { Q = 1;
YF = A.bit(5);
}
auto Z80::instructionRLC_irr(n16& addr) -> void { Q = 1;
write(addr, RLC(read(addr)));
}
auto Z80::instructionRLC_irr_r(n16& addr, n8& x) -> void { Q = 1;
write(addr, x = RLC(read(addr)));
auto data = read(addr);
wait(1);
write(addr, x = RLC(data));
}
auto Z80::instructionRLC_r(n8& x) -> void { Q = 1;
@@ -647,9 +692,8 @@ auto Z80::instructionRLCA() -> void { Q = 1;
auto Z80::instructionRLD() -> void { Q = 1;
WZ = HL + 1;
auto data = read(HL);
wait(1);
wait(4);
write(HL, (data << 4) | (A & 0x0f));
wait(3);
A = (A & 0xf0) | (data >> 4);
NF = 0;
@@ -661,12 +705,10 @@ auto Z80::instructionRLD() -> void { Q = 1;
SF = A.bit(7);
}
auto Z80::instructionRR_irr(n16& addr) -> void { Q = 1;
write(addr, RR(read(addr)));
}
auto Z80::instructionRR_irr_r(n16& addr, n8& x) -> void { Q = 1;
write(addr, x = RR(read(addr)));
auto data = read(addr);
wait(1);
write(addr, x = RR(data));
}
auto Z80::instructionRR_r(n8& x) -> void { Q = 1;
@@ -684,12 +726,10 @@ auto Z80::instructionRRA() -> void { Q = 1;
YF = A.bit(5);
}
auto Z80::instructionRRC_irr(n16& addr) -> void { Q = 1;
write(addr, RRC(read(addr)));
}
auto Z80::instructionRRC_irr_r(n16& addr, n8& x) -> void { Q = 1;
write(addr, x = RRC(read(addr)));
auto data = read(addr);
wait(1);
write(addr, x = RRC(data));
}
auto Z80::instructionRRC_r(n8& x) -> void { Q = 1;
@@ -710,9 +750,8 @@ auto Z80::instructionRRCA() -> void { Q = 1;
auto Z80::instructionRRD() -> void { Q = 1;
WZ = HL + 1;
auto data = read(HL);
wait(1);
wait(4);
write(HL, (data >> 4) | (A << 4));
wait(3);
A = (A & 0xf0) | (data & 0x0f);
NF = 0;
@@ -745,9 +784,9 @@ auto Z80::instructionSBC_a_r(n8& x) -> void { Q = 1;
auto Z80::instructionSBC_hl_rr(n16& x) -> void { Q = 1;
WZ = HL + 1;
wait(4);
auto lo = SUB(HL >> 0, x >> 0, CF);
wait(3);
auto lo = SUB(HL >> 0, x >> 0, CF);
wait(4);
auto hi = SUB(HL >> 8, x >> 8, CF);
HL = hi << 8 | lo << 0;
ZF = HL == 0;
@@ -763,60 +802,50 @@ auto Z80::instructionSCF() -> void {
Q = 1;
}
auto Z80::instructionSET_o_irr(n3 bit, n16& addr) -> void { Q = 1;
write(addr, SET(bit, read(addr)));
auto Z80::instructionSET_o_irr_r(n3 bit, n16& addr, n8& x) -> void { Q = 0;
auto data = read(addr);
wait(1);
write(addr, x = SET(bit, data));
}
auto Z80::instructionSET_o_irr_r(n3 bit, n16& addr, n8& x) -> void { Q = 1;
write(addr, x = SET(bit, read(addr)));
}
auto Z80::instructionSET_o_r(n3 bit, n8& x) -> void { Q = 1;
auto Z80::instructionSET_o_r(n3 bit, n8& x) -> void { Q = 0;
x = SET(bit, x);
}
auto Z80::instructionSLA_irr(n16& addr) -> void { Q = 1;
write(addr, SLA(read(addr)));
}
auto Z80::instructionSLA_irr_r(n16& addr, n8& x) -> void { Q = 1;
write(addr, x = SLA(read(addr)));
auto data = read(addr);
wait(1);
write(addr, x = SLA(data));
}
auto Z80::instructionSLA_r(n8& x) -> void { Q = 1;
x = SLA(x);
}
auto Z80::instructionSLL_irr(n16& addr) -> void { Q = 1;
write(addr, SLL(read(addr)));
}
auto Z80::instructionSLL_irr_r(n16& addr, n8& x) -> void { Q = 1;
write(addr, x = SLL(read(addr)));
auto data = read(addr);
wait(1);
write(addr, x = SLL(data));
}
auto Z80::instructionSLL_r(n8& x) -> void { Q = 1;
x = SLL(x);
}
auto Z80::instructionSRA_irr(n16& addr) -> void { Q = 1;
write(addr, SRA(read(addr)));
}
auto Z80::instructionSRA_irr_r(n16& addr, n8& x) -> void { Q = 1;
write(addr, x = SRA(read(addr)));
auto data = read(addr);
wait(1);
write(addr, x = SRA(data));
}
auto Z80::instructionSRA_r(n8& x) -> void { Q = 1;
x = SRA(x);
}
auto Z80::instructionSRL_irr(n16& addr) -> void { Q = 1;
write(addr, SRL(read(addr)));
}
auto Z80::instructionSRL_irr_r(n16& addr, n8& x) -> void { Q = 1;
write(addr, x = SRL(read(addr)));
auto data = read(addr);
wait(1);
write(addr, x = SRL(data));
}
auto Z80::instructionSRL_r(n8& x) -> void { Q = 1;
+2 -2
View File
@@ -27,10 +27,10 @@ auto Z80::pop() -> n16 {
return data | read(SP++) << 8;
}
auto Z80::displace(n16& x) -> n16 {
auto Z80::displace(n16& x, u32 wclocks) -> n16 {
if(&x != &ix.word && &x != &iy.word) return x;
auto d = operand();
wait(5);
wait(wclocks);
WZ = x + (i8)d;
return WZ;
}
+39 -18
View File
@@ -31,29 +31,31 @@ auto Z80::power(MOSFET mosfet) -> void {
HALT = 0;
IFF1 = 0;
IFF2 = 0;
IM = 1;
IM = 0;
}
auto Z80::irq(bool maskable, n16 pc, n8 extbus) -> bool {
auto Z80::reset() -> void {
prefix = Prefix::hl;
ir.word = 0x0000;
WZ = PC = 0x0000;
EI = 0;
HALT = 0;
IFF1 = 0;
IFF2 = 0;
IM = 0;
}
auto Z80::irq(n8 extbus) -> bool {
//do not execute maskable interrupts if disabled or immediately after EI instruction
if(maskable && (!IFF1 || EI)) return false;
if(!IFF1 || EI) return false;
R.bit(0,6)++;
push(PC);
switch(maskable ? IM : (n2)1) {
switch(IM) {
case 1: extbus = 0xff; [[fallthrough]];
case 0: {
//external data bus ($ff = RST $38)
WZ = extbus;
wait(extbus | 0x38 == 0xff ? 6 : 7);
break;
}
case 1: {
//constant address
WZ = pc;
wait(maskable ? 7 : 5);
wait(6);
instruction(WZ);
break;
}
@@ -63,18 +65,37 @@ auto Z80::irq(bool maskable, n16 pc, n8 extbus) -> bool {
WZL = read(address + 0);
WZH = read(address + 1);
wait(7);
push(PC);
PC = WZ;
break;
}
}
PC = WZ;
IFF1 = 0;
if(maskable) IFF2 = 0;
IFF2 = 0;
HALT = 0;
if(P) PF = 0;
P = 0;
Q = 0;
return true;
}
auto Z80::nmi() -> bool {
R.bit(0,6)++;
push(PC);
WZ = 0x66;
wait(5);
PC = WZ;
IFF1 = 0;
HALT = 0;
if(P) PF = 0;
P = 0;
Q = 0;
return true;
}
+4 -2
View File
@@ -22,8 +22,10 @@ struct Z80 {
//z80.cpp
auto power(MOSFET = MOSFET::NMOS) -> void;
auto reset() -> void;
auto irq(bool maskable, n16 vector = 0x0000, n8 extbus = 0xff) -> bool;
auto irq(n8 extbus = 0xff) -> bool;
auto nmi() -> bool;
auto parity(n8) const -> bool;
//memory.cpp
@@ -33,7 +35,7 @@ struct Z80 {
auto operands() -> n16;
auto push(n16) -> void;
auto pop() -> n16;
auto displace(n16&) -> n16;
auto displace(n16&, u32 wclocks = 5) -> n16;
auto read(n16 address) -> n8;
auto write(n16 address, n8 data) -> void;
auto in(n16 address) -> n8;
+38 -8
View File
@@ -1,9 +1,10 @@
auto V9938::Background::setup(n8 y) -> void {
latch.vscroll = io.vscroll;
}
auto V9938::Background::run(n8 x, n8 y) -> void {
output = {};
switch(self.videoMode()) {
case 0b00000: return graphic1(x, y);
case 0b00001: return text1(x, y);
@@ -19,7 +20,26 @@ auto V9938::Background::run(n8 x, n8 y) -> void {
}
auto V9938::Background::text1(n8 hoffset, n8 voffset) -> void {
debug(unimplemented, "[V9938::Background::text1]");
// Offset by 6px and blank the last 10px to centre the display
i32 x = hoffset - 6;
if (x < 0) return;
if (hoffset > 246) return;
n14 nameAddress = (voffset.bit(3,7) * 40) + (x / 6);
nameAddress.bit(10,16) = io.nameTableAddress.bit(10,16);
n8 pattern = self.vram.read(nameAddress);
n14 patternAddress;
patternAddress.bit( 0, 2) = voffset.bit(0,2);
patternAddress.bit( 3,10) = pattern;
patternAddress.bit(11,13) = io.patternTableAddress.bit(11,13);
n3 index = 7 - (x % 6);
if(self.vram.read(patternAddress).bit(index)) {
output.color[0] = self.io.colorForeground;
output.color[1] = self.io.colorForeground;
}
}
auto V9938::Background::text2(n8 hoffset, n8 voffset) -> void {
@@ -30,7 +50,7 @@ auto V9938::Background::graphic1(n8 hoffset, n8 voffset) -> void {
n14 patternLayout;
patternLayout.bit( 0, 4) = hoffset.bit(3,7);
patternLayout.bit( 5, 9) = voffset.bit(3,7);
patternLayout.bit(10,13) = io.nameTableAddress.bit(10,13);
patternLayout.bit(10,16) = io.nameTableAddress.bit(10,16);
n8 pattern = self.vram.read(patternLayout);
n14 patternGenerator;
@@ -44,14 +64,15 @@ auto V9938::Background::graphic1(n8 hoffset, n8 voffset) -> void {
n8 color = self.vram.read(colorAddress);
if(self.vram.read(patternGenerator).bit(~hoffset & 7)) color >>= 4;
output.color = color.bit(0,3);
output.color[0] = color.bit(0,3);
output.color[1] = color.bit(0,3);
}
auto V9938::Background::graphic2(n8 hoffset, n8 voffset) -> void {
n14 patternLayout;
patternLayout.bit( 0, 4) = hoffset.bit(3,7);
patternLayout.bit( 5, 9) = voffset.bit(3,7);
patternLayout.bit(10,13) = io.nameTableAddress.bit(10,13);
patternLayout.bit(10,16) = io.nameTableAddress.bit(10,16);
n8 pattern = self.vram.read(patternLayout);
n14 patternGenerator;
@@ -67,7 +88,8 @@ auto V9938::Background::graphic2(n8 hoffset, n8 voffset) -> void {
n8 colorMask = io.colorTableAddress.bit(6,12) << 1 | 1;
n8 color = self.vram.read(colorAddress);
if(self.vram.read(patternGenerator).bit(~hoffset & 7)) color >>= 4;
output.color = color.bit(0,3);
output.color[0] = color.bit(0,3);
output.color[1] = color.bit(0,3);
}
auto V9938::Background::graphic3(n8 hoffset, n8 voffset) -> void {
@@ -82,11 +104,19 @@ auto V9938::Background::graphic4(n8 hoffset, n8 voffset) -> void {
address += hoffset >> 1;
auto data = self.vram.read(address);
auto shift = !hoffset.bit(0) ? 4 : 0;
output.color = n4(data >> shift);
output.color[0] = n4(data >> shift);
output.color[1] = n4(data >> shift);
}
auto V9938::Background::graphic5(n8 hoffset, n8 voffset) -> void {
debug(unimplemented, "[V9938::Background::graphic5]");
n17 address = io.nameTableAddress & 0x18000;
address += voffset << 7;
address += hoffset >> 1;
auto data = self.vram.read(address);
auto shift = !hoffset.bit(0) ? 4 : 0;
output.color[0] = n2(data >> (shift + 2));
output.color[1] = n2(data >> (shift + 0));
}
auto V9938::Background::graphic6(n8 hoffset, n8 voffset) -> void {
+13 -5
View File
@@ -5,13 +5,21 @@ auto V9938::DAC::setup(n8 voffset) -> void {
}
auto V9938::DAC::run(n8 hoffset, n8 voffset) -> void {
n4 color = self.io.colorBackground;
n4 color[2];
color[0] = self.io.colorBackground;
color[1] = self.io.colorBackground;
if(io.enable) {
if(self.background.output.color) color = self.background.output.color;
if(self.sprite.output.color) color = self.sprite.output.color;
if(self.background.output.color[0]) color[0] = self.background.output.color[0];
if(self.background.output.color[1]) color[1] = self.background.output.color[1];
if(self.sprite.output.color) {
color[0] = self.sprite.output.color;
color[1] = self.sprite.output.color;
}
}
*output++ = self.pram[color];
*output++ = self.pram[color];
*output++ = self.pram[color[0]];
*output++ = self.pram[color[1]];
}
auto V9938::DAC::power() -> void {
+1 -1
View File
@@ -219,7 +219,7 @@ auto V9938::register(n6 register, n8 data) -> void {
return;
case 0x17:
background.io.vscroll = data;
io.vscroll = data;
return;
case 0x20: op.sx.bit(0,7) = data.bit(0,7); return;
Loaded 100 of 1457 files, more files were not shown because too many files have changed in this diff. Show more