Compare commits

...
283 Commits
Author SHA1 Message Date
Luke Usher 6174fa384e bump version number to v128 2022-05-17 19:45:05 +01:00
invertego e5d1f2dfea recompiler: update to latest SLJIT API 2022-05-13 18:48:45 +01:00
Luke Usher 54f6ea31f5 Merge commit '0d26512309d871d62972bfcd8e48f48528881332' 2022-05-13 18:47:17 +01:00
Luke Usher 1d26512309 Squashed 'thirdparty/sljit/' changes from d6a0fa61e..761d48d2b
761d48d2b Improve constant generation
1f32a9f23 Implement fpu operations for RISC-V
ad99f17a9 Improve x86 float compare
fb55788d0 Initial implementation of RISC-V port
7f08de6ff Improve jump code generator on MIPS
469c61db9 Improve mips code generator
a4e8e34ef Support unsaved registers on s390x
f404f3608 Support unsaved registers
88d4778b9 Add license file
160b6f99d windows: fix building in arm64 with clang (#126)
022482eeb wxexec: officially drop support for EOL NetBSD < 8 versions (#124)
beda74f07 Support reworked floating point compare on s390x
050215b22 Remove unnecessary checks
6b950049d Improve floating point compare.
6ace72c90 windows: allow building with MinGW64 gcc/clang (#125)
186b07064 mips: avoid sign conversion warnings with clang (#122)
e0b17f5a6 macos: fix recent regression breaking build in macos/arm64e (#121)
68d9b4bac misc: mostly to avoid warnings (#120)
76330309a Update s390x.
6807c7a8f Remove SLJIT_NEG.
ca530a4a7 Readd carry flag support.
5f60134b5 s390x: be explicit about cache coherence needs (#119)
75a555604 power: avoid bogus clear_cache builtin in gcc >= 10 (#118)
1448ef97c sparc: avoid NOP implementation for clear_cache with gcc (#117)
ad69ad87b sparc: build fixes (#116)
47646b943 Support incoming arguments in scratch registers for s390x.
4fbdd6953 Support incoming arguments in scratch registers.
86ebfbd50 Rework x86-32 function prologue/epilogue.
2f8cf7a08 Increase the number of floating point registers on ppc, mips, and sparc.
2737606ee Increase the number floating point registers on s390x.
03469c8e1 Rename tail call to call return and minor ARM improvements.
7cb8a5c24 Increase the number floating point registers on x86 and ARM.
b35ab5e7e Implement fpu support on s390x.
dcc8fc149 misc: fix -Wextra related errors (#114)
92fcb0fe5 Fix fallthrough errors.
d345a64b3 misc: build/documentation fixes from recent changes (#113)
ff6ec4f74 Implement tail call on MIPS.
eed28632f Implement tail call on ARM.
d7793570f Reduce signed comparison warnings.
30b2dcd83 Reduce value conversion warnings on s390x.
c783c1119 Reduce value conversion warnings on MIPS, PPC, SPARC.
335ee51f5 Reduce value conversion warnings on ARM.
8d0f668fa Improve value conversion warnings.
373163144 Implementing tail calls for x86.
9c8b6961b Improve argument sanity checks.
24c547b7e Swap f32 and f64 argument types.
7f0afb25e Rework function argument list descriptor macros.
585ac42bf Implement four argument support for emit enter.
b5e0b1234 Improve mov32 operation.
433294658 Fix incorrect function call (#112)
cf594d74d Change SLJIT_I32_OP and SLJIT_F32_OP to SLJIT_32.
ae5fff841 Improve arm code generator.
43538b877 Replace SLJIT_UNUSED with appropriate function calls.

git-subtree-dir: thirdparty/sljit
git-subtree-split: 761d48d2b89a048badbd9c5cf45da75336891cfe
2022-05-13 18:47:16 +01:00
Luke Usher 43f1e524e0 Merge commit '402c8acc5f30b9ec355deb52618d99eb69f58916' 2022-05-13 18:47:05 +01:00
Luke Usher 402c8acc5f Squashed 'ares/n64/vulkan/parallel-rdp/' changes from 05136e3b4..af9b4b00f
af9b4b00f Update to b355d60aa32c8647670634d30ea1b107c3f78b05
0dcebe11e Update to e5efa5836cd43a597c706e07f04e79083d5ffb4f
e79d0cb77 Update to b3eeb49e708a215ee990415f303ce9936e55bd66

git-subtree-dir: ares/n64/vulkan/parallel-rdp
git-subtree-split: af9b4b00f0e6ec17cfd59f9e71c4976b5c3c40b0
2022-05-13 18:47:05 +01:00
Giovanni Bajo 2451fec704 n64: internal mask of physicalAddress register in TLB entries
Fix one test in n64-systemtest
2022-05-08 14:31:34 +01:00
Giovanni Bajo 8a70118446 n64: fix 64-bit pc calculation in J opcode
This was missed in the previous sweep on 64-bit PC. Fix one test
in n64-systemtest.
2022-05-08 14:31:34 +01:00
Giovanni Bajo fa017c26a5 n64: implement exceptions in non-taken delay slots
When an exception happen in a delay slot, it behaves the same whether
the branch was taken or not. In Ares, instead, the state "delay slot"
only applied to taken branches.

Fix several tests in n64-systemtest
2022-05-08 14:31:34 +01:00
Giovanni Bajo 670920a5a4 n64: increase a little the PI DMA timing.
These timings actually depend on the PI registers, even though they
are almost always set to fixed default values. We will get there
eventually and provide a more accurate figure, but for now this
allows to pass timing tests in n64-systemtest so that it can't be
more wrong than before.
2022-05-08 14:31:34 +01:00
Giovanni Bajo 82364646d3 n64: fix controller input after PIF refactoring
A last minute change in 741320e0be introduced a regression in controller
input.

Similar to what we did with PI DMA, SI DMA does not go through the main
bus (SysAD bus) but directly communicate with pif and rdram. This is not
just for the sake of correctness, but SysAD bus half-word writes are
now emulated with the same brokeness they have on real hardware, and
obviously DMA works instead. Moreover, since SI only reads/writes
32-bit words, also switch to word access.
2022-05-07 21:59:27 +01:00
Giovanni Bajo 40220a6ba1 n64: map domain 1 address 3 zone into main memory map
This was missed in the PI bus refactoring. All addresses up to
7fff'ffff are mapped to the PI bus.
2022-05-07 11:33:48 +01:00
Giovanni Bajo 96a6f98862 n64: refactor PIF chip into its own class
Currently, Ares does not model the PIF chip on its own: it looks like
there was an original mistake that conflated the PI (peripheral
interface, one of the components of RCP) with the PIF-NUS (a separate
chip, connected to SI component of RCP via a serial bus).

This refactor introduces a PIF class and moves all the related code
into it. Since the class implements the Memory::IO protocol for memory
accesses, it also fixes memory accesses with non standard sizes, as
tested by n64-systemtest.
2022-05-07 11:33:48 +01:00
Giovanni Bajo 3423bcf65e n64: improve TLB register masking
Fix a few tests from n64-systemtest
2022-05-07 11:33:48 +01:00
Giovanni Bajo a74ef69d86 n64: add address error for invalid 64bit address in 32bit mode
Fix a few tests from n64-systemtest
2022-05-07 11:33:48 +01:00
Giovanni Bajo 177475f053 n64: fix a few memory access opcodes that were using a 32-bit address 2022-05-07 11:33:48 +01:00
Giovanni Bajo 32ba2fe676 n64: activate address errors by default
These improve accuracy and help with homebrew development, while not
affecting performance much.
2022-05-07 11:33:48 +01:00
Giovanni Bajo 3aa1b3b738 n64: fix LL / SC / LLD / SCD opcodes
Updates #140.

Unfortunately this doesn't fix Gauntlet Legends.
2022-05-06 10:24:40 +01:00
Giovanni Bajo abf4c58ce6 n64: fix cache to use physical addresses
There is a bit confusion of virtual vs physical addresses in Ares,
so dcache/icache were sometimes using a virtual address, sometimes
a physical one. This is wrong: cache is based on physical addresses
only.

Moreover, the CACHE opcode was not even going through TLBs, while it
should. So a CACHE opcode on a TLB-mapped address wasn't working before.
2022-05-06 10:23:31 +01:00
Luke Usher 6b0a52fcb6 Merge commit 'c7e59d13fa1eaa6d6e19daec8dc22a3bdf7e0e70' 2022-05-03 18:02:47 +01:00
Luke Usher c7e59d13fa Squashed 'thirdparty/libchdr/' changes from a03e69319..6eeb6abc4
6eeb6abc4 Merge pull request #76 from invertego/zlib_codec_init_free
254cdaccc Remove erroneous free() call in zlib_codec_init()

git-subtree-dir: thirdparty/libchdr
git-subtree-split: 6eeb6abc4adc094d489c8ba8cafdcff9ff61251b
2022-05-03 18:02:47 +01:00
invertego ea2b6886b5 nall: handle CHD paths with non-ASCII chars on Windows 2022-05-03 09:11:15 +01:00
Giovanni Bajo 80e651741c n64: make sure TLB entries are correctly initialized at power
This bug has always been there, but was hidden by the incorrect TLB
matching logic. After fixing the logic in 0bf24b3, this bug was
uncovered.

Fixes Goldeneye.
2022-05-03 09:10:20 +01:00
Giovanni Bajo 6b70ae6d69 n64: fix RSP LTV opcode in its corner cases
Fix one test in n64-systemtest ROM.
2022-05-03 09:09:08 +01:00
Giovanni Bajo a3a777ef93 nall: optimize priority_queue remove function 2022-04-30 22:06:12 +01:00
Giovanni Bajo abaf7a82f3 n64: implement proper PI bus writes with IO busy bit
All writes through the PI bus are actually performed asynchronous by
the hardware, and the status is reflected in the PI IO busy bit.

This commit emulates this properly, and also emulates what happens while
the busy bit is set: further writes are ignored, and reads at any
address return the word being written.

This fixes A Bug's Life and Toy Story 2.
2022-04-30 22:06:12 +01:00
Giovanni Bajoandremutro 0bf24b3161 n64: fix (again) TLB logic in case of invalid TLBs
This is a revert of 56458d5b, while keeping b7f96b7109 which is the
real fix that should have been done all along. The former just papered
over the issue and actually introduced a regression (Goldeneye wouldn't
boot).

Co-Authored-By: remutro <[email protected]>
2022-04-29 22:02:24 +01:00
bigbass1997 a527ed6d1d n64: add separate CIC 7102 detection 2022-04-27 16:31:01 +01:00
Giovanni Bajo cf0582f607 n64: implement undocumented broken RSP opcodes
Fix several tests in n64-systemtest ROM.
2022-04-27 16:30:46 +01:00
Giovanni Bajo 02942aca6b n64: Fix RSP MTC2 and LFV opcodes
Fix several tests in n64-systemtest ROM.
2022-04-27 16:30:46 +01:00
Giovanni Bajo aae3caab38 n64: fix RSP BGEZAL/BLTZAL when RA is being tested
Fix several tests in n64-systemtest ROM.
2022-04-27 16:30:46 +01:00
Giovanni Bajo 2a71b978be n64: fix cop0 LL write mask
Fix one test in n64-systemtest ROM.
2022-04-27 16:30:46 +01:00
Giovanni Bajo 336af4c219 Revert "n64: update RSP DMA registers after transfers."
This reverts commit 5e4e64dbd7.

Reason: it breaks Zelda OOT. Requires more thinking.
2022-04-27 00:32:38 +01:00
Giovanni Bajo 1afbf893d7 n64: fix RSP DMEM/IMEM accesses with all access sizes
Like anything else, DMEM/IMEM need to go through the mangling performed
by Memory::IO.

Fix several tests in n64-systemtest ROM.
2022-04-26 09:14:50 +01:00
Giovanni Bajo 6bcab5e7ed n64: fix Dual accesses on MMIO regs
Those accesses are really broken beyond repair, and they just write
the upper half.

Fix several tests in n64-systemtest ROM.
2022-04-26 09:14:50 +01:00
Giovanni Bajo 5e4e64dbd7 n64: update RSP DMA registers after transfers.
Fix several tests in n64-systemtest ROM.
2022-04-26 09:14:50 +01:00
Giovanni Bajo 728db642f0 n64: fix RSP DMA wraparound
RSP DMA always wraps within the same region.

Fix several tests in n64-systemtest ROM.
2022-04-26 09:14:50 +01:00
Giovanni Bajo e1f1cbbb4b rsp: small accuracy tweak to semaphore register
Fix several tests in n64-systemtest ROM.
2022-04-26 09:14:50 +01:00
Giovanni Bajo b7f96b7109 n64: fix TLB logic for non-global entries
Fix several tests in n64-systemtest ROM.
2022-04-26 09:14:50 +01:00
Giovanni Bajo 32c15726ae n64: fix masking of COP0 context / xcontext
Fix several tests in n64-systemtest ROM.
2022-04-26 09:14:50 +01:00
Giovanni Bajo 6160a81368 n64: fix TLB random register when wired > 31
Also take the chance to remove the "hopefully accurate but then not
really" implementation which runs after every instruction in favor
of a real random.

Fix one test in n64-systemtest ROM.
2022-04-26 09:14:50 +01:00
Giovanni Bajo 523b6ce5cf n64: improve emulation of vector load opcodes in side cases
Fix several tests in n64-systemtest ROM.
2022-04-24 21:14:49 +01:00
Giovanni Bajo 95e407aae1 n64: implement LWU opcode in RSP
Fix one test in n64-systemtest ROM.
2022-04-24 21:14:49 +01:00
Giovanni Bajo 5e1d6d1aab n64: improve address exceptions with correct COP0 status
Fix several tests in n64-systemtest ROM.
2022-04-24 21:14:49 +01:00
Giovanni Bajo 9f0f4b3432 n64: implement buggy byte/half reads from cartridge space
Fix several tests in n64-systemtest ROM.
2022-04-24 21:14:49 +01:00
Giovanni Bajo f4a38d121d n64; implement correct behaviours of jumps within delay slots
Fix several tests in n64-systemtest ROM.
2022-04-23 15:49:13 +01:00
Giovanni Bajo abf454cecb n64: fix JALR when jumping to RA
Fix one test in n64-systemtest ROM.
2022-04-23 15:49:13 +01:00
Giovanni Bajo 6c40a5b4c6 n64: fix handling of invalid pagemasks
Fix several tests in n64-systemtest ROM.
2022-04-23 15:49:13 +01:00
Giovanni Bajo 56458d5ba5 n64: fix exception kind in case of TLB invalid page and with nonmatching asid
Fix several tests in n64-systemtest ROM.
2022-04-23 15:49:13 +01:00
Giovanni Bajo 8d04515b5f n64: fix behavior of conflicting bits in writes to SP_STATUS
Fix several tests in n64-systemtest ROM.
2022-04-23 15:49:13 +01:00
Giovanni Bajo f66c93c0c2 n64: fix BGEZAL/BGEZALL opcodes when testing RA
Fix several tests in n64-systemtest ROM.
2022-04-23 15:49:13 +01:00
Giovanni Bajo f4c9c11596 n64: fix RSP PC to stay within 12 bits in all cases
Fix several tests in n64-systemtest ROM.
2022-04-23 15:49:13 +01:00
Giovanni Bajo 906191ac45 n64: fix COP0 config initial status
Fix a test in n64-systemtest ROM.
2022-04-23 15:49:13 +01:00
Giovanni Bajo a0c063cabe n64: fix CPU core to correctly handle 64-bit PC
PC register in VR4300 is 64-bit but there were many places where
the register was incorrectly treated as a 32-bit one, effectively
discarding the higher half.

Fix several tests in n64-systemtest ROM.
2022-04-23 15:49:13 +01:00
invertego ebf41cb696 mia: update out of date resources 2022-04-23 15:49:02 +01:00
invertego c0dfad661b build: fix clean targets on Windows
To get clean makefile targets working robustly under a Windows command
prompt, allow the entire contents of obj/out directories to be deleted.
They are now recreated by the build as needed.
2022-04-23 15:49:02 +01:00
invertego 0b80107cdf build: fix building from Windows command prompt
Replace uses of Bourne shell commands (cp, mkdir) with shell-agnostic
versions that work from a Windows command prompt. Some Bourne shell
commands still remain in macOS and Linux specific makefile lines.
2022-04-23 15:49:02 +01:00
invertego f7eb4483b2 build: fix zlib include path 2022-04-23 15:49:02 +01:00
shinra-electric 9178761932 Fix typo: type --> typeStr
using `type` results in compiler warnings: `warning: result of comparison against a string literal is unspecified (use an explicit string comparison function instead)` 

Was informed by merryhime that `typeStr` was probably intended.
2022-04-16 20:28:18 +01:00
Luke Usher 235a04d54d nall: prevent chd memory leaks + don't allow unsupported track types 2022-04-16 09:43:33 +01:00
Luke Usher 75c0a5f36e mia: support for loading CHD compressed CD-ROM images 2022-04-16 01:09:02 +01:00
Luke Usher 6de4810ab7 Squashed 'thirdparty/libchdr/' content from commit a03e69319
git-subtree-dir: thirdparty/libchdr
git-subtree-split: a03e69319164f69d781ab8e453f8cf407387bd13
2022-04-15 09:58:55 +01:00
Luke Usher 1a5ab89cd4 Merge commit '6de4810ab78cbdc0f18863b9c3ee2a954c7bb4d5' as 'thirdparty/libchdr' 2022-04-15 09:58:55 +01:00
Luke Usher 4a80dbabcb desktop-ui: minor tweaks to msx keyboard map 2022-04-14 16:06:38 +01:00
Luke Usher 6399a5cd15 nall: sse42 -> sse41 2022-04-11 18:32:13 +01:00
Giovanni Bajo acd2130a4d n64: fix SIGILL at startup when SSE4.2 is not supported
The N64 core was forcing -msse4.2 for compilation of the whole Ares.
On host PCs without SSE 4.2, Ares would crash at startup with SIGILL
because GCC used SSE 4.2 instructions even in hiro, while building up
the UI.

RSP SIMD emulation requires SSE 4.1, but the solution here is to
fallback to SISD if SSE 4.1 is not supported. This can be checked
with a predefined macro, that will be set by GCC. We do compile with
-march=native, so this will reflect the host PC of the build process.
For non-local builds (eg: official CI builds), default to nehalem
(Core 2) which is the first architecture with SSE 4.1.

Since this is yet another compile-time flag that affects the N64 core
performance, add a status message warning if SIMD is disabled.

Fixes #193
2022-04-11 07:55:53 +01:00
Giovanni Bajo b3b32ef026 n64: add missing file for mame RDP SSE2 implementation
Mame RDP has two codepath: one for SSE4.1 and one for SSE2. The latter
relies on some static tables that weren't imported from upstream.
2022-04-11 07:55:53 +01:00
Luke Usher 4ce8290e49 sfc: pad bsx flash to minimum size of a memory cart
Fixes running BS-X content smaller than 1M
2022-04-11 00:00:33 +01:00
Luke Usher fd6698c5f6 sfc: fix a hang when loading Satallaview content 2022-04-10 23:22:49 +01:00
Luke Usher f92605cfbd desktop-ui: add support for using Supergrafx and CD together
The homebrew game "Space Ava 201" does this
2022-04-10 20:42:25 +01:00
Luke Usher 2c3c9fe25f desktop-ui: implement status queue + 'keyboard capture' notice 2022-04-09 10:17:39 +01:00
Luke Usher 18e013beda mia: formatting fixes 2022-04-07 21:55:13 +01:00
Luke Usher 1e26a8be76 msx: improve rom type detection and add more board types 2022-04-07 21:52:15 +01:00
Luke Usher 300fa4801f msx: fix a number of memory layout issues
The results of the "tinyslotchecker" rom are sane now;
it finally reports a valid configuration.
2022-04-07 20:25:28 +01:00
Luke Usher c5106a1982 msx: require a proper bios rom for msx1
This is because C-BIOS has significant compatibility issues, including
the ability to boot any software that uses BASIC.

The MSX2 emulation is still too preliminary to be able to boot the
official bios, so msx2 will continue to use C-BIOS for the time being.
2022-04-07 20:24:37 +01:00
Luke Usher 1d22db7e1c desktop-ui: fix an issue where settings would not persist after previous change 2022-04-06 22:08:45 +01:00
Luke Usher c986a14401 desktop-ui: remap all inputs based on physical controller layouts
Note: you will need to reconfigure your virtual pad after this commit.
2022-04-06 21:29:38 +01:00
Luke Usher a6d3a57df9 gba: slightly reduce red tint, to bring the display closer to my GBA SP 2022-04-06 09:47:33 +01:00
Luke Usher 8d04df1641 desktop-ui: add hotkey to toggle fast forward 2022-04-05 23:23:15 +01:00
Luke Usher 6baebd0f06 msx: update cbios to latest japanese revision
Fixes kana fonts in many games
2022-04-04 23:23:15 +01:00
Luke Usher e34bfc04e3 msx: fix linear cartridge rom mapping
This allows many titles that didn't boot previously to start
2022-04-04 22:07:11 +01:00
Luke Usher 0d7c70bdba tms9918: implement text mode 2022-04-04 21:51:09 +01:00
Luke Usher fccd73f8e3 gb: tweak display timing; fixes dmg-acid2 and cgb-acid2 2022-03-31 18:44:19 +01:00
kev4cards c52c7fd1bb Change inner dead-zone size and geometry
Replace the large, inner circular dead-zone of the N64 control stick with a small, inner square dead-zone; separate the inner and outer dead-zones; attach the scaling equation to the outer dead-zone; fixes https://github.com/ares-emulator/ares/issues/86 .
2022-03-31 09:53:11 +01:00
kev4cards 5210341ad3 Update gamepad.cpp 2022-03-31 09:53:11 +01:00
AmatCoder d7e456a46f hiro: fix menubar visibility with gtk3
Fixing issue #229
2022-03-23 11:31:06 +00:00
Luke Usher a3b126f079 pce: initialise bram for cd-rom system 2022-03-20 21:54:58 +00:00
Giovanni Bajo bc8c308ee9 n64: add support for homebrew-specific special header flag
Nintendo 64 homebrew community is standardizing on a convention to
declare the save memory type as a header flag. This convention has been
first introduced by EverDrive 64 as a way to handle games not present
in their DB, but it's been since adopted by libdragon as well.

With this commit, Ares will automatically configure the correct savetype
for homebrew ROMs using the special header flag.
2022-03-19 10:12:27 +00:00
TascoDLX 124a678c8e m68000: omit illegal addressing modes for CMPA & TST 2022-03-17 09:08:29 +00:00
TascoDLX 333dd85ba5 m68000: fixed group 2 exception prefetch (CHK, DIV by zero) 2022-03-17 09:08:29 +00:00
jbo-85 d08a9bdcc2 sfc: Add database entry for the "Super FX voxel demo" to specify a RAM size of 64k instead of 32k
Support ROM/RAM addressing for Super FX ROMs that are not a power of 2
2022-03-14 22:45:55 +00:00
Luke Usher f4a018036d ruby: fix typo (missing semicolon) in pulseaudio driver 2022-03-14 09:31:34 +00:00
AmatCoder 65f4e176c2 ruby: pulseaudio shouldn't block for events
Now it sets a timeout of one second
2022-03-14 09:14:59 +00:00
Luke Usher 3b8e9bbff5 msx: connect/fix up keyboard emulation
This is implemented via a 'keyboard capture' hotkey; this ensures that
users can switch between keyboard & gamepad emulation, even if they have
no physical gamepad.

When keyboard capture is enabled:
 - All non-hotkey key-presses are translated and dispatched to the guest
 - Virtual GamePad Inputs that are mapped to Keyboard no longer trigger
 - Virtual GamePad inputs that are mapped to Mouse or physical GamePads work normally.
2022-03-10 23:56:01 +00:00
Luke Usher 8f2c6eff9c desktop-ui: fix an issue where System directories were created incorrectly 2022-03-10 21:24:02 +00:00
Luke Usher 85a5292648 desktop-ui: default filter/shader to "None" rather than "Blur" 2022-03-10 19:57:57 +00:00
Luke Usher c8f261201c mia: recompile resources 2022-03-08 19:17:32 +00:00
Luke Usher e42c79677d Merge branch 'master' of https://github.com/ares-emulator/ares 2022-03-08 19:14:59 +00:00
Luke Usher de9ec5d83c mia: oops, title => label 2022-03-08 10:35:27 +00:00
Luke Usher 93e89446e2 mia: update sfc board database & heuristics 2022-03-08 10:04:22 +00:00
Luke Usher 2a28c46a41 desktop-ui: update locate to carry over old settings, explain choices. 2022-03-07 22:00:43 +00:00
Luke Usher 23fa258dfd nall: remove hardcoding of lto=true
This was overriding the given command line preference, making it difficult to build with lto disabled.
2022-03-07 09:59:30 +00:00
invertego e86a18f293 md/32x: add missing initialization during power-on
Nearly all state is initialized to a fixed or random value during
power-on, though a few things are deliberately left alone on soft reset.

A handful of fields weren't being initialized at all, save for the zero
initialization that occurs during process creation. This state would be
persisted from one ROM load to the next.

This fix is intended to address 32x PWM audio eventually going silent
after switching between multiple roms.
2022-03-07 09:32:22 +00:00
Giovanni Bajo 665229a892 macos: codesign binary after build
This is required on Apple Silicon and won't harm on Intel.
2022-03-07 09:21:05 +00:00
Giovanni Bajo 4d46be8344 Add top-level Makefile 2022-03-07 09:21:05 +00:00
Luke Usher 5a839f1010 Revert "sfc: slight ppu performance boost by templating arguments"
This reverts commit d01b8db441.

This was an experimental local change that should've never made it to master
2022-03-05 21:58:33 +00:00
Luke Usher d5dcc645e4 desktop-ui: ensure ares is 'portable' on Windows 2022-03-04 20:09:03 +00:00
Luke Usher 35f6a93713 nall: determine desktop path based on environment 2022-03-04 20:09:03 +00:00
Luke Usher d01b8db441 sfc: slight ppu performance boost by templating arguments 2022-03-04 20:09:03 +00:00
TascoDLX a8373002b5 ares: bump serializer version (md updates) 2022-03-04 20:08:15 +00:00
TascoDLX 5d192fb215 md/32x: readjust cpu sync after recent changes (Kolibri fix) 2022-03-04 20:08:15 +00:00
TascoDLX e13722870e m68000: adjust interrupt/exception timing
*based on Motorola app note AN1012/D. Timing for autovector action is approximated based on MegaDrive h/w tests.
2022-03-04 20:08:15 +00:00
TascoDLX 82e49616a2 md: reimplement refresh timings
*based on research by Mask of Destiny and approximations from h/w tests
2022-03-04 20:08:15 +00:00
TascoDLX 7d425dc5e7 md: vdp vscroll bug implemented 2022-03-04 20:08:15 +00:00
TascoDLX aa975f8f6c md: vdp dma transfer is delayed after bus is acquired 2022-03-04 20:08:15 +00:00
TascoDLX 7fcd6d1f5a md: vdp timing tweaks for accuracy
- vtick() shifted; can't be any later w/o breaking due to render alignment
- vblank flag update moved to vtick(); also updated on v28/v30 switch (per ekeeke's note re: Kabuto's findings)
- corrected apu irq timing
- readded extra refresh slot when display is disabled (confirmed after latest timing fixes)
2022-03-04 20:08:15 +00:00
Luke Usher 9d7c83aa39 Update README.md 2022-03-04 09:02:47 +00:00
Luke Usher 1d8aa3fc3f ares v127 released
ares v127 brings significant improvements to Mega Drive and Nintendo 64
emulation, as well as improvements to NES / Famicom and SNES / Super Famicom.

Other than the usual emulation improvements, there have been the following notable
changes:

**Apple Silicon Support**

ares v127 fixes the recompiler for aarch64 architecture, meaning that it is now
possible to create Apple Silicon/M1 native builds, without relying on Rosetta
and without losing support for the high performance JIT recompilers.

In order to be Apple Silicon Native, it is currently required to compile ares
from source code as automated builds have not yet been configured, but users
who wish to do so will no longer lose functionality or suffer poor performance
as a result.

**MAME RDP**

ares's Nintendo 64 core uses paraLLEl-RDP by default; this brings fast and
accurate RDP emulation as long as Vulkan is present on the users machine; this
meant that Nintendo 64 emulation was completely broken for all configurations
without Vulkan support, including macOS.

ares v127 adds support for MAME's RDP implementation as a fallback, allowing
Nintendo 64 emulation to be used when Vulkan is not present. This is handled
automatically, however, a new option has been added to video settings to allow
Vulkan support to be toggled, giving all users the ability to test the MAME
RDP, if they wish to do so.

Although MAME RDP is now an option, paraLLEl-RDP is still the recommended
choice, for both performance and accuracy.

**Pixel Accuracy Mode**

ares has contains two implementations of some of our emulated hardware; one
optimised for performance, and another optimised for accuracy.
Historically, the choice of which path to use has never been exposed to the
user; higan *always* used the 'accurate' profiles, with ares always opting for
the 'performance' profiles; any user wishing to change this would be required
to compile ares themselves from source.

As of ares v127, we now provide a new option in the emulator settings: "Pixel
Accuracy"; when this is enabled, any emulator core that supports a pixel
accurate mode will use it.

For 99% of games, the default fast profiles will be sufficient, but enabling
"Pixel Accuracy" allows games that require mid-scanline effects, such as the
infamous "Air Strike Patrol" to function properly.

The following systems are currently support the Pixel Accuracy setting:

* NEC - PC-Engine / TurboGrafx
* Nintendo - Super Famicom / SNES

**Changelog:**
* desktop-ui: hook up pc-engine 6-button pads to virtual pads [Luke Usher]
* desktop-ui: implement frame advance [Luke Usher]
* fc: add bus conflicts to cnrom [encoded-byte]
* fc: check for ram on mmc1 [encoded-byte]
* fc: check if ram exists on mmc3 [encoded-byte]
* fc: clear oam address on each scanline [encoded-byte]
* fc: improve mmc3 irq behavior [encoded-byte]
* fc: improve ppu skipped clock timing [encoded-byte]
* fc: use hkrom for mmc6 [encoded-byte]
* m68000: allow recovery from zero divide [TascoDLX]
* m68000: reimplement DBcc instruction with correct timing[TascoDLX]
* md: A few fixes to SRAM save game [rasky]
* md: correct overscan / output when display is off [TascoDLX]
* md: correct reads of CRAM and VSRAM [rasky]
* md: detect region 'K' as NTSC-J [invertego]
* md: fix APU port in [rasky]
* md: fix debug register sprite masking [rasky]
* md: fix high bits in control port read [rasky]
* md: fix misaligned reads from VRAM [rasky]
* md: fix register masked write in mode5 [rasky]
* md: fix vblank bit toggling horizontal timing [rasky]
* md: fix VSRAM out of bound accesses [rasky]
* md: ignore erroneous device string used by Codemasters [invertego]
* md: implement undocumented VDP VRAM 8-bit reading mode [rasky]
* md: persist VDP state on reset [invertego]
* md: restore vdp free slot lost to refresh [TascoDLX]
* mia: Correct save type for Premier Manager 64 (N64) [sp1187]
* mia: Correct save type for Transformers: Beast Wars Transmetals (N64) [sp1187]
* mia: correct type for pak attribute [encoded-byte]
* mia: fix 32x sram [Luke Usher]
* mia: properly pass MD eeprom details to ares [Luke Usher]
* mia: updated famicom database [encoded-byte]
* mos6502: add illegal nops [encoded-byte]
* ms: correct overscan inc. dynamic screen resizing [TascoDLX]
* n64: add MAME RDP as a fallback for parallel-RDP [invertego]
* n64: allow vulkan to be disabled [Luke Usher]
* n64: change PI DMA to use 16 bit fetches [CasualPokePlayer]
* n64: fix mult/div opcode timings [rasky]
* n64: fix RSP halt condition to be more accurate [rasky]
* n64: fix several RDP regressions [invertego]
* n64: fix small bug in VMACQ [rasky]
* n64: fix SRA/SRAV opcodes [rasky]
* n64: fix vulkan detection [Luke Usher]
* n64: improve rsp recompiler pool allocation [invertego]
* n64: swap RSP/RDP order [CasualPokePlayer]
* n64: templatize rsp vpu [invertego]
* n64: vulkan tweaks [Luke Usher]
* nall: fix many compilation warnings on macOS [Luke Usher]
* nall: fix page protection on Apple silicon [invertego]
* nall: rewrite recompiler for machine-independence using sljit [invertego]
* pce: runtime pixel accurate VDP setting [invertego]
* sfc: fix horizontal off-screen test for sprites [jbo-85]
* sfc: fix missing sprite tile on Super Conflict title screen [jbo-85]
* sfc: fix missing sprites in Jurassic Park that are partly offscreen [jbo-85]
* sfc: runtime pixel accurate PPU setting [invertego]
* sh2: move registers into POD struct [invertego]
2022-03-03 11:12:11 +00:00
invertego 7692f102e5 pce: runtime pixel accurate VDP setting 2022-03-03 09:31:59 +00:00
invertego 3be1ced3ef sfc: runtime pixel accurate PPU setting 2022-03-02 09:59:35 +00:00
Luke Usher c78d931e28 Revert "ares: remove performance renderers"
This reverts commit dc5ff13b5c.
2022-02-26 21:59:51 +00:00
TascoDLX e7f24c06d5 m68000: reimplement DBcc instruction with correct timing 2022-02-26 12:13:56 +00:00
Luke Usher dc5ff13b5c ares: remove performance renderers
Some systems in ares contained two implementations of video hardware;
these systems were Mega Drive / Genesis, Super Famicom / SNES, and
PC-Engine / TurboGrafx 16.

For the Mega Drive, we switched to the accuracy core quite some time ago,
SNES and PC-Engine we were still using the performance core.

Going forward, we wish to only maintain the accuracy focused renderers.
2022-02-23 13:04:45 +00:00
Luke Usher 7140b64b13 nall: fix many compilation warnings on macOS 2022-02-23 13:00:45 +00:00
Giovanni Bajo 4d4d3308b9 md: fix debug register sprite masking
VDP always writes transparent pixels to the internal sprite buffers,
overwriting previous transparent pixels; then the first non-transparent
pixel sticks and wins. This implementation detail only reveals itself
when sprite plane masking is activated using the VDP debug register:
in that case, the palette number of transparent pixels concurs in the
AND of the visible pixels, and thus the correct palette number should
be found in the buffer.

Fixes the logo effect of Overdrive 2 (ref #255)
2022-02-23 08:50:24 +00:00
Giovanni Bajo e02a7cc6fb md: fix APU port in
It's technically unused, but it must return 0xFF. Looks like some
game erroneously read it anyway.

Fixes #286
2022-02-23 08:50:13 +00:00
Giovanni Bajo ce981795f5 md: second attempt at vblank bit timing
After more analysis, it looks like the correct thing to do is to
check for vblank status on most of the raster line. Kabuto's doc says
that it is possibly to switch from V30 to V28 during line 224 and
still see the vblank triggered, which suggests that the hardware does
actually check it on most of the time.

This seems to fix #402 and does not seem to cause any immediate
regression in timing-sensitive ROMs.
2022-02-23 08:50:00 +00:00
Giovanni Bajo 51d16a58cd md: fix vblank bit toggling horizontal timing
Currently, the vblank bit is turned on/off at the same time vcounter
is incremented, which is a reasonable assumption, missing any real
data on this.

But it turns out this is responsible for most of the breakage of
Overdrive 1. I did some tests and it looks like anything in the
range >= 0xF0 (same line), or <= 0x80 (on next line) fixes those bugs.
I decided to bind it to vedge(), which means that vblank bit now is
triggered the same instant that VINT is raised, which also makes sense
when you think of it.

Updates #212
2022-02-22 11:05:19 +00:00
TascoDLX 89287dabf1 ms: correct overscan inc. dynamic screen resizing 2022-02-21 08:17:21 +00:00
TascoDLX 5b52f94aa1 md: correct overscan / output when display is off 2022-02-21 08:17:21 +00:00
Luke Usher f67373732c mia: properly pass MD eeprom details to ares 2022-02-21 08:00:10 +00:00
Luke Usher 8d43e67b96 fix eeprom after PR #357 2022-02-20 20:32:44 +00:00
Luke Usher 8a37b00fef mia: fix 32x sram 2022-02-20 20:20:49 +00:00
Luke Usher 80c2678930 desktop-ui: hook up pc-engine 6-button pads to virtual pads 2022-02-18 13:46:07 +00:00
TascoDLX 510cc55d76 m68000: allow recovery from zero divide 2022-02-18 09:15:28 +00:00
TascoDLX 5c285e3ce3 md: restore vdp free slot lost to refresh 2022-02-18 09:15:28 +00:00
Giovanni Bajo 21203b2401 md: fix misaligned reads from VRAM
VRAM misaligned addresses were implemented with partial slot reads.
This seems to be wrong, as proven by vdpfifotesting: once the slot is
read, the whole word is invalidated.
2022-02-17 19:04:06 +00:00
Giovanni Bajo 2c8f3ef84d md: implement undocumented VDP VRAM 8-bit reading mode
Using target 0xC, it is possible to do 8-bit reads from VRAM.
2022-02-17 19:04:06 +00:00
Giovanni Bajo 80348ae691 md: correct reads of CRAM and VSRAM
Reading unmapped bits in CRAM and VSRAM returns a copy of the same bits
in the top slot of the FIFO.
2022-02-17 19:04:06 +00:00
Giovanni Bajo 5e55f1a8a7 md: fix VSRAM out of bound accesses
VSRAM is actually made of 40 11-bit words, though the chip only accesses
the first 10 bits. The top bit on each word is still readable and writable
though, so they should be emulated.

Also, reading at addresses >= 40 returns a copy of the first word,
rather than 0.
2022-02-17 19:04:06 +00:00
Giovanni Bajo c63257029e md: fix register masked write in mode5
Mode5 (SMS compatibility mode) is unsupported and mostly undocumented,
but the vdpfifotesting ROM at least checks one know behavior: non-SMS
registers can't be written.
2022-02-17 19:04:06 +00:00
Giovanni Bajo 93d44072da md: fix high bits in control port read
Bits 10-15 in control port read (aka status register) are not fixed
as found in some online docs, but they are actually an open bus
that returns the instruction prefetched by m68k at that cycle.
2022-02-17 19:04:06 +00:00
Luke Usher 2cf921be41 desktop-ui: implement frame advance 2022-02-16 22:35:17 +00:00
Luke Usher cc8ccbf1bd point to the new ares website 2022-02-16 15:34:01 +00:00
Giovanni Bajo 10e589672f [MD] A few fixes to SRAM save game
* Allow MIA to declare address for mapping (typically from ROM header)
   rather than hardcoding 0x200000.
 * Autoenable SRAM if the ROM size is smaller. Also make the ramEnable
   I/O conditional to the same layout.
 * Add MIA entries for NBA Live 98, NHL 96 and NHL 98, which have a 8-bit
   SRAM not declared in the header.
2022-02-16 10:27:10 +00:00
jbo-85 3c28ecd8b6 sfc: fix missing sprites in Jurassic Park that are partly offscreen 2022-02-14 07:26:10 +00:00
jbo-85 cc64eb50c0 sfc: fix missing sprite tile on Super Conflict title screen; sprites that start on x==256 (offscreen) are considered for the range-tile-over checks 2022-02-14 07:26:10 +00:00
jbo-85 5cb877b49c sfc: fix horizontal off-screen test for sprites; fixes SNES test card Burn-In test, maybe others 2022-02-14 07:26:10 +00:00
CasualPokePlayer 275ba735de change PI DMA to use 16 bit fetches
Using the read<Byte> currently in use breaks DMAs from Flash (breaking Paper Mario, probably others), which always return 0. I assume 8 bit reads are just not allowed for Flash, although I can't verify this myself.
Checking https://github.com/n64dev/cen64/commit/8367698e20cca7eb262779f19c8c7847ae31bb29, it seems that fetches should always be 16 bits anyways, so I presume this is the correct behavior, and fixes DMAs from Flash.
No regressions with the original testrom have occured.
2022-02-12 10:15:37 +00:00
CasualPokePlayer 2b894add40 Swap RSP/RDP order, fixes #348 2022-02-11 12:13:33 +00:00
Luke Usher 58690cd5fc n64: fix vulkan detection 2022-02-09 07:22:20 +00:00
Luke Usher b03da384d8 n64: vulkan tweaks
- introduce a status api, so cores can report status messages to the UI
- avoid calling vulkan-related functions when vulkan is disabled
- show status messages so the user is aware of what RDP implementation is active
- Disabled 'loaded' status message, it prevented the Vulkan messages being shown
2022-02-08 20:34:05 +00:00
invertego f382a18d10 libco: update Windows thread information block
Update the stack base and limit in the thread information block. This is
required to support kernel stack unwinding, which is used for both C++
exception dispatch and setjmp/longjmp on Windows x64 and ARM64.

Add a cothread entry routine that consistently aborts when the user
supplied routine returns. Debugger stack backtraces now stop
consistently at this entry routine.
2022-02-07 08:56:29 +00:00
invertego f63cad6de9 md: ignore erroneous device string used by Codemasters 2022-02-06 16:09:57 +00:00
invertego 34d2c091c7 md: detect region 'K' as NTSC-J
The Korean release of Tiny Toon Adventures specifies its region with a
'K' and, like several other Korean releases, is region locked to
Japanese consoles. It may be the only one with a 'K' specifier, though.
2022-02-03 12:36:32 +00:00
invertego d845582d4a md: persist VDP state on reset
The game Skitchin' performs a fade out effect after reset with the
expectation that VDP state was persisted across the reset.
2022-02-02 09:55:28 +00:00
encoded-byte 9788752bc1 fc: check for ram on mmc1 2022-01-26 20:15:20 +00:00
encoded-byte 5f60ab2dde mia: updated fc database 2022-01-26 20:15:20 +00:00
encoded-byte 628432e75c fc: clear oam address on each scanline 2022-01-26 20:15:20 +00:00
Luke Usher 980e9ed687 n64: allow vulkan to be disabled 2022-01-19 19:52:19 +00:00
Giovanni Bajo e98a313ed6 n64: fix mult/div opcode timings
Taken from NEC VR4300 manual. These are easier than expected to
implement accurately as the CPU doesn't execute them in parallel but
stalls the entire pipeline while they are running.
2022-01-18 09:14:56 +00:00
Giovanni Bajo 90d42d1ea3 n64: fix SRA/SRAV opcodes
These two opcodes were incorrectly ignoring the higher part of the
register before shifting.
2022-01-18 08:02:23 +00:00
Giovanni Bajo 11d6b7c673 rsp: fix small bug in VMACQ
Real hardware testing showed that VMACQ does not modify the accumulator
if it is exactly zero. Fix it.

Also remove two "unconfirmed" comments which I have personally verified.
2022-01-13 08:41:58 +00:00
invertego c04bcf03e0 n64: fix several RDP regressions
- YUV texture fetch and color space conversion
- textured rectangle command parsing
- set primitive depth command parsing
2022-01-12 14:44:39 +00:00
Luke Usher c4d73cc427 Update split-subtrees.yml
Debugging CI action
2022-01-12 11:26:05 +00:00
Luke Usher 8634c11cff Update split-subtrees.yml 2022-01-12 11:22:37 +00:00
Luke Usher 8a5c48e3ed add split-subtrees github action 2022-01-12 11:18:27 +00:00
encoded-byte b22513a6e8 fc: check if ram exists on mmc3 2022-01-05 23:24:10 +00:00
Giovanni Bajo e5220e8fd0 n64: fix RSP halt condition to be more accurate
* Fix usage of break opcode in a delay slot. After unhalt, the
   RSP continues execution, taking the jump if needed. So the
   branch state should not be affected by the break opcode.
 * Reading from SP_PC produces garbage (open bus?) when the RSP is
   running. This fix is unlikely to fix game but may help homebrew
   developers.
 * Writing to SP_PC resets the RSP MIPS pipeline, so any pending branch
   is canceled.
2022-01-03 12:21:45 +00:00
encoded-byte 8099bf54fd mia: updated famicom database 2022-01-01 20:13:57 +00:00
encoded-byte bed4ce3659 fc: use hkrom for mmc6 2022-01-01 20:13:57 +00:00
encoded-byte f630a9418d fc: improve mmc3 irq behavior 2022-01-01 20:13:57 +00:00
invertego f9e4070b15 n64: improve rsp recompiler pool allocation
The existing implementation was allocating pools in the code cache only
to copy them to the heap. This was wasteful on multiple counts: the
space in the cache would go unused until the next allocator flush and
the data copied to the heap consisted almost entirely of zeroes. Best of
all, writing the hash code to the code cache was triggering a page
protection fault on Apple M1.

A small data structure refactor avoids the heap allocations, the copies,
the wasted space in the code cache, and the page protection issue.
2021-12-20 18:16:01 +00:00
invertego 5050d6c45d n64: add MAME RDP as a fallback for parallel-RDP
For systems that do not meet parallel-RDP's Vulkan requirements, use the
pure software RDP implementation from MAME as a fallback.

All of the source files taken from MAME are either BSD-3-Clause licensed
or public domain. Edits were kept to a minimum and guarded by ifdefs to
ease future integrations.
2021-12-20 18:16:01 +00:00
invertego b56dac15e9 recompiler: fix page protection on Apple silicon
- when dynamically allocating executable memory, use VirtualAlloc/mmap()
  for finer control over allocation flags (like MAP_JIT on macOS/arm64)
- toggle JIT memory protection around writes on macOS/arm64
- reduce recompiler code cache sizes to improve likelihood of dynamic
  allocations being close to ares image (affects branch perf)
- remove arch x86_64 override on macOS non-local builds; native arm64
  builds should now be at feature parity with x86_64
- sh2: prevent pollution of code cache with empty pools by invalidate()
2021-12-15 20:01:40 +00:00
invertego a8e35d0299 recompiler: rewrite for machine-independence 2021-12-14 09:02:52 +00:00
invertego 1462bac4c5 sljit: wire up to the build 2021-12-14 09:02:52 +00:00
invertego 5e2a8f08bf n64: templatize rsp vpu 2021-12-14 09:02:52 +00:00
invertego e88cb48f19 sh2: move registers into POD struct 2021-12-14 09:02:52 +00:00
invertego 70a669287b build: arm64 build fixes 2021-12-14 09:02:52 +00:00
invertego 9d3addc241 mia: fix build break 2021-12-14 09:02:52 +00:00
Luke Usher f22e1405dc Squashed 'thirdparty/sljit/' content from commit d6a0fa61e
git-subtree-dir: thirdparty/sljit
git-subtree-split: d6a0fa61e09266ad2e36d8ccd56f775e37b749e9
2021-12-11 19:43:23 +00:00
Luke Usher 4542ac5674 Merge commit 'f22e1405dc12ed4fdc05a3f6a9e5fa7ee966f627' as 'thirdparty/sljit' 2021-12-11 19:43:23 +00:00
encoded-byte 5c3ac88547 mia: updated famicom database 2021-12-10 15:55:35 +00:00
encoded-byte 85fcda5b42 mia: correct type for pak attribute 2021-12-10 15:55:35 +00:00
encoded-byte f512fdc969 fc: add bus conflicts to cnrom 2021-12-10 15:55:35 +00:00
encoded-byte 64286fbd46 fc: improve ppu skipped clock timing 2021-12-06 16:54:50 +00:00
Simon Eriksson e0c4cc76f2 mia: Correct save type for Transformers: Beast Wars Transmetals (N64) 2021-12-03 21:59:50 +00:00
encoded-byte 7b4a346336 component: add illegal nops to mos6502 cpu 2021-12-02 21:49:57 +00:00
Simon Eriksson 763f7da939 mia: Correct save type for Premier Manager 64 (N64) 2021-12-01 20:05:09 +00:00
Luke Usher ee188dcb31 ares: bump version number to v126 2021-11-28 08:00:14 +00:00
encoded-byte 1f8b3f86b9 fc: partial support for bandai datach 2021-11-27 14:30:51 +00:00
encoded-byte 18e334a6cf fc: support for bandai oeka board 2021-11-27 14:30:51 +00:00
encoded-byte 24675b0161 fc: fix saving on bandai lz93d50 + m24c02 2021-11-25 21:33:15 +00:00
encoded-byte f4caedcd5e component: fix eeprom m24c mode selection 2021-11-25 21:33:15 +00:00
encoded-byte bdc6313e46 fc: support for bandai karaoke board 2021-11-25 09:52:14 +00:00
encoded-byte fd3a56b0a2 fc: support for cprom board 2021-11-25 09:52:14 +00:00
encoded-byte 663b6951e3 fc: attach sunsoft 4 + ext rom 2021-11-25 09:52:14 +00:00
encoded-byte 554430276c fc: support for namco 163 board (no sound) 2021-11-22 20:47:23 +00:00
Luke Usher 3748baf8e8 Revert "libco: disable backing up SSE registers on Win64"
This reverts commit 32690bb6f0.

Skipping restoration of SSE registers turned out to be too fragile/risky
2021-11-22 15:11:28 +00:00
encoded-byte e1bd1bfdf9 fc: support txrom variants 2021-11-22 09:06:54 +00:00
encoded-byte 5f6b75a013 fc: support for cnrom with security 2021-11-22 09:06:54 +00:00
encoded-byte 2d6fe4aa16 fc: support for sxrom boards with mmc1a 2021-11-22 09:06:54 +00:00
encoded-byte b49e5496da fc: support for unrom variants 2021-11-22 09:06:54 +00:00
encoded-byte 645d481493 fc: support for bandai lz93d50 variant 2021-11-22 09:06:54 +00:00
Simon Eriksson bc14c35cb5 fc: Support for Action 52 board 2021-11-18 06:40:36 +00:00
encoded-byte 16210cf1bf fc: split bandai fcg / lz93d50 boards
To better describe chips and prepare support for other related boards
2021-11-17 09:04:23 +00:00
encoded-byte d34e54c808 fc: support for bandai 74161 boards 2021-11-17 09:04:23 +00:00
encoded-byte 76508d02bd mia: updated fc database
Games tested so far. Two new not working games discovered:
- Aladdin (Europe): Hangs after starting game
- Wizards & Warriors (Europe): Graphicals glitches on HUD, severe slowdowns. PAL timing related?
2021-11-17 09:04:23 +00:00
Luke Usher 32690bb6f0 libco: disable backing up SSE registers on Win64
For some users, this gives a dramatic performance boost, and finally
brings the Windows builds in-line with Linux/Mac builds in terms of
performance.

This technically goes against the Win64 ABI, which demands that SSE
registers are saved, however, in-practice, our testing has shown that
this has not caused any issues so far.
2021-11-16 11:10:41 +00:00
Simon Eriksson 9eca885d8b fc: Support for Color Dreams board 2021-11-16 06:28:36 +00:00
Luke Usher f9a53d2167 msx: remove rom debug print 2021-11-12 18:28:41 +00:00
Luke Usher fd5b22c5cd msx: use the slot layout and memory expected by cbios 2021-11-12 18:23:21 +00:00
Luke Usher 2f6edc7efe msx: add huristics for rom type detection 2021-11-12 18:22:48 +00:00
invertego 12ac1b5534 hiro: monitor activate messages for window focus
Monitor WM_ACTIVATE instead of WM_SETFOCUS/KILLFOCUS messages to avoid
responding to spurious notifications.
2021-11-11 09:09:50 +00:00
encoded-byte c8fa67ec39 mia: updated fc database
All entries tested and working (except for "Akira")
2021-11-10 22:17:27 +00:00
encoded-byte 5341d0d7d4 fc: support for namco 118 board 2021-11-10 22:17:27 +00:00
encoded-byte ad0105de25 fc: support for namco 175/340 boards 2021-11-10 22:17:27 +00:00
Luke Usher e3663a9eec bump version to v125.1 2021-11-10 21:34:06 +00:00
invertego a01ccb72f2 hiro: track window focus via messages, not polling
On Windows, track WM_SETFOCUS and WM_KILLFOCUS messages to determine
focused status rather than polling with GetForegroundWindow(). The
latter involves a syscall and causes noticeable slowdown when called
repeatedly, such as when GameBoy games poll joypad status in a loop.
2021-11-10 21:32:41 +00:00
Luke Usher 27996d81d4 fc: implement gtrom mapper 2021-11-10 21:01:42 +00:00
invertego 47af07c507 ms, sfc: fix light gun related crashes
Fix unloading systems with light gun peripherals active. The code
responsible for removing crosshair sprites was dereferencing a null
pointer. This cleanup now occurs in Screen::quit() when unloading.
2021-11-10 18:31:51 +00:00
invertego cc6ab702c0 mia: prefer known rom extensions in zip archives
Instead of just reading the first file from a zip archive, prefer files
that match known rom extensions. Extra files such as readmes should not
interfere with the loading of the game.
2021-11-10 11:08:33 +00:00
Luke Usher d633b92a57 v125 2021-11-09 20:20:53 +00:00
Luke Usher 579be2bb04 ms: pass "set VDPbuffer" tests in VDPTEST 2021-11-09 11:45:19 +00:00
Luke Usher 89db771c73 gg: add Mickey Mouse no Castle Illusion (Japan) to game database 2021-11-09 11:00:35 +00:00
invertego 33b95510cb sh2: fix several instructions, default to recompiler
Fix several correctness bugs in SH2 instructions in both the interpreter and
recompiler and switch the default implementation from the cached interpreter to
the recompiler. This brings the 32x games BC Racers and Zaxxon's
Motherbase 2000 to playable status. Fixed instructions:

Interpreter
- ADDC Rm,Rn
- ADDV Rm,Rn

Recompiler
- MAC.W @Rm+,@Rn+

Both
- CMP/STR Rm,Rn
- MOV.B Rm,@-Rn
- MOV.W Rm,@-Rn
- MOV.L Rm,@-Rn
- NEGC Rm,Rn
2021-11-09 08:50:44 +00:00
encoded-byte 31eee5f6f1 fc: pinout support for konami vrc7 2021-11-05 16:25:13 +00:00
encoded-byte 7ba1c2925d mia: add fc konami vrc2/4/6 to database 2021-11-05 16:25:13 +00:00
encoded-byte dbc1b4ccc6 fc: support for konami vrc2 variant 2021-11-05 16:25:13 +00:00
encoded-byte a3a1969775 fc: always check for ram presence
Some games without ram try to read this space, better be safe
2021-11-05 16:25:13 +00:00
encoded-byte ab67ec12cd fc: refactor of jaleco boards 2021-11-03 06:41:59 +00:00
encoded-byte 02cb1268e4 fc: support for jaleco jf13 board 2021-11-03 06:41:59 +00:00
encoded-byte 50994a2c60 fc: support for jaleco fc05 board 2021-11-03 06:41:59 +00:00
encoded-byte 9e099e9b15 fc: remove unneeded test
No need to test rom if board don't support ram
2021-11-03 06:41:59 +00:00
encoded-byte 16cbd8b149 fc: support for jaleco jf17/19 boards 2021-11-03 06:41:59 +00:00
encoded-byte 5491a6a9c8 fc: fix jaleco jf14 banking 2021-11-03 06:41:59 +00:00
encoded-byte d0a14c682d fc: support for irem if12 board 2021-11-01 13:01:30 +00:00
encoded-byte 4eb4b6cdb7 fc: support for irem lrog017 board 2021-11-01 13:01:30 +00:00
encoded-byte 9bc59159d0 fc: check for ram and simplify banking 2021-11-01 13:01:30 +00:00
encoded-byte f518f04ffa mia: database for fc 2021-11-01 13:01:30 +00:00
encoded-byte 2ce06bc4d1 fc: support for irem h3001 board 2021-11-01 13:01:30 +00:00
encoded-byte a3285b6959 fc: support for irem g101 board 2021-11-01 13:01:30 +00:00
jbo_85 8a7ac00d03 snes: Fix 'D-Port B+O+S' test in SPC7110 Check Program as reported in issue #228, this bug was introduced after the huge rewrite to the type system in v117 2021-10-27 08:15:35 +01:00
encoded-byte 38cf1b0f8e fc: fix address 2021-10-26 22:57:57 +01:00
encoded-byte d26ffccc9f fc: add chip type to manifest 2021-10-26 22:57:57 +01:00
encoded-byte 9ee4afd17f fc: support for taito x1-017 board 2021-10-26 22:57:57 +01:00
encoded-byte 61dbb64999 fc: support for taito x1-005 board 2021-10-26 22:57:57 +01:00
encoded-byte 2d5e1ba552 fc: support for taito tc0690 board 2021-10-26 22:57:57 +01:00
encoded-byte a31b0a7768 fc: support for taito tc0190 board 2021-10-26 22:57:57 +01:00
TascoDLX 7c9ff4ba6d md: sram support for Super Hydlide (J) 2021-10-25 09:14:15 +01:00
TascoDLX 0bc30dd26d md: fix interrupt ack special case 2021-10-25 09:14:15 +01:00
TascoDLX f73032e17f mcd: support for 3-button pad (as default) 2021-10-25 09:14:15 +01:00
TascoDLX 2eee9bcd4e mcd: autodetect disc region based on boot code 2021-10-25 09:14:15 +01:00
TascoDLX e3a3927e95 mcd: report error on unhandled cdd command 2021-10-25 09:14:15 +01:00
TascoDLX f04e55f863 mcd: allow continuous cd playback 2021-10-25 09:14:15 +01:00
TascoDLX 08aecccc5a mcd: clean up & fix graphics render 2021-10-25 09:14:15 +01:00
TascoDLX 3471756c06 mcd: reset timer on write 2021-10-25 09:14:15 +01:00
invertego d40e6e1cd3 n64: increase screen canvas to 576 lines
Certain PAL games require this. Affected games include:
- Michael Owen's WLS 2000
- Perfect Dark
- Top Gear Overdrive
2021-10-25 09:13:14 +01:00
encoded-byte 6a262e01ae fc: support for taito tc0690 board 2021-10-25 07:44:40 +01:00
encoded-byte 2f6a51b3ef fc: support for taito tc0190 board 2021-10-25 07:44:40 +01:00
TascoDLX ee3b764b8e ares: bump serializer version for MD changes 2021-10-22 19:16:39 +01:00
TascoDLX 4216d5ae0a md: improved timing/signaling for z80 busreq 2021-10-22 19:16:39 +01:00
TascoDLX 878efe0a05 md: fixed irq issues: timing, delays, ack 2021-10-22 19:16:39 +01:00
Luke Usher 98aee19e93 fc: support expanded bnrom & uxrom
These mappers are used in various homebrew/unlicenced titles
2021-10-21 20:08:23 +01:00
TascoDLX 7810a05b60 md: improved cpu open bus line accuracy 2021-10-21 15:57:15 +01:00
TascoDLX b83e868a6e md: fix z80 bus access & timing issues 2021-10-21 15:57:15 +01:00
TascoDLX ce3153b10e md: prevent sram from masking out high rom 2021-10-21 15:57:15 +01:00
TascoDLX 259642ae2a m68000: fix disassembly of pc-relative addresses 2021-10-21 15:57:15 +01:00
TascoDLX 30921061c7 m68000: restore TAS instruction for cpus other than MD main 2021-10-21 15:57:15 +01:00
TascoDLX 757da94463 m68000: avoid changing interrupt mask on exception 2021-10-21 15:57:15 +01:00
Sintendo 1c026f5edf libco/aarch64: Optimize co_swap_function
Improves thread-switching performance using the following techniques:

- Interleave stores/loads
- Restore the stack pointer and link register as early as possible
2021-10-19 12:15:56 +01:00
Sintendo 2d90b6343d libco/aarch64: Fix vector register handling
The calling convention specifies that d8-d15 (the lower 64 bits of
vector registers q8-q15) are callee-saved. However, libco was
erroneously saving and restoring general-purpose registers x8-x15
instead.
2021-10-19 12:15:56 +01:00
Giovanni Bajo 4c312ab2af Fix linking on old macOS toolchains
Ares JIT recently started to require the data segment to be executable
(see  https://github.com/ares-emulator/ares/pull/200 for details on why
this was done instead of allocating a new segment via mmap).

To do this, it uses mprotect() (bump_allocator::resize), but it also
needs to tell the linker that the data segment can be upgraded to
executable with -Wl,-segprot,__DATA,rwx,rw (nall/GNUmakefile).
Unfortunately, for quite some time, the clang LD had a bug and didn't
accept that option for the data segment.

The official CI has a newer linker without the bug, but for developers
compiling ares with an old toolchain, this small tool will patch the
binary to mark the data segment as potentially executable.
2021-10-19 11:00:23 +01:00
invertego 55d197fdc3 desktop-ui: fix file/folder browser dialog alignment
Align file/folder dialogs to the settings window when appropriate. The
absence of this alignment was triggering asserts in debug builds.
2021-10-19 10:59:51 +01:00
Kawa 53290b9c71 Add screenshot hotkey
As requested in #233
2021-10-17 22:55:49 +01:00
invertego 764a881d36 recompiler: on macOS allow data segment to be executable
Override the data segment's maximum protection from rw to rwx, allowing
mprotect() to be called on recompiler code blocks to make them
executable.
2021-10-17 12:38:14 +01:00
invertego a10e089100 ci: use MSYS2 on Windows, add Windows/Clang build
This change upgrades GCC from the version preinstalled by GitHub Actions
(8.1.0) to the latest MSYS2 version (10.3.0). It also adds a
Windows/Clang build configuration, though the release job still
grabs the GCC build.
2021-10-16 18:59:50 +01:00
TascoDLX 590ec4cb32 Various fixes to CD session handling 2021-10-16 18:59:14 +01:00
TascoDLX 30d143092d Tweak & fix generation of CD subchannel data 2021-10-16 18:59:14 +01:00
TascoDLX 2dbd5a43a0 Improved CD CUEsheet loading to handle PREGAPs & POSTGAPs 2021-10-16 18:59:14 +01:00
Shideravan 08c013dc46 Update README.md 2021-10-15 16:39:36 +01:00
Shideravan 0d169fe641 Adding the ares logo
The resource comes directly from https://ares-emulator.github.io/
This ends the editions in the readme page.
2021-10-15 16:39:36 +01:00
560 changed files with 183418 additions and 8472 deletions

No files matched your search

+34 -10
View File
@@ -11,27 +11,51 @@ jobs:
matrix:
program:
- ares
os:
platform:
- name: windows
version: latest
os: windows-latest
compiler: g++
shell: 'msys2 {0}'
msystem: mingw64
msys-env: x86_64
- name: windows-clang
os: windows-latest
compiler: clang++
shell: 'msys2 {0}'
msystem: clang64
msys-env: clang-x86_64
- name: macos
version: latest
os: macos-latest
compiler: clang++
shell: sh
- name: ubuntu
version: latest
runs-on: ${{ matrix.os.name }}-${{ matrix.os.version }}
os: ubuntu-latest
compiler: g++
shell: sh
name: ${{ matrix.program }}-${{ matrix.platform.name }}
runs-on: ${{ matrix.platform.os }}
defaults:
run:
shell: ${{ matrix.platform.shell }}
steps:
- uses: actions/checkout@v2
- name: Install Dependencies
if: matrix.os.name == 'ubuntu'
- name: Install MSYS2 Dependencies
if: matrix.platform.shell == 'msys2 {0}'
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.platform.msystem }}
install: make mingw-w64-${{ matrix.platform.msys-env }}-toolchain
- 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
- name: Make
run: make -j4 -C desktop-ui build=optimized local=false lto=true
run: make -j4 -C desktop-ui build=optimized local=false lto=true compiler=${{ matrix.platform.compiler }}
- name: Upload
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.program }}-${{ matrix.os.name }}
name: ${{ matrix.program }}-${{ matrix.platform.name }}
path: desktop-ui/out/*
+30
View File
@@ -0,0 +1,30 @@
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]"
+2
View File
@@ -0,0 +1,2 @@
obj/
out/
+6
View File
@@ -0,0 +1,6 @@
all: desktop
desktop:
$(MAKE) -C desktop-ui
.PHONY: all desktop
+133
View File
@@ -1,3 +1,4 @@
----------------------------------------------------------------------
ares
Copyright (c) 2004-2021 ares team, Near et al
@@ -13,3 +14,135 @@ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
----------------------------------------------------------------------
----------------------------------------------------------------------
Stack-less Just-In-Time compiler
Copyright Zoltan Herczeg ([email protected]). All rights reserved.
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.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) 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(S) 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.
----------------------------------------------------------------------
----------------------------------------------------------------------
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
Copyright Romain Tisserand
All rights reserved.
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.
* Neither the name of the <organization> 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 <COPYRIGHT HOLDER> 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
----------------------------------------------------------------------
----------------------------------------------------------------------
LZMA SDK is placed in the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute
the original LZMA SDK code, either in source code form or as a compiled binary,
for any purpose, commercial or non-commercial, and by any means.
----------------------------------------------------------------------
----------------------------------------------------------------------
zlib
(C) 1995-2017 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jean-loup Gailly Mark Adler
[email protected] [email protected]
If you use the zlib library in a product, we would appreciate *not* receiving
lengthy legal documents to sign. The sources are provided for free but without
warranty of any kind. The library has been entirely written by Jean-loup
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.
----------------------------------------------------------------------
+2 -2
View File
@@ -1,4 +1,4 @@
# ares
![ares logo](https://ares-emulator.github.io/images/logo.png)
[![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://github.com/higan-emu/ares/blob/master/LICENSE)
@@ -9,7 +9,7 @@ Official Releases
-----------------
Official releases are available from
[the ares website](https://ares-emulator.github.io).
[the ares website](https://ares-emu.net).
Nightly Builds
--------------
+5 -4
View File
@@ -1,6 +1,7 @@
#pragma once
#include <libco/libco.h>
#include <sljit.h>
#include <nall/platform.hpp>
#include <nall/adaptive-array.hpp>
@@ -37,16 +38,16 @@ using namespace nall;
namespace ares {
static const string Name = "ares";
static const string Version = "124";
static const string Version = "128";
static const string Copyright = "ares team, Near";
static const string License = "ISC";
static const string LicenseURI = "https://opensource.org/licenses/ISC";
static const string Website = "ares-emulator.github.io";
static const string WebsiteURI = "https://ares-emulator.github.io";
static const string Website = "ares-emu.net";
static const string WebsiteURI = "https://ares-emu.net/";
//incremented only when serialization format changes
static const u32 SerializerSignature = 0x31545342; //"BST1" (little-endian)
static const string SerializerVersion = "123.1";
static const string SerializerVersion = "128";
namespace VFS {
using Pak = shared_pointer<vfs::directory>;
+22 -16
View File
@@ -1,16 +1,22 @@
#include <ares/ares.hpp>
namespace ares::Memory {
alignas(4096) u8 fixedBuffer[1_GiB];
FixedAllocator::FixedAllocator() {
_allocator.resize(sizeof(fixedBuffer), 0, fixedBuffer);
}
auto FixedAllocator::get() -> bump_allocator& {
static FixedAllocator allocator;
return allocator._allocator;
}
}
#include <ares/ares.hpp>
namespace ares::Memory {
#if defined(PLATFORM_MACOS) && defined(ARCHITECTURE_ARM64)
//stub for unsupported platforms
FixedAllocator::FixedAllocator() {
}
#else
alignas(4096) u8 fixedBuffer[128_MiB];
FixedAllocator::FixedAllocator() {
_allocator.resize(sizeof(fixedBuffer), 0, fixedBuffer);
}
#endif
auto FixedAllocator::get() -> bump_allocator& {
static FixedAllocator allocator;
return allocator._allocator;
}
}
@@ -27,7 +27,7 @@ struct Instruction : Tracer {
for(auto& history : _history) history = ~0;
}
auto address(u32 address) -> bool {
auto address(u64 address) -> bool {
address &= (1ull << _addressBits) - 1; //mask upper bits of address
_address = address;
address >>= _addressMask; //clip unneeded alignment bits (to reduce _masks size)
@@ -55,7 +55,7 @@ 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(u32 address) -> void {
auto invalidate(u64 address) -> void {
if(unlikely(_mask && updateMasks())) {
address &= (1ull << _addressBits) - 1;
address >>= _addressMask;
+1
View File
@@ -36,6 +36,7 @@ auto Screen::main(uintptr_t) -> void {
auto Screen::quit() -> void {
_kill = true;
_thread.join();
_sprites.reset();
}
auto Screen::power() -> void {
+1
View File
@@ -16,6 +16,7 @@ struct Platform {
virtual auto pak(Node::Object) -> shared_pointer<vfs::directory> { return {}; }
virtual auto event(Event) -> void {}
virtual auto log(string_view message) -> void {}
virtual auto status(string_view message) -> void {}
virtual auto video(Node::Video::Screen, const u32* data, u32 pitch, u32 width, u32 height) -> void {}
virtual auto audio(Node::Audio::Stream) -> void {}
virtual auto input(Node::Input::Input) -> void {}
+6 -2
View File
@@ -1,6 +1,10 @@
build := stable
nall.path := ../../../nall
include $(nall.path)/GNUmakefile
all:
sourcery resource.bml resource.cpp resource.hpp
clean:
rm resource.cpp
rm resource.hpp
$(call delete,resource.cpp)
$(call delete,resource.hpp)
+1 -1
View File
@@ -74,7 +74,7 @@ auto M24C::write() -> void {
case Mode::Device:
if(counter <= 8) {
device = device << 1 | data();
} else if(!select()) {
} else if(select() != Acknowledge) {
mode = Mode::Standby;
} else if(device & 1) {
mode = Mode::Read;
@@ -50,7 +50,7 @@ template<u32 Size> auto M68000::_address(EffectiveAddress& ea) -> string {
if(ea.mode == 2) return {_addressRegister(AddressRegister{ea.reg})};
if(ea.mode == 5) return {"$", hex(_readDisplacement(read(AddressRegister{ea.reg})), 6L)};
if(ea.mode == 6) return {"$", hex(_readIndex(read(AddressRegister{ea.reg})), 6L)};
if(ea.mode == 7) return {"$", hex((i16)_readPC<Word>(), 6L)};
if(ea.mode == 7) { auto imm = _readPC<Word>(); return {"$", imm >= 0x8000 ? hex((i16)imm, 6L, 'f') : hex((i16)imm, 6L, '0') }; }
if(ea.mode == 8) return {"$", hex(_readPC<Long>(), 6L)};
if(ea.mode == 9) return {"$", hex(_pc + (i16)_readPC(), 6L)};
if(ea.mode == 10) return {"$", hex(_readIndex(_pc), 6L)};
@@ -65,7 +65,7 @@ template<u32 Size> auto M68000::_effectiveAddress(EffectiveAddress& ea) -> strin
if(ea.mode == 4) return {"-(", _addressRegister(AddressRegister{ea.reg}), ")"};
if(ea.mode == 5) return {"($", hex(_readDisplacement(read(AddressRegister{ea.reg})), 6L), ")"};
if(ea.mode == 6) return {"($", hex(_readIndex(read(AddressRegister{ea.reg})), 6L), ")"};
if(ea.mode == 7) return {"($", hex((i16)_readPC<Word>(), 6L), ")"};
if(ea.mode == 7) { auto imm = _readPC<Word>(); return {"($", imm >= 0x8000 ? hex((i16)imm, 6L, 'f') : hex((i16)imm, 6L, '0'), ")"}; }
if(ea.mode == 8) return {"($", hex(_readPC<Long>(), 6L), ")"};
if(ea.mode == 9) return {"($", hex(_readDisplacement(_pc), 6L), ")"};
if(ea.mode == 10) return {"($", hex(_readIndex(_pc), 6L), ")"};
@@ -414,6 +414,7 @@ M68000::M68000() {
for(n3 mode : range(8))
for(n3 reg : range(8)) {
auto opcode = pattern("1011 ---+ 11-- ----") | areg << 9 | mode << 3 | reg << 0;
if(mode == 7 && reg >= 5) continue;
AddressRegister with{areg};
EffectiveAddress from{mode, reg};
@@ -1256,7 +1257,7 @@ M68000::M68000() {
for(n3 mode : range(8))
for(n3 reg : range(8)) {
auto opcode = pattern("0100 1010 ++-- ----") | mode << 3 | reg << 0;
if(mode == 7 && reg >= 2) continue;
if(mode == 1 || mode == 7 && reg >= 2) continue;
EffectiveAddress from{mode, reg};
bind(opcode | 0 << 6, TST<Byte>, from);
@@ -332,14 +332,20 @@ auto M68000::instructionCHK(DataRegister compare, EffectiveAddress maximum) -> v
r.z = clip<Word>(target) == 0;
r.n = sign<Word>(target) < 0;
if(r.n) return exception(Exception::BoundsCheck, Vector::BoundsCheck);
if(r.n) {
prefetched();
return exception(Exception::BoundsCheck, Vector::BoundsCheck);
}
auto result = (n64)target - source;
r.c = sign<Word>(result >> 1) < 0;
r.v = sign<Word>((target ^ source) & (target ^ result)) < 0;
r.z = clip<Word>(result) == 0;
r.n = sign<Word>(result) < 0;
if(r.n == r.v && !r.z) return exception(Exception::BoundsCheck, Vector::BoundsCheck);
if(r.n == r.v && !r.z) {
prefetched();
return exception(Exception::BoundsCheck, Vector::BoundsCheck);
}
prefetch();
}
@@ -390,22 +396,30 @@ template<u32 Size> auto M68000::instructionCMPM(EffectiveAddress from, Effective
}
auto M68000::instructionDBCC(n4 test, DataRegister with) -> void {
auto displacement = extension<Word>();
if(condition(test)) {
idle(4);
} else {
idle(2);
r.pc -= 2;
if(!condition(test)) { // cc false
auto disp = sign<Word>(r.irc);
// predict branch
r.pc += disp;
prefetch();
// decrement register
n16 result = read<Word>(with);
write<Word>(with, result - 1);
if(result) {
idle(2);
r.pc -= 4;
r.pc += sign<Word>(displacement);
prefetch();
// branch taken
prefetch();
return;
} else {
idle(2);
// branch not taken
r.pc -= disp;
}
} else { // cc true
idle(2);
r.pc += 2;
}
prefetch();
prefetch();
}
auto M68000::instructionDIVS(EffectiveAddress from, DataRegister with) -> void {
@@ -413,6 +427,7 @@ auto M68000::instructionDIVS(EffectiveAddress from, DataRegister with) -> void {
n32 divisor = read<Word>(from) << 16, odivisor = divisor;
if(divisor == 0) {
prefetched();
return exception(Exception::DivisionByZero, Vector::DivisionByZero);
}
@@ -489,6 +504,7 @@ auto M68000::instructionDIVU(EffectiveAddress from, DataRegister with) -> void {
n32 divisor = read<Word>(from) << 16;
if(divisor == 0) {
prefetched();
return exception(Exception::DivisionByZero, Vector::DivisionByZero);
}
@@ -1262,7 +1278,7 @@ auto M68000::instructionSWAP(DataRegister with) -> void {
auto M68000::instructionTAS(EffectiveAddress with) -> void {
n32 data;
if(with.mode == DataRegisterDirect) {
if(lockable() || with.mode == DataRegisterDirect) {
data = read<Byte, Hold>(with);
prefetch();
write<Byte>(with, data | 0x80);
+22 -7
View File
@@ -50,21 +50,36 @@ auto M68000::supervisor() -> bool {
auto M68000::exception(u32 exception, u32 vector, u32 priority) -> void {
r.stop = false;
idle(10); //todo: not accurate
auto pc = r.pc;
auto sr = readSR();
// register setup (+6 cyc)
idle(6);
n32 pc = r.pc - 4;
n32 sr = readSR();
if(!r.s) swap(r.a[7], r.sp);
r.i = priority;
r.s = 1;
r.t = 0;
push<Long>(pc - 4);
push<Word>(sr);
// push pc low (+4 cyc)
push<Word>(pc & 0x0000ffff);
// external interrupt handling
if(exception == Exception::Interrupt) {
// IACK vector number acquisition (+4 cyc normal or +10 to +18 cyc autovectored)
// & justify vector number (+4 cyc)
idle(16+4); // assuming autovector cycles (approximated for Megadrive)
r.i = priority;
}
// push pc high & sr (+8 cyc)
push<Long>(sr << 16 | pc >> 16);
// read vector address (+8 cyc)
r.pc = read<Long>(vector << 2);
// todo: if the vector address read causes an address error, this exception should be escalated
// prefetch (+8 cyc)
prefetch();
if(exception == Exception::Interrupt) idle(2); // dead cycles (+2 cyc)
prefetch();
}
+4 -2
View File
@@ -9,8 +9,10 @@ struct M68000 {
virtual auto wait(u32 clocks) -> void = 0;
virtual auto read(n1 upper, n1 lower, n24 address, n16 data = 0) -> n16 = 0;
virtual auto write(n1 upper, n1 lower, n24 address, n16 data) -> void = 0;
virtual auto lockable() -> bool { return true; }
auto ird() const -> n16 { return r.ird; }
auto irc() const -> n16 { return r.irc; }
enum : bool { User, Supervisor };
enum : u32 { Byte, Word, Long };
@@ -70,8 +72,8 @@ struct M68000 {
M68000();
auto power() -> void;
auto supervisor() -> bool;
auto exception(u32 exception, u32 vector, u32 priority = 7) -> void;
auto interrupt(u32 vector, u32 priority = 7) -> void;
auto exception(u32 exception, u32 vector, u32 priority = 0) -> void;
auto interrupt(u32 vector, u32 priority = 0) -> void;
//registers.cpp
struct DataRegister {
@@ -57,19 +57,24 @@ auto MOS6502::disassembleInstruction(maybe<n16> _pc) -> string {
switch(auto opcode = readDebugger(pc)) {
op(0x00, "brk", immediate)
op(0x01, "ora", indirectX)
op(0x04, "nop", zeroPage)
op(0x05, "ora", zeroPage)
op(0x06, "asl", zeroPage)
op(0x08, "php", implied)
op(0x09, "ora", immediate)
op(0x0a, "asl", implied)
op(0x0c, "nop", absolute)
op(0x0d, "ora", absolute)
op(0x0e, "asl", absolute)
op(0x10, "bpl", branch)
op(0x11, "ora", indirectY)
op(0x14, "nop", zeroPageX)
op(0x15, "ora", zeroPageX)
op(0x16, "asl", zeroPageX)
op(0x18, "clc", implied)
op(0x19, "ora", absoluteY)
op(0x1a, "nop", implied)
op(0x1c, "nop", absoluteX)
op(0x1d, "ora", absoluteX)
op(0x1e, "asl", absoluteX)
op(0x20, "jsr", absolute)
@@ -85,14 +90,18 @@ auto MOS6502::disassembleInstruction(maybe<n16> _pc) -> string {
op(0x2e, "rol", absolute)
op(0x30, "bmi", branch)
op(0x31, "and", indirectY)
op(0x34, "nop", zeroPageX)
op(0x35, "and", zeroPageX)
op(0x36, "rol", zeroPageX)
op(0x38, "sec", implied)
op(0x39, "and", absoluteY)
op(0x3a, "nop", implied)
op(0x3c, "nop", absoluteX)
op(0x3d, "and", absoluteX)
op(0x3e, "rol", absoluteX)
op(0x40, "rti", implied)
op(0x41, "eor", indirectX)
op(0x44, "nop", zeroPage)
op(0x45, "eor", zeroPage)
op(0x46, "lsr", zeroPage)
op(0x48, "pha", implied)
@@ -103,14 +112,18 @@ auto MOS6502::disassembleInstruction(maybe<n16> _pc) -> string {
op(0x4e, "lsr", absolute)
op(0x50, "bvc", branch)
op(0x51, "eor", indirectY)
op(0x54, "nop", zeroPageX)
op(0x55, "eor", zeroPageX)
op(0x56, "lsr", zeroPageX)
op(0x58, "cli", implied)
op(0x59, "eor", absoluteY)
op(0x5a, "nop", implied)
op(0x5c, "nop", absoluteX)
op(0x5d, "eor", absoluteX)
op(0x5e, "lsr", absoluteX)
op(0x60, "rts", implied)
op(0x61, "adc", indirectX)
op(0x64, "nop", zeroPage)
op(0x65, "adc", zeroPage)
op(0x66, "ror", zeroPage)
op(0x68, "pla", implied)
@@ -121,17 +134,23 @@ auto MOS6502::disassembleInstruction(maybe<n16> _pc) -> string {
op(0x6e, "ror", absolute)
op(0x70, "bvs", branch)
op(0x71, "adc", indirectY)
op(0x74, "nop", zeroPageX)
op(0x75, "adc", zeroPageX)
op(0x76, "ror", zeroPageX)
op(0x78, "sei", implied)
op(0x79, "adc", absoluteY)
op(0x7a, "nop", implied)
op(0x7c, "nop", absoluteX)
op(0x7d, "adc", absoluteX)
op(0x7e, "ror", absoluteX)
op(0x80, "nop", immediate)
op(0x81, "sta", indirectX)
op(0x82, "nop", immediate)
op(0x84, "sty", zeroPage)
op(0x85, "sta", zeroPage)
op(0x86, "stx", zeroPage)
op(0x88, "dey", implied)
op(0x89, "nop", immediate)
op(0x8a, "txa", implied)
op(0x8c, "sty", absolute)
op(0x8d, "sta", absolute)
@@ -170,6 +189,7 @@ auto MOS6502::disassembleInstruction(maybe<n16> _pc) -> string {
op(0xbe, "ldx", absoluteY)
op(0xc0, "cpy", immediate)
op(0xc1, "cmp", indirectX)
op(0xc2, "nop", immediate)
op(0xc4, "cpy", zeroPage)
op(0xc5, "cmp", zeroPage)
op(0xc6, "dec", zeroPage)
@@ -181,14 +201,18 @@ auto MOS6502::disassembleInstruction(maybe<n16> _pc) -> string {
op(0xce, "dec", absolute)
op(0xd0, "bne", branch)
op(0xd1, "cmp", indirectY)
op(0xd4, "nop", zeroPageX)
op(0xd5, "cmp", zeroPageX)
op(0xd6, "dec", zeroPageX)
op(0xd8, "cld", implied)
op(0xd9, "cmp", absoluteY)
op(0xda, "nop", implied)
op(0xdc, "nop", absoluteX)
op(0xdd, "cmp", absoluteX)
op(0xde, "dec", absoluteX)
op(0xe0, "cpx", immediate)
op(0xe1, "sbc", indirectX)
op(0xe2, "nop", immediate)
op(0xe4, "cpx", zeroPage)
op(0xe5, "sbc", zeroPage)
op(0xe6, "inc", zeroPage)
@@ -200,10 +224,13 @@ auto MOS6502::disassembleInstruction(maybe<n16> _pc) -> string {
op(0xee, "inc", absolute)
op(0xf0, "beq", branch)
op(0xf1, "sbc", indirectY)
op(0xf4, "nop", zeroPageX)
op(0xf5, "sbc", zeroPageX)
op(0xf6, "inc", zeroPageX)
op(0xf8, "sed", implied)
op(0xf9, "sbc", absoluteY)
op(0xfa, "nop", implied)
op(0xfc, "nop", absoluteX)
op(0xfd, "sbc", absoluteX)
op(0xfe, "inc", absoluteX)
@@ -20,19 +20,24 @@ auto MOS6502::instruction() -> void {
switch(code) {
op(0x00, Break)
op(0x01, IndirectXRead, fp(ORA), A)
op(0x04, NoOperationZeroPage)
op(0x05, ZeroPageRead, fp(ORA), A)
op(0x06, ZeroPageModify, fp(ASL))
op(0x08, PushP)
op(0x09, Immediate, fp(ORA), A)
op(0x0a, Implied, fp(ASL), A)
op(0x0c, NoOperationAbsolute)
op(0x0d, AbsoluteRead, fp(ORA), A)
op(0x0e, AbsoluteModify, fp(ASL))
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(0x18, Clear, C)
op(0x19, AbsoluteRead, fp(ORA), A, Y)
op(0x1a, NoOperation)
op(0x1c, NoOperationAbsolute, X)
op(0x1d, AbsoluteRead, fp(ORA), A, X)
op(0x1e, AbsoluteModify, fp(ASL), X)
op(0x20, CallAbsolute)
@@ -48,14 +53,18 @@ auto MOS6502::instruction() -> void {
op(0x2e, AbsoluteModify, fp(ROL))
op(0x30, Branch, N == 1)
op(0x31, IndirectYRead, fp(AND), A)
op(0x34, NoOperationZeroPage, X)
op(0x35, ZeroPageRead, fp(AND), A, X)
op(0x36, ZeroPageModify, fp(ROL), X)
op(0x38, Set, C)
op(0x39, AbsoluteRead, fp(AND), A, Y)
op(0x3a, NoOperation)
op(0x3c, NoOperationAbsolute, X)
op(0x3d, AbsoluteRead, fp(AND), A, X)
op(0x3e, AbsoluteModify, fp(ROL), X)
op(0x40, ReturnInterrupt)
op(0x41, IndirectXRead, fp(EOR), A)
op(0x44, NoOperationZeroPage)
op(0x45, ZeroPageRead, fp(EOR), A)
op(0x46, ZeroPageModify, fp(LSR))
op(0x48, Push, A)
@@ -66,14 +75,18 @@ auto MOS6502::instruction() -> void {
op(0x4e, AbsoluteModify, fp(LSR))
op(0x50, Branch, V == 0)
op(0x51, IndirectYRead, fp(EOR), A)
op(0x54, NoOperationZeroPage, X)
op(0x55, ZeroPageRead, fp(EOR), A, X)
op(0x56, ZeroPageModify, fp(LSR), X)
op(0x58, Clear, I)
op(0x59, AbsoluteRead, fp(EOR), A, Y)
op(0x5a, NoOperation)
op(0x5c, NoOperationAbsolute, X)
op(0x5d, AbsoluteRead, fp(EOR), A, X)
op(0x5e, AbsoluteModify, fp(LSR), X)
op(0x60, ReturnSubroutine)
op(0x61, IndirectXRead, fp(ADC), A)
op(0x64, NoOperationZeroPage)
op(0x65, ZeroPageRead, fp(ADC), A)
op(0x66, ZeroPageModify, fp(ROR))
op(0x68, Pull, A)
@@ -84,17 +97,23 @@ auto MOS6502::instruction() -> void {
op(0x6e, AbsoluteModify, fp(ROR))
op(0x70, Branch, V == 1)
op(0x71, IndirectYRead, fp(ADC), A)
op(0x74, NoOperationZeroPage, X)
op(0x75, ZeroPageRead, fp(ADC), A, X)
op(0x76, ZeroPageModify, fp(ROR), X)
op(0x78, Set, I)
op(0x79, AbsoluteRead, fp(ADC), A, Y)
op(0x7a, NoOperation)
op(0x7c, NoOperationAbsolute, X)
op(0x7d, AbsoluteRead, fp(ADC), A, X)
op(0x7e, AbsoluteModify, fp(ROR), X)
op(0x80, NoOperationImmediate)
op(0x81, IndirectXWrite, A)
op(0x82, NoOperationImmediate)
op(0x84, ZeroPageWrite, Y)
op(0x85, ZeroPageWrite, A)
op(0x86, ZeroPageWrite, X)
op(0x88, Implied, fp(DEC), Y)
op(0x89, NoOperationImmediate)
op(0x8a, Transfer, X, A, 1)
op(0x8c, AbsoluteWrite, Y)
op(0x8d, AbsoluteWrite, A)
@@ -133,6 +152,7 @@ auto MOS6502::instruction() -> void {
op(0xbe, AbsoluteRead, fp(LD), X, Y)
op(0xc0, Immediate, fp(CPY), Y)
op(0xc1, IndirectXRead, fp(CMP), A)
op(0xc2, NoOperationImmediate)
op(0xc4, ZeroPageRead, fp(CPY), Y)
op(0xc5, ZeroPageRead, fp(CMP), A)
op(0xc6, ZeroPageModify, fp(DEC))
@@ -144,14 +164,18 @@ auto MOS6502::instruction() -> void {
op(0xce, AbsoluteModify, fp(DEC))
op(0xd0, Branch, Z == 0)
op(0xd1, IndirectYRead, fp(CMP), A)
op(0xd4, NoOperationZeroPage, X)
op(0xd5, ZeroPageRead, fp(CMP), A, X)
op(0xd6, ZeroPageModify, fp(DEC), X)
op(0xd8, Clear, D)
op(0xd9, AbsoluteRead, fp(CMP), A, Y)
op(0xda, NoOperation)
op(0xdc, NoOperationAbsolute, X)
op(0xdd, AbsoluteRead, fp(CMP), A, X)
op(0xde, AbsoluteModify, fp(DEC), X)
op(0xe0, Immediate, fp(CPX), X)
op(0xe1, IndirectXRead, fp(SBC), A)
op(0xe2, NoOperationImmediate)
op(0xe4, ZeroPageRead, fp(CPX), X)
op(0xe5, ZeroPageRead, fp(SBC), A)
op(0xe6, ZeroPageModify, fp(INC))
@@ -163,10 +187,13 @@ auto MOS6502::instruction() -> void {
op(0xee, AbsoluteModify, fp(INC))
op(0xf0, Branch, Z == 1)
op(0xf1, IndirectYRead, fp(SBC), A)
op(0xf4, NoOperationZeroPage, X)
op(0xf5, ZeroPageRead, fp(SBC), A, X)
op(0xf6, ZeroPageModify, fp(INC), X)
op(0xf8, Set, D)
op(0xf9, AbsoluteRead, fp(SBC), A, Y)
op(0xfa, NoOperation)
op(0xfc, NoOperationAbsolute, X)
op(0xfd, AbsoluteRead, fp(SBC), A, X)
op(0xfe, AbsoluteModify, fp(INC), X)
}
@@ -139,6 +139,34 @@ auto MOS6502::instructionNoOperation() -> void {
L idle();
}
auto MOS6502::instructionNoOperationAbsolute() -> void {
n16 absolute = operand();
absolute |= operand() << 8;
L read(absolute);
}
auto MOS6502::instructionNoOperationAbsolute(n8 index) -> void {
n16 absolute = operand();
absolute |= operand() << 8;
idlePageCrossed(absolute, absolute + index);
L read(absolute + index);
}
auto MOS6502::instructionNoOperationImmediate() -> void {
L operand();
}
auto MOS6502::instructionNoOperationZeroPage() -> void {
auto zeroPage = operand();
L load(zeroPage);
}
auto MOS6502::instructionNoOperationZeroPage(n8 index) -> void {
auto zeroPage = operand();
load(zeroPage);
L load(zeroPage + index);
}
auto MOS6502::instructionPull(n8& data) -> void {
idle();
idle();
@@ -70,6 +70,11 @@ struct MOS6502 {
auto instructionJumpAbsolute() -> void;
auto instructionJumpIndirect() -> void;
auto instructionNoOperation() -> void;
auto instructionNoOperationAbsolute() -> void;
auto instructionNoOperationAbsolute(n8 index) -> void;
auto instructionNoOperationImmediate() -> void;
auto instructionNoOperationZeroPage() -> void;
auto instructionNoOperationZeroPage(n8 index) -> void;
auto instructionPull(n8& data) -> void;
auto instructionPullP() -> void;
auto instructionPush(n8& data) -> void;
+25 -12
View File
@@ -1,3 +1,11 @@
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));
@@ -7,7 +15,9 @@ auto SH2::Recompiler::pool(u32 address) -> Pool* {
auto SH2::Recompiler::block(u32 address) -> Block* {
if(auto block = pool(address)->blocks[address >> 1 & 0x7f]) return block;
auto block = emit(address);
return pool(address)->blocks[address >> 1 & 0x7f] = block;
pool(address)->blocks[address >> 1 & 0x7f] = block;
memory::jitprotect(true);
return block;
}
alwaysinline auto SH2::Recompiler::emitInstruction(u16 opcode) -> bool {
@@ -25,34 +35,37 @@ alwaysinline auto SH2::Recompiler::emitInstruction(u16 opcode) -> bool {
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));
block->code = allocator.acquire();
bind({block->code, allocator.available()});
beginFunction(2);
bool hasBranched = 0;
while(true) {
u16 instruction = self.readWord(address);
bool branched = emitInstruction(instruction);
mov(rax, mem64(&self.CCR));
inc(rax);
mov(mem64(&self.CCR), rax);
call(&SH2::instructionEpilogue, &self);
add64(CCR, CCR, imm(1));
call(&SH2::instructionEpilogue);
address += 2;
if(hasBranched || (address & 0xfe) == 0) break; //block boundary
hasBranched = branched;
test(al, al);
jz(imm8(1));
ret();
testJumpEpilog();
}
ret();
jumpEpilog();
memory::jitprotect(false);
block->code = endFunction();
allocator.reserve(size());
return block;
}
#undef CCR
+1 -1
View File
@@ -45,7 +45,7 @@ auto SH2::instruction() -> void {
}
}
auto SH2::instructionEpilogue() -> bool {
auto SH2::instructionEpilogue() -> s32 {
switch(PPM) {
case Branch::Step: PC = PC + 2; return 0;
case Branch::Slot: PC = PC + 2; PPM = Branch::Take; return 0;
+20 -10
View File
@@ -5,9 +5,10 @@ auto SH2::ADD(u32 m, u32 n) -> void {
//ADDC Rm,Rn
auto SH2::ADDC(u32 m, u32 n) -> void {
bool c = (u64)R[n] + R[m] >> 32;
R[n] = R[n] + R[m] + SR.T;
SR.T = c;
u32 a = R[n];
u32 b = a + R[m];
R[n] = b + SR.T;
SR.T = a > b || b > R[n];
}
//ADD #imm,Rn
@@ -17,9 +18,11 @@ auto SH2::ADDI(u32 i, u32 n) -> void {
//ADDV Rm,Rn
auto SH2::ADDV(u32 m, u32 n) -> void {
bool v = ~(R[n] ^ R[m]) & (R[n] ^ R[n] + R[m]) >> 31;
u32 d = ((s32)R[n] < 0);
u32 s = ((s32)R[m] < 0) + d;
R[n] += R[m];
SR.T = v;
u32 r = ((s32)R[n] < 0) + d;
SR.T = s != 1 ? r == 1 : 0;
}
//AND Rm,Rn
@@ -140,7 +143,11 @@ auto SH2::CMPPZ(u32 n) -> void {
//CMP/STR Rm,Rn
auto SH2::CMPSTR(u32 m, u32 n) -> void {
SR.T = bool(R[n] ^ R[m]);
u32 t = R[n] ^ R[m];
SR.T = !(t & 0xff << 24)
|| !(t & 0xff << 16)
|| !(t & 0xff << 8)
|| !(t & 0xff);
}
//DIV0S Rm,Rn
@@ -353,8 +360,9 @@ auto SH2::MOVBLG(u32 d) -> void {
//MOV.B Rm,@-Rn
auto SH2::MOVBM(u32 m, u32 n) -> void {
u32 t = R[m];
R[n] -= 1;
writeByte(R[n], R[m]);
writeByte(R[n], t);
}
//MOV.B @Rm+,Rn
@@ -405,8 +413,9 @@ auto SH2::MOVWLG(u32 d) -> void {
//MOV.W Rm,@-Rn
auto SH2::MOVWM(u32 m, u32 n) -> void {
u32 t = R[m];
R[n] -= 2;
writeWord(R[n], R[m]);
writeWord(R[n], t);
}
//MOV.W @Rm+,Rn
@@ -457,8 +466,9 @@ auto SH2::MOVLLG(u32 d) -> void {
//MOV.L Rm,@-Rn
auto SH2::MOVLM(u32 m, u32 n) -> void {
u32 t = R[m];
R[n] -= 4;
writeLong(R[n], R[m]);
writeLong(R[n], t);
}
//MOV.L @Rm+,Rn
@@ -536,7 +546,7 @@ auto SH2::NEG(u32 m, u32 n) -> void {
auto SH2::NEGC(u32 m, u32 n) -> void {
u32 t = 0 - R[m];
R[n] = t - SR.T;
SR.T = (s32)t >= 0 || t < R[n];
SR.T = 0 < t || t < R[n];
}
//NOP
File diff suppressed because it is too large. Load diff
+37 -5
View File
@@ -3,14 +3,26 @@
namespace ares {
#define SP R[15]
#define SP R[15]
#define R regs.R
#define PC regs.PC
#define PR regs.PR
#define GBR regs.GBR
#define VBR regs.VBR
#define MAC regs.MAC
#define MACL regs.MACL
#define MACH regs.MACH
#define CCR regs.CCR
#define SR regs.SR
#define PPC regs.PPC
#define PPM regs.PPM
#define ET regs.ET
#define ID regs.ID
#include "sh7604/sh7604.cpp"
#include "exceptions.cpp"
#include "instruction.cpp"
#include "instructions.cpp"
#include "cached.cpp"
//#include "recompiler.cpp"
#include "serialization.cpp"
#include "disassembler.cpp"
@@ -30,6 +42,7 @@ auto SH2::power(bool reset) -> void {
SR.M = undefined;
PPC = 0;
PPM = Branch::Step;
ET = 0;
ID = 0;
exceptions = !reset ? ResetCold : ResetWarm;
@@ -47,10 +60,29 @@ auto SH2::power(bool reset) -> void {
cache.power();
if constexpr(Accuracy::Recompiler) {
auto buffer = ares::Memory::FixedAllocator::get().acquire(512_MiB);
recompiler.allocator.resize(512_MiB, bump_allocator::executable | bump_allocator::zero_fill, buffer);
auto buffer = ares::Memory::FixedAllocator::get().tryAcquire(64_MiB);
recompiler.allocator.resize(64_MiB, bump_allocator::executable | bump_allocator::zero_fill, buffer);
recompiler.reset();
}
}
#undef SP
#undef R
#undef PC
#undef PR
#undef GBR
#undef VBR
#undef MAC
#undef MACL
#undef MACH
#undef CCR
#undef SR
#undef PPC
#undef PPM
#undef ET
#undef ID
//#include "cached.cpp"
#include "recompiler.cpp"
}
+26 -37
View File
@@ -1,6 +1,6 @@
#pragma once
#include <nall/recompiler/amd64/amd64.hpp>
#include <nall/recompiler/generic/generic.hpp>
//Hitachi SH-2
@@ -16,7 +16,7 @@ struct SH2 {
virtual auto busWriteLong(u32 address, u32 data) -> void = 0;
auto inDelaySlot() const -> bool {
return PPM != Branch::Step;
return regs.PPM != Branch::Step;
}
//sh2.cpp
@@ -39,7 +39,7 @@ struct SH2 {
auto jump(u32 pc) -> void;
auto branch(u32 pc) -> void;
auto delaySlot(u32 pc) -> void;
auto instructionEpilogue() -> bool;
auto instructionEpilogue() -> s32;
auto instruction() -> void;
auto execute(u16 opcode) -> void;
@@ -220,21 +220,23 @@ struct SH2 {
u32 M;
};
u32 R[16]; //general purpose registers
u32 PC; //program counter
u32 PR; //procedure register
u32 GBR; //global base register
u32 VBR; //vector base register
union {
u64 MAC; //multiply-and-accumulate register
struct { u32 order_msb2(MACH, MACL); };
};
u32 CCR; //clock counter register
S32 SR; //status register
u32 PPC; //program counter for delay slots
u32 PPM; //delay slot mode
u32 ET; //exception triggered flag
u32 ID; //interrupts disabled flag
struct Registers {
u32 R[16]; //general purpose registers
u32 PC; //program counter
u32 PR; //procedure register
u32 GBR; //global base register
u32 VBR; //vector base register
union {
u64 MAC; //multiply-and-accumulate register
struct { u32 order_msb2(MACH, MACL); };
};
u32 CCR; //clock counter register
S32 SR; //status register
u32 PPC; //program counter for delay slots
u32 PPM; //delay slot mode
u32 ET; //exception triggered flag
u32 ID; //interrupts disabled flag
} regs;
enum : u32 {
ResetCold = 1 << 0,
@@ -244,14 +246,13 @@ struct SH2 {
};
u32 exceptions = 0; //delayed exception flags
struct Recompiler : recompiler::amd64 {
using recompiler::amd64::call;
struct Recompiler : recompiler::generic {
SH2& self;
Recompiler(SH2& self) : self(self) {}
Recompiler(SH2& self) : self(self), generic(allocator) {}
struct Block {
auto execute(SH2& self) -> void {
((void (*)(u32*, SH2*))code)(&self.R[0], &self);
((void (*)(SH2*, Registers*))code)(&self, &self.regs);
}
u8* code;
@@ -265,25 +266,13 @@ struct SH2 {
for(u32 index : range(1 << 24)) pools[index] = nullptr;
}
auto invalidate(u32 address) -> void {
pool(address)->blocks[address >> 1 & 0x7f] = nullptr;
}
auto invalidate(u32 address) -> void;
auto pool(u32 address) -> Pool*;
auto block(u32 address) -> Block*;
auto emit(u32 address) -> Block*;
auto emitInstruction(u16 opcode) -> bool;
template<typename V, typename... P>
alwaysinline auto call(V (SH2::*function)(P...)) -> void {
static_assert(sizeof...(P) <= 5);
if constexpr(ABI::Windows) {
if constexpr(sizeof...(P) >= 5) mov(dis8(rsp, 0x28), ra5);
if constexpr(sizeof...(P) >= 4) mov(dis8(rsp, 0x20), ra4);
}
mov(ra0, rbp);
call(imm64{function}, rax);
}
auto getSR(reg dst) -> void;
auto setSR(reg src) -> void;
bump_allocator allocator;
Pool* pools[1 << 24];
+19 -1
View File
@@ -14,7 +14,25 @@ auto TMS9918::Background::run(n8 hoffset, n8 voffset) -> void {
}
auto TMS9918::Background::text1(n8 hoffset, n8 voffset) -> void {
debug(unimplemented, "[TMS9918::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,13) = io.nameTableAddress;
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;
n3 index = 7 - (x % 6);
if(self.vram.read(patternAddress).bit(index)) {
output.color = self.dac.io.colorForeground;
}
}
auto TMS9918::Background::graphics1(n8 hoffset, n8 voffset) -> void {
+3
View File
@@ -32,6 +32,9 @@ auto TMS9918::Sprite::setup(n8 voffset) -> void {
}
auto TMS9918::Sprite::run(n8 hoffset, n8 voffset) -> void {
// Text mode does not support sprites
if (self.videoMode() == 1) return;
output = {};
n4 color;
+64
View File
@@ -0,0 +1,64 @@
struct Bandai74161 : Interface {
static auto create(string id) -> Interface* {
if(id == "BANDAI-74161" ) return new Bandai74161(Revision::B74161);
if(id == "BANDAI-74161A") return new Bandai74161(Revision::B74161A);
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
enum class Revision : u32 {
B74161,
B74161A,
} revision;
Bandai74161(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
mirror = pak->attribute("mirror") == "vertical";
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
n3 bank = (address < 0xc000 ? programBank : (n3)0x7);
return programROM.read(bank << 14 | (n14)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
characterBank = data.bit(0,3);
programBank = data.bit(4,6);
nametableBank = data.bit(7);
}
auto addressCIRAM(n32 address) const -> n32 {
if(revision == Revision::B74161A) {
return nametableBank << 10 | (n10)address;
}
return address >> !mirror & 0x0400 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
return characterROM.read(characterBank << 13 | (n13)address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
}
auto serialize(serializer& s) -> void override {
s(mirror);
s(programBank);
s(characterBank);
s(nametableBank);
}
n1 mirror;
n3 programBank;
n4 characterBank;
n1 nametableBank;
};
+35 -78
View File
@@ -6,123 +6,80 @@ struct BandaiFCG : Interface {
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
Memory::Writable<n8> characterRAM;
M24C eeprom;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
Interface::load(characterRAM, "character.ram");
if(auto fp = pak->read("save.eeprom")) {
eeprom.load(M24C::Type::X24C01);
fp->read({eeprom.memory, eeprom.size()});
}
}
auto save() -> void override {
Interface::save(characterRAM, "save.ram");
if(auto fp = pak->write("save.eeprom")) {
fp->write({eeprom.memory, eeprom.size()});
}
}
auto main() -> void override {
if(irqCounterEnable) {
if(irqEnable) {
if(--irqCounter == 0xffff) {
cpu.irqLine(1);
irqCounterEnable = false;
irqEnable = false;
}
}
tick();
}
auto addressCIRAM(n32 address) const -> n32 {
switch(mirror) {
case 0: return address >> 0 & 0x0400 | address & 0x03ff;
case 1: return address >> 1 & 0x0400 | address & 0x03ff;
case 2: return 0x0000 | address & 0x03ff;
case 3: return 0x0400 | address & 0x03ff;
}
unreachable;
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address >= 0x6000 && address <= 0x7fff) {
data.bit(4) = eeprom.read();
return data;
}
if(address & 0x8000) {
n1 region = bool(address & 0x4000);
n4 bank = (region == 0 ? programBank : (n4)0x0f);
return programROM.read(bank << 14 | (n14)address);
}
return data;
if(address < 0x8000) return data;
n4 bank = (address < 0xc000 ? programBank : (n4)0x0f);
return programROM.read(bank << 14 | (n14)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address >= 0x6000) {
switch(address & 0xf) {
case 0x0: characterBank[0] = data; break;
case 0x1: characterBank[1] = data; break;
case 0x2: characterBank[2] = data; break;
case 0x3: characterBank[3] = data; break;
case 0x4: characterBank[4] = data; break;
case 0x5: characterBank[5] = data; break;
case 0x6: characterBank[6] = data; break;
case 0x7: characterBank[7] = data; break;
case 0x8: programBank = data.bit(0,3); break;
case 0x9: mirror = data.bit(0,1); break;
case 0xa:
cpu.irqLine(0);
irqCounterEnable = data.bit(0);
irqCounter = irqLatch;
break;
case 0xb: irqLatch.byte(0) = data; break;
case 0xc: irqLatch.byte(1) = data; break;
case 0xd:
eeprom.clock = data.bit(5);
eeprom.data = data.bit(6);
eeprom.write();
break;
}
switch(address & 0xe00f) {
case 0x6000: characterBank[0] = data; break;
case 0x6001: characterBank[1] = data; break;
case 0x6002: characterBank[2] = data; break;
case 0x6003: characterBank[3] = data; break;
case 0x6004: characterBank[4] = data; break;
case 0x6005: characterBank[5] = data; break;
case 0x6006: characterBank[6] = data; break;
case 0x6007: characterBank[7] = data; break;
case 0x6008: programBank = data.bit(0,3); break;
case 0x6009: mirror = data.bit(0,1); break;
case 0x600a:
irqEnable = data.bit(0);
cpu.irqLine(0);
break;
case 0x600b: irqCounter.byte(0) = data; break;
case 0x600c: irqCounter.byte(1) = data; break;
}
}
auto addressCIRAM(n32 address) const -> n32 {
switch(mirror) {
case 0: return address >> 0 & 0x0400 | (n10)address;
case 1: return address >> 1 & 0x0400 | (n10)address;
case 2: return 0x0000 | (n10)address;
case 3: return 0x0400 | (n10)address;
}
unreachable;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
address = characterBank[address >> 10] << 10 | (n10)address;
if(characterROM) return characterROM.read(address);
if(characterRAM) return characterRAM.read(address);
return data;
return characterROM.read(address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
address = characterBank[address >> 10] << 10 | (n10)address;
if(characterRAM) return characterRAM.write(address, data);
}
auto power() -> void override {
eeprom.power();
}
auto serialize(serializer& s) -> void override {
s(characterRAM);
s(eeprom);
s(characterBank);
s(programBank);
s(mirror);
s(irqCounterEnable);
s(irqEnable);
s(irqCounter);
s(irqLatch);
}
n8 characterBank[8];
n4 programBank;
n2 mirror;
n1 irqCounterEnable;
n1 irqEnable;
n16 irqCounter;
n16 irqLatch;
};
@@ -0,0 +1,69 @@
struct BandaiKaraoke : Interface {
static auto create(string id) -> Interface* {
if(id == "BANDAI-KARAOKE") return new BandaiKaraoke;
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> optionROM;
Memory::Writable<n8> characterRAM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(optionROM, "option.rom");
Interface::load(characterRAM, "character.ram");
}
auto save() -> void override {
Interface::save(characterRAM, "character.ram");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x6000) return data;
if(address < 0x8000) {
data.bit(0) = 1; //A button
data.bit(1) = 1; //B button
//data.bit(2) = 1; //1-bit ADC
return data;
}
if(address < 0xc000) {
if(!optionEnable) return programROM.read(programBank << 14 | (n14)address);
if(optionROM) return optionROM.read(programBank << 14 | (n14)address);
return data;
}
return programROM.read(0xf << 14 | (n14)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
programBank = data.bit(0,3);
optionEnable = !data.bit(4);
mirror = data.bit(5);
}
auto addressCIRAM(n32 address) -> n32 {
return address >> mirror & 0x0400 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
return characterRAM.read(address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
return characterRAM.write(address, data);
}
auto serialize(serializer& s) -> void override {
s(characterRAM);
s(programBank);
s(optionEnable);
s(mirror);
}
n4 programBank;
n1 optionEnable;
n1 mirror;
};
+139
View File
@@ -0,0 +1,139 @@
struct BandaiLZ93D50 : Interface {
static auto create(string id) -> Interface* {
if(id == "BANDAI-LZ93D50") return new BandaiLZ93D50;
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Writable<n8> programRAM;
Memory::Readable<n8> characterROM;
Memory::Writable<n8> characterRAM;
M24C eeprom;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(programRAM, "save.ram");
Interface::load(characterROM, "character.rom");
Interface::load(characterRAM, "character.ram");
if(auto fp = pak->read("save.eeprom")) {
if(fp->size() == 128) eeprom.load(M24C::Type::X24C01);
if(fp->size() == 256) eeprom.load(M24C::Type::M24C02);
if(eeprom) fp->read({eeprom.memory, eeprom.size()});
}
}
auto save() -> void override {
Interface::save(programRAM, "save.ram");
Interface::save(characterRAM, "character.ram");
if(auto fp = pak->write("save.eeprom")) {
if(eeprom) fp->write({eeprom.memory, eeprom.size()});
}
}
auto main() -> void override {
if(irqEnable) {
if(--irqCounter == 0xffff) {
cpu.irqLine(1);
irqEnable = false;
}
}
tick();
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x6000) return data;
if(address < 0x8000) {
if(programRAM && ramEnable) return programRAM.read((n13)address);
if(eeprom) data.bit(4) = eeprom.read();
return data;
}
n5 bank = (address < 0xc000 ? (n5)programBank : (n5)0xf);
if(characterRAM) bank.bit(4) = bool(programOuterBank);
return programROM.read(bank << 14 | (n14)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x6000) return;
if(address < 0x8000) {
if(programRAM && ramEnable) return programRAM.write((n13)address, data);
}
switch(address & 0x800f) {
case 0x8000: characterBank[0] = data; programOuterBank.bit(0) = data.bit(0); break;
case 0x8001: characterBank[1] = data; programOuterBank.bit(1) = data.bit(0); break;
case 0x8002: characterBank[2] = data; programOuterBank.bit(2) = data.bit(0); break;
case 0x8003: characterBank[3] = data; programOuterBank.bit(3) = data.bit(0); break;
case 0x8004: characterBank[4] = data; break;
case 0x8005: characterBank[5] = data; break;
case 0x8006: characterBank[6] = data; break;
case 0x8007: characterBank[7] = data; break;
case 0x8008: programBank = data.bit(0,3); break;
case 0x8009: mirror = data.bit(0,1); break;
case 0x800a:
irqEnable = data.bit(0);
irqCounter = irqLatch;
cpu.irqLine(0);
break;
case 0x800b: irqLatch.byte(0) = data; break;
case 0x800c: irqLatch.byte(1) = data; break;
case 0x800d:
if(eeprom) {
eeprom.clock = data.bit(5);
eeprom.data = data.bit(6);
eeprom.write();
}
ramEnable = data.bit(5);
break;
}
}
auto addressCIRAM(n32 address) const -> n32 {
switch(mirror) {
case 0: return address >> 0 & 0x0400 | (n10)address;
case 1: return address >> 1 & 0x0400 | (n10)address;
case 2: return 0x0000 | (n10)address;
case 3: return 0x0400 | (n10)address;
}
unreachable;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
if(characterRAM) return characterRAM.read(address);
address = characterBank[address >> 10] << 10 | (n10)address;
return characterROM.read(address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
if(characterRAM) return characterRAM.write(address, data);
}
auto power() -> void override {
eeprom.power();
}
auto serialize(serializer& s) -> void override {
s(programRAM);
s(characterRAM);
s(eeprom);
s(characterBank);
s(programBank);
s(programOuterBank);
s(mirror);
s(ramEnable);
s(irqEnable);
s(irqCounter);
s(irqLatch);
}
n8 characterBank[8];
n4 programBank;
n4 programOuterBank;
n2 mirror;
n1 ramEnable;
n1 irqEnable;
n16 irqCounter;
n16 irqLatch;
};
+76
View File
@@ -0,0 +1,76 @@
struct BandaiOeka : Interface {
static auto create(string id) -> Interface* {
if(id == "BANDAI-OEKA") return new BandaiOeka;
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Writable<n8> characterRAM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterRAM, "character.ram");
mirror = pak->attribute("mirror") == "vertical";
}
auto save() -> void override {
Interface::save(characterRAM, "character.ram");
}
auto addressTest(n32 address) -> void {
if((characterAddress >> 12) != 2 && (address >> 12) == 2) {
characterBank.bit(0,1) = address >> 8 & 3;
}
characterAddress = address;
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
return programROM.read(programBank << 15 | (n15)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address == 0x2006) {
if(++characterLatch) addressTest(data << 8);
}
if(address < 0x8000) return;
programBank = data.bit(0,1);
characterBank.bit(2) = data.bit(2);
}
auto addressCHR(n32 address) const -> n32 {
n3 bank = (address < 0x1000) ? characterBank : n3(characterBank & 4 | 3);
return bank << 12 | (n12)address;
}
auto addressCIRAM(n32 address) const -> n32 {
return address >> !mirror & 0x0400 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
addressTest(address);
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
return characterRAM.read(addressCHR(address));
}
auto writeCHR(n32 address, n8 data) -> void override {
addressTest(address);
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
return characterRAM.write(addressCHR(address), data);
}
auto serialize(serializer& s) -> void override {
s(characterRAM);
s(mirror);
s(programBank);
s(characterBank);
s(characterLatch);
s(characterAddress);
}
n1 mirror;
n2 programBank;
n3 characterBank;
n1 characterLatch;
n32 characterAddress;
};
+44 -6
View File
@@ -1,8 +1,17 @@
namespace Board {
#include "bandai-74161.cpp"
#include "bandai-fcg.cpp"
#include "jaleco-jf.cpp"
#include "jaleco-jf11-jf14.cpp"
#include "bandai-karaoke.cpp"
#include "bandai-lz93d50.cpp"
#include "bandai-oeka.cpp"
#include "colordreams-74x377.cpp"
#include "gtrom.cpp"
#include "jaleco-jf05.cpp"
#include "jaleco-jf11.cpp"
#include "jaleco-jf16.cpp"
#include "jaleco-jf17.cpp"
#include "jaleco-jf23.cpp"
#include "konami-vrc1.cpp"
#include "konami-vrc2.cpp"
#include "konami-vrc3.cpp"
@@ -13,7 +22,6 @@ namespace Board {
#include "hvc-axrom.cpp"
#include "hvc-bnrom.cpp"
#include "hvc-cnrom.cpp"
#include "hvc-dxrom.cpp"
#include "hvc-exrom.cpp"
#include "hvc-fmr.cpp"
#include "hvc-fxrom.cpp"
@@ -24,20 +32,36 @@ namespace Board {
#include "hvc-sxrom.cpp"
#include "hvc-txrom.cpp"
#include "hvc-uxrom.cpp"
#include "irem-g101.cpp"
#include "irem-h3001.cpp"
#include "irem-lrog017.cpp"
#include "irem-tam-s1.cpp"
#include "mlt-action52.cpp"
#include "namco-118.cpp"
#include "namco-163.cpp"
#include "namco-340.cpp"
#include "sunsoft-1.cpp"
#include "sunsoft-2.cpp"
#include "sunsoft-3.cpp"
#include "sunsoft-4.cpp"
#include "sunsoft-5b.cpp"
#include "taito-tc0190.cpp"
#include "taito-tc0690.cpp"
#include "taito-x1-005.cpp"
#include "taito-x1-017.cpp"
auto Interface::create(string board) -> Interface* {
Interface* p = nullptr;
if(!p) p = Bandai74161::create(board);
if(!p) p = BandaiFCG::create(board);
if(!p) p = BandaiKaraoke::create(board);
if(!p) p = BandaiLZ93D50::create(board);
if(!p) p = BandaiOeka::create(board);
if(!p) p = ColorDreams_74x377::create(board);
if(!p) p = GTROM::create(board);
if(!p) p = HVC_AxROM::create(board);
if(!p) p = HVC_BNROM::create(board);
if(!p) p = HVC_CNROM::create(board);
if(!p) p = HVC_DxROM::create(board);
if(!p) p = HVC_ExROM::create(board);
if(!p) p = HVC_FMR::create(board);
if(!p) p = HVC_FxROM::create(board);
@@ -48,9 +72,15 @@ auto Interface::create(string board) -> Interface* {
if(!p) p = HVC_SxROM::create(board);
if(!p) p = HVC_TxROM::create(board);
if(!p) p = HVC_UxROM::create(board);
if(!p) p = IremG101::create(board);
if(!p) p = IremH3001::create(board);
if(!p) p = IremLROG017::create(board);
if(!p) p = IremTAMS1::create(board);
if(!p) p = JalecoJF::create(board);
if(!p) p = Jaleco_JF11_JF14::create(board);
if(!p) p = JalecoJF05::create(board);
if(!p) p = JalecoJF11::create(board);
if(!p) p = JalecoJF16::create(board);
if(!p) p = JalecoJF17::create(board);
if(!p) p = JalecoJF23::create(board);
if(!p) p = KonamiVRC1::create(board);
if(!p) p = KonamiVRC2::create(board);
if(!p) p = KonamiVRC3::create(board);
@@ -58,11 +88,19 @@ auto Interface::create(string board) -> Interface* {
if(!p) p = KonamiVRC5::create(board);
if(!p) p = KonamiVRC6::create(board);
if(!p) p = KonamiVRC7::create(board);
if(!p) p = MltAction52::create(board);
if(!p) p = Namco118::create(board);
if(!p) p = Namco163::create(board);
if(!p) p = Namco340::create(board);
if(!p) p = Sunsoft1::create(board);
if(!p) p = Sunsoft2::create(board);
if(!p) p = Sunsoft3::create(board);
if(!p) p = Sunsoft4::create(board);
if(!p) p = Sunsoft5B::create(board);
if(!p) p = TaitoTC0190::create(board);
if(!p) p = TaitoTC0690::create(board);
if(!p) p = TaitoX1005::create(board);
if(!p) p = TaitoX1017::create(board);
if(!p) p = new Interface;
return p;
}
@@ -0,0 +1,66 @@
struct ColorDreams_74x377 : Interface {
static auto create(string id) -> Interface* {
if(id == "COLORDREAMS-74*377") return new ColorDreams_74x377();
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
Memory::Writable<n8> characterRAM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
Interface::load(characterRAM, "character.ram");
mirror = pak->attribute("mirror") == "vertical";
}
auto save() -> void override {
Interface::save(characterRAM, "character.ram");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
return programROM.read(programBank << 15 | (n15)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
programBank = data.bit(0,1);
characterBank = data.bit(4,7);
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) {
address = address >> !mirror & 0x0400 | (n10)address;
return ppu.readCIRAM(address);
}
address = characterBank << 13 | (n13)address;
if(characterROM) return characterROM.read(address);
if(characterRAM) return characterRAM.read(address);
return data;
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) {
address = address >> !mirror & 0x0400 | (n10)address;
return ppu.writeCIRAM(address, data);
}
address = characterBank << 13 | (n13)address;
if(characterRAM) return characterRAM.write(address, data);
}
auto power() -> void override {
}
auto serialize(serializer& s) -> void override {
s(characterRAM);
s(programBank);
s(characterBank);
s(mirror);
}
n2 programBank;
n4 characterBank;
n1 mirror;
};
+63
View File
@@ -0,0 +1,63 @@
struct GTROM : Interface {
static auto create(string id) -> Interface* {
if(id == "GTROM" ) return new GTROM();
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Writable<n8> characterRAM;
Memory::Writable<n8> videoRAM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterRAM, "character.ram");
videoRAM.allocate(16_KiB);
}
auto save() -> void override {
Interface::save(characterRAM, "character.ram");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
return programROM.read(programBank << 15 | (n15)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address >= 0x5000 && address <= 0x5fff) {
programBank = data.bit(0, 3);
characterBank = data.bit(4);
videoBank = data.bit(5);
return;
}
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return videoRAM.read(videoBank << 13 | (n13)address);
if(characterRAM) return characterRAM.read(characterBank << 13 | (n13)address);
return data;
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return videoRAM.write(videoBank << 13 | (n13)address, data);
return characterRAM.write(characterBank << 13 | (n13)address, data);
}
auto power() -> void override {
programBank = 0;
characterBank = 0;
videoBank = 0;
}
auto serialize(serializer& s) -> void override {
s(characterRAM);
s(videoRAM);
s(programBank);
s(characterBank);
s(videoBank);
}
n4 programBank;
n1 characterBank;
n1 videoBank;
};
+2 -2
View File
@@ -26,7 +26,7 @@ struct HVC_BNROM : Interface {
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
programBank = data.bit(0,1);
programBank = data;
}
auto readCHR(n32 address, n8 data) -> n8 override {
@@ -57,5 +57,5 @@ struct HVC_BNROM : Interface {
}
n1 mirror; //0 = horizontal, 1 = vertical
n2 programBank;
n8 programBank;
};
+31 -10
View File
@@ -1,6 +1,8 @@
struct HVC_CNROM : Interface {
static auto create(string id) -> Interface* {
if(id == "HVC-CNROM") return new HVC_CNROM;
if(id == "HVC-CNROM" ) return new HVC_CNROM(Revision::CNROM);
if(id == "HVC-CNROM-SEC") return new HVC_CNROM(Revision::CNROMS);
if(id == "HVC-CPROM" ) return new HVC_CNROM(Revision::CPROM);
return nullptr;
}
@@ -8,11 +10,20 @@ struct HVC_CNROM : Interface {
Memory::Readable<n8> characterROM;
Memory::Writable<n8> characterRAM;
enum class Revision : u32 {
CNROM,
CNROMS,
CPROM,
} revision;
HVC_CNROM(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
Interface::load(characterRAM, "character.ram");
mirror = pak->attribute("mirror") == "vertical";
key = pak->attribute("chip/key").natural();
}
auto save() -> void override {
@@ -26,7 +37,8 @@ struct HVC_CNROM : Interface {
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
characterBank = data.bit(0,1);
characterBank = data & programROM.read((n15)address);
characterEnable = (data == key);
}
auto readCHR(n32 address, n8 data) -> n8 override {
@@ -34,10 +46,16 @@ struct HVC_CNROM : Interface {
address = address >> !mirror & 0x0400 | (n10)address;
return ppu.readCIRAM(address);
}
if(revision == Revision::CPROM) {
n2 bank = (address < 0x1000) ? (n2)0 : characterBank;
return characterRAM.read(bank << 12 | (n12)address);
}
if(revision == Revision::CNROMS) {
if(!characterEnable) return 0xff;
return characterROM.read((n13)address);
}
address = characterBank << 13 | (n13)address;
if(characterROM) return characterROM.read(address);
if(characterRAM) return characterRAM.read(address);
return data;
return characterROM.read(address);
}
auto writeCHR(n32 address, n8 data) -> void override {
@@ -45,19 +63,22 @@ struct HVC_CNROM : Interface {
address = address >> !mirror & 0x0400 | (n10)address;
return ppu.writeCIRAM(address, data);
}
address = characterBank << 13 | (n13)address;
if(characterRAM) return characterRAM.write(address, data);
}
auto power() -> void override {
if(revision == Revision::CPROM) {
n2 bank = (address < 0x1000) ? (n2)0 : characterBank;
return characterRAM.write(bank << 12 | (n12)address, data);
}
}
auto serialize(serializer& s) -> void override {
s(characterRAM);
s(mirror);
s(key);
s(characterBank);
s(characterEnable);
}
n1 mirror; //0 = horizontal, 1 = vertical
n8 key;
n2 characterBank;
n1 characterEnable;
};
-94
View File
@@ -1,94 +0,0 @@
struct HVC_DxROM : Interface {
static auto create(string id) -> Interface* {
if(id == "HVC-DEROM" ) return new HVC_DxROM(Revision::DEROM);
if(id == "HVC-DE1ROM") return new HVC_DxROM(Revision::DE1ROM);
if(id == "HVC-DRROM" ) return new HVC_DxROM(Revision::DRROM);
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
Memory::Writable<n8> characterCIRAM;
enum class Revision : u32 {
DEROM,
DE1ROM,
DRROM,
} revision;
HVC_DxROM(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
Interface::load(characterCIRAM, "character.ram");
}
auto save() -> void override {
Interface::save(characterCIRAM, "character.ram");
}
auto readPRG(n32 address, n8 data) -> n8 override {
switch(address) {
case 0x8000 ... 0x9fff: return programROM.read(programBank[0] << 13 | (n13)address);
case 0xa000 ... 0xbfff: return programROM.read(programBank[1] << 13 | (n13)address);
case 0xc000 ... 0xdfff: return programROM.read(0x0e << 13 | (n13)address);
case 0xe000 ... 0xffff: return programROM.read(0x0f << 13 | (n13)address);
}
return data;
}
auto writePRG(n32 address, n8 data) -> void override {
switch(address & 0xe001) {
case 0x8000:
bankSelect = data.bit(0,2);
break;
case 0x8001:
switch(bankSelect) {
case 0: characterBank[0] = data & ~1; break;
case 1: characterBank[1] = data & ~1; break;
case 2: characterBank[2] = data; break;
case 3: characterBank[3] = data; break;
case 4: characterBank[4] = data; break;
case 5: characterBank[5] = data; break;
case 6: programBank[0] = data; break;
case 7: programBank[1] = data; break;
}
break;
}
}
auto readCHR(n32 address, n8 data) -> n8 override {
switch(address) {
case 0x0000 ... 0x07ff: return characterROM.read(characterBank[0] << 10 | (n11)address);
case 0x0800 ... 0x0fff: return characterROM.read(characterBank[1] << 10 | (n11)address);
case 0x1000 ... 0x13ff: return characterROM.read(characterBank[2] << 10 | (n10)address);
case 0x1400 ... 0x17ff: return characterROM.read(characterBank[3] << 10 | (n10)address);
case 0x1800 ... 0x1bff: return characterROM.read(characterBank[4] << 10 | (n10)address);
case 0x1c00 ... 0x1fff: return characterROM.read(characterBank[5] << 10 | (n10)address);
case 0x2000 ... 0x27ff: return ppu.readCIRAM((n11)address);
case 0x2800 ... 0x2fff: return characterCIRAM.read((n11)address);
}
return data;
}
auto writeCHR(n32 address, n8 data) -> void override {
switch(address) {
case 0x2000 ... 0x27ff: return ppu.writeCIRAM((n11)address, data);
case 0x2800 ... 0x2fff: return characterCIRAM.write((n11)address, data);
}
}
auto power() -> void override {
}
auto serialize(serializer& s) -> void override {
s(bankSelect);
s(programBank);
s(characterBank);
}
n3 bankSelect;
n4 programBank[2];
n6 characterBank[6];
};
+7 -3
View File
@@ -31,8 +31,9 @@ struct HVC_HKROM : Interface { //MMC6
if(!(characterAddress & 0x1000) && (address & 0x1000)) {
if(irqDelay == 0) {
if(irqCounter == 0) {
irqCounter = irqLatch;
} else if(--irqCounter == 0) {
irqCounter = irqLatch + 1;
}
if(--irqCounter == 0) {
if(irqEnable) irqLine = 1;
}
}
@@ -64,6 +65,7 @@ struct HVC_HKROM : Interface { //MMC6
}
auto writePRG(n32 address, n8 data) -> void override {
if(address == 0x2006 && ++characterLatch) irqTest(data << 8);
if(address < 0x7000) return;
if(address < 0x8000) {
@@ -179,6 +181,7 @@ struct HVC_HKROM : Interface { //MMC6
s(irqEnable);
s(irqDelay);
s(irqLine);
s(characterLatch);
s(characterAddress);
}
@@ -194,7 +197,8 @@ struct HVC_HKROM : Interface { //MMC6
n8 irqLatch;
n8 irqCounter;
n1 irqEnable;
n1 irqDelay;
n8 irqDelay;
n1 irqLine;
n1 characterLatch;
n16 characterAddress;
};
+11 -3
View File
@@ -69,7 +69,13 @@ struct HVC_SxROM : Interface { //MMC1
HVC_SxROM(Revision revision) : revision(revision) {}
auto load() -> void override {
auto chip = pak->attribute("chip");
chipRevision = ChipRevision::MMC1B2;
if(chip == "MMC1" ) chipRevision = ChipRevision::MMC1;
if(chip == "MMC1A" ) chipRevision = ChipRevision::MMC1A;
if(chip == "MMC1B1") chipRevision = ChipRevision::MMC1B1;
if(chip == "MMC1B3") chipRevision = ChipRevision::MMC1B3;
if(chip == "MMC1C" ) chipRevision = ChipRevision::MMC1C;
Interface::load(programROM, "program.rom");
Interface::load(programRAM, "save.ram");
@@ -130,7 +136,7 @@ struct HVC_SxROM : Interface { //MMC1
if(revision == Revision::SNROM) {
if(characterBank[0].bit(4)) return data;
}
if(ramDisable) return 0x00;
if(!programRAM || ramDisable) return 0x00;
return programRAM.read(addressProgramRAM(address));
}
@@ -146,7 +152,7 @@ struct HVC_SxROM : Interface { //MMC1
if(revision == Revision::SNROM) {
if(characterBank[0].bit(4)) return;
}
if(ramDisable) return;
if(!programRAM || ramDisable) return;
return programRAM.write(addressProgramRAM(address), data);
}
@@ -180,7 +186,9 @@ struct HVC_SxROM : Interface { //MMC1
break;
case 3:
programBank = shiftValue.bit(0,3);
ramDisable = shiftValue.bit(4);
if(chipRevision > ChipRevision::MMC1A) {
ramDisable = shiftValue.bit(4);
}
break;
}
}
+44 -6
View File
@@ -65,8 +65,9 @@ struct HVC_TxROM : Interface { //MMC3
if(!(characterAddress & 0x1000) && (address & 0x1000)) {
if(irqDelay == 0) {
if(irqCounter == 0) {
irqCounter = irqLatch;
} else if(--irqCounter == 0) {
irqCounter = irqLatch + 1;
}
if(--irqCounter == 0) {
if(irqEnable) irqLine = 1;
}
}
@@ -79,7 +80,7 @@ struct HVC_TxROM : Interface { //MMC3
if(address < 0x6000) return data;
if(address < 0x8000) {
if(!ramEnable) return data;
if(!ramEnable || !programRAM) return data;
return programRAM.read((n13)address);
}
@@ -95,10 +96,11 @@ struct HVC_TxROM : Interface { //MMC3
}
auto writePRG(n32 address, n8 data) -> void override {
if(address == 0x2006 && ++characterLatch) irqTest(data << 8);
if(address < 0x6000) return;
if(address < 0x8000) {
if(!ramEnable || !ramWritable) return;
if(!ramEnable || !ramWritable || !programRAM) return;
return programRAM.write((n13)address, data);
}
@@ -163,20 +165,54 @@ struct HVC_TxROM : Interface { //MMC3
}
auto addressCIRAM(n32 address) const -> n32 {
if(revision == Revision::TKSROM || revision == Revision::TLSROM) {
address.bit(12) = 0;
if(characterMode == 0) {
if(address <= 0x27ff) return characterBank[0].bit(7) << 10 | (n10)address;
if(address <= 0x2fff) return characterBank[1].bit(7) << 10 | (n10)address;
} else {
if(address <= 0x23ff) return characterBank[2].bit(7) << 10 | (n10)address;
if(address <= 0x27ff) return characterBank[3].bit(7) << 10 | (n10)address;
if(address <= 0x2bff) return characterBank[4].bit(7) << 10 | (n10)address;
if(address <= 0x2fff) return characterBank[5].bit(7) << 10 | (n10)address;
}
unreachable;
}
return address >> mirror & 0x0400 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
irqTest(address);
if(revision == Revision::TVROM) {
if(address < 0x2000) return characterROM.read(addressCHR(address));
address.bit(12) = 0;
if(address < 0x2800) return ppu.readCIRAM((n11)address);
return characterRAM.read((n11)address);
}
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
if(characterROM) return characterROM.read(addressCHR(address));
if(revision == Revision::TQROM) {
address = addressCHR(address);
if(address < 0x10000) return characterROM.read(address);
return characterRAM.read(address);
}
if(characterRAM) return characterRAM.read(addressCHR(address));
return data;
return characterROM.read(addressCHR(address));
}
auto writeCHR(n32 address, n8 data) -> void override {
irqTest(address);
if(revision == Revision::TVROM) {
if(address < 0x2000) return;
address.bit(12) = 0;
if(address < 0x2800) return ppu.writeCIRAM((n11)address, data);
return characterRAM.write((n11)address, data);
}
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
if(revision == Revision::TQROM) {
address = addressCHR(address);
if(address < 0x10000) return;
return characterRAM.write(address, data);
}
if(characterRAM) return characterRAM.write(addressCHR(address), data);
}
@@ -201,6 +237,7 @@ struct HVC_TxROM : Interface { //MMC3
s(irqEnable);
s(irqDelay);
s(irqLine);
s(characterLatch);
s(characterAddress);
}
@@ -217,5 +254,6 @@ struct HVC_TxROM : Interface { //MMC3
n1 irqEnable;
n8 irqDelay;
n1 irqLine;
n1 characterLatch;
n16 characterAddress;
};
+14 -5
View File
@@ -1,7 +1,9 @@
struct HVC_UxROM : Interface {
static auto create(string id) -> Interface* {
if(id == "HVC-UNROM") return new HVC_UxROM(Revision::UNROM);
if(id == "HVC-UOROM") return new HVC_UxROM(Revision::UOROM);
if(id == "HVC-UNROM" ) return new HVC_UxROM(Revision::UNROM);
if(id == "HVC-UNROMA") return new HVC_UxROM(Revision::UNROMA);
if(id == "HVC-UN1ROM") return new HVC_UxROM(Revision::UN1ROM);
if(id == "HVC-UOROM" ) return new HVC_UxROM(Revision::UOROM);
return nullptr;
}
@@ -11,6 +13,8 @@ struct HVC_UxROM : Interface {
enum class Revision : u32 {
UNROM,
UNROMA,
UN1ROM,
UOROM,
} revision;
@@ -29,13 +33,18 @@ struct HVC_UxROM : Interface {
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
n4 bank = (address < 0xc000 ? programBank : (n4)0xf);
n8 bank;
switch(address >> 14 & 1) {
case 0: bank = (revision == Revision::UNROMA ? (n8)0x00 : programBank); break;
case 1: bank = (revision == Revision::UNROMA ? programBank : (n8)0xff); break;
}
return programROM.read(bank << 14 | (n14)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
programBank = data.bit(0,3);
programBank = data;
if(revision == Revision::UN1ROM) programBank >>= 2;
}
auto readCHR(n32 address, n8 data) -> n8 override {
@@ -66,5 +75,5 @@ struct HVC_UxROM : Interface {
}
n1 mirror; //0 = horizontal, 1 = vertical
n4 programBank;
n8 programBank;
};
+89
View File
@@ -0,0 +1,89 @@
struct IremG101 : Interface {
static auto create(string id) -> Interface* {
if(id == "IREM-G101" ) return new IremG101(Revision::G101);
if(id == "IREM-G101A") return new IremG101(Revision::G101A);
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Writable<n8> programRAM;
Memory::Readable<n8> characterROM;
enum class Revision : u32 {
G101,
G101A,
} revision;
IremG101(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(programRAM, "save.ram");
Interface::load(characterROM, "character.rom");
}
auto save() -> void override {
Interface::save(programRAM, "save.ram");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x6000) return data;
if(address < 0x8000 && !programRAM) return data;
if(address < 0x8000) return programRAM.read((n13)address);
n5 bank;
switch(address >> 13 & 3) {
case 0: bank = (programMode == 0 ? programBank[0] : (n5)0x1e); break;
case 1: bank = programBank[1]; break;
case 2: bank = (programMode == 1 ? programBank[0] : (n5)0x1e); break;
case 3: bank = 0x1f; break;
}
return programROM.read(bank << 13 | (n13)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x6000) return;
if(address < 0x8000 && !programRAM) return;
if(address < 0x8000) return programRAM.write((n13)address, data);
switch(address & 0xf000) {
case 0x8000: programBank[0] = data.bit(0,4); break;
case 0xa000: programBank[1] = data.bit(0,4); break;
case 0xb000: characterBank[address & 7] = data; break;
case 0x9000:
if(revision == Revision::G101) {
mirror = data.bit(0);
programMode = data.bit(1);
}
break;
}
}
auto addressCIRAM(n32 address) const -> n32 {
if(revision == Revision::G101A) return (n10)address;
return address >> mirror & 0x0400 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
n8 bank = characterBank[address >> 10 & 7];
return characterROM.read(bank << 10 | (n10)address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
}
auto serialize(serializer& s) -> void override {
s(programRAM);
s(programBank);
s(characterBank);
s(programMode);
s(mirror);
}
n5 programBank[2];
n8 characterBank[8];
n1 programMode;
n1 mirror;
};
+104
View File
@@ -0,0 +1,104 @@
struct IremH3001 : Interface {
static auto create(string id) -> Interface* {
if(id == "IREM-H3001") return new IremH3001;
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
}
auto main() -> void override {
if(irqEnable) {
if(irqCounter && --irqCounter == 0) irqLine = 1;
}
cpu.irqLine(irqLine);
tick();
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
n6 bank;
switch(address >> 13 & 3) {
case 0: bank = (programMode == 0 ? programBank[0] : (n6)0x3e); break;
case 1: bank = programBank[1]; break;
case 2: bank = (programMode == 1 ? programBank[0] : (n6)0x3e); break;
case 3: bank = 0x3f; break;
}
return programROM.read(bank << 13 | (n13)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
switch(address) {
case 0x8000: programBank[0] = data.bit(0,5); break;
case 0xa000: programBank[1] = data.bit(0,5); break;
case 0xb000: characterBank[0] = data; break;
case 0xb001: characterBank[1] = data; break;
case 0xb002: characterBank[2] = data; break;
case 0xb003: characterBank[3] = data; break;
case 0xb004: characterBank[4] = data; break;
case 0xb005: characterBank[5] = data; break;
case 0xb006: characterBank[6] = data; break;
case 0xb007: characterBank[7] = data; break;
case 0x9000: programMode = data.bit(7); break;
case 0x9001: mirror = data.bit(6,7); break;
case 0x9003:
irqEnable = data.bit(7);
irqLine = 0;
break;
case 0x9004:
irqCounter = irqLatch;
irqLine = 0;
break;
case 0x9005: irqLatch = irqLatch.bit(0,7) << 0 | data << 8; break;
case 0x9006: irqLatch = irqLatch.bit(8,15) << 8 | data << 0; break;
}
}
auto addressCIRAM(n32 address) const -> n32 {
switch(mirror) {
case 0: return address >> 0 & 0x0400 | (n10)address;
case 1: return (n10)address;
case 2: return address >> 1 & 0x0400 | (n10)address;
case 3: return (n10)address;
}
unreachable;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
n8 bank = characterBank[address >> 10 & 7];
return characterROM.read(bank << 10 | (n10)address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
}
auto serialize(serializer& s) -> void override {
s(programBank);
s(characterBank);
s(programMode);
s(mirror);
s(irqLatch);
s(irqCounter);
s(irqEnable);
s(irqLine);
}
n6 programBank[2];
n8 characterBank[8];
n1 programMode;
n2 mirror;
n16 irqLatch;
n16 irqCounter;
n1 irqEnable;
n1 irqLine;
};
+61
View File
@@ -0,0 +1,61 @@
struct IremLROG017 : Interface {
static auto create(string id) -> Interface* {
if(id == "IREM-LROG017") return new IremLROG017;
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
Memory::Writable<n8> characterRAM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
Interface::load(characterRAM, "character.ram");
}
auto save() -> void override {
Interface::save(characterRAM, "character.ram");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
return programROM.read(programBank << 15 | (n15)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
programBank = data.bit(0,3);
characterBank = data.bit(4,7);
}
auto addressCHR(n32 address) const -> n32 {
if(address < 0x1000) return 1 << 11 | (n11)address;
if(address < 0x1800) return 2 << 11 | (n11)address;
if(address < 0x2000) return 3 << 11 | (n11)address;
if(address < 0x2800) return 0 << 11 | (n11)address;
unreachable;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address < 0x0800) return characterROM.read(characterBank << 11 | (n11)address);
if(address < 0x2800) return characterRAM.read(addressCHR(address));
if(address < 0x3000) return ppu.readCIRAM((n11)address);
return data;
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address < 0x0800) return;
if(address < 0x2800) return characterRAM.write(addressCHR(address), data);
if(address < 0x3000) return ppu.writeCIRAM((n11)address, data);
}
auto serialize(serializer& s) -> void override {
s(characterRAM);
s(programBank);
s(characterBank);
}
n4 programBank;
n4 characterBank;
};
+1 -1
View File
@@ -5,7 +5,7 @@ struct IremTAMS1 : Interface {
}
Memory::Readable<n8> programROM;
Memory::Writable<n8> characterROM;
Memory::Readable<n8> characterROM;
Memory::Writable<n8> characterRAM;
auto load() -> void override {
@@ -1,6 +1,10 @@
struct Jaleco_JF11_JF14 : Interface {
struct JalecoJF05 : Interface {
static auto create(string id) -> Interface* {
if(id == "JALECO-JF11-JF14") return new Jaleco_JF11_JF14;
if(id == "JALECO-JF-05") return new JalecoJF05;
if(id == "JALECO-JF-06") return new JalecoJF05;
if(id == "JALECO-JF-07") return new JalecoJF05;
if(id == "JALECO-JF-08") return new JalecoJF05;
if(id == "JALECO-JF-10") return new JalecoJF05;
return nullptr;
}
@@ -15,13 +19,12 @@ struct Jaleco_JF11_JF14 : Interface {
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
return programROM.read(programBank << 15 | (n15)address);
return programROM.read(address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x6000 || address > 0x7fff) return;
characterBank = data.bit(0,1);
programBank = data.bit(4,5);
characterBank = data.bit(0) << 1 | data.bit(1);
}
auto readCHR(n32 address, n8 data) -> n8 override {
@@ -30,8 +33,7 @@ struct Jaleco_JF11_JF14 : Interface {
return ppu.readCIRAM(address);
}
address = characterBank << 13 | (n13)address;
if(characterROM) return characterROM.read(address);
return data;
return characterROM.read(address);
}
auto writeCHR(n32 address, n8 data) -> void override {
@@ -41,16 +43,11 @@ struct Jaleco_JF11_JF14 : Interface {
}
}
auto power() -> void override {
}
auto serialize(serializer& s) -> void override {
s(mirror);
s(programBank);
s(characterBank);
}
n1 mirror; //0 = horizontal, 1 = vertical
n2 programBank;
n1 mirror;
n2 characterBank;
};
+70
View File
@@ -0,0 +1,70 @@
//todo: uPD7756 ADPCM unsupported
struct JalecoJF11 : Interface {
static auto create(string id) -> Interface* {
if(id == "JALECO-JF-11") return new JalecoJF11(Revision::JF11);
if(id == "JALECO-JF-13") return new JalecoJF11(Revision::JF13);
if(id == "JALECO-JF-14") return new JalecoJF11(Revision::JF14);
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
enum class Revision : u32 {
JF11,
JF13,
JF14,
} revision;
JalecoJF11(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
mirror = pak->attribute("mirror") == "vertical";
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
return programROM.read(programBank << 15 | (n15)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x6000 || address > 0x7fff) return;
if(revision == Revision::JF13 && address > 0x6fff) return;
programBank = data.bit(4,5);
if(revision == Revision::JF13) {
characterBank = data.bit(6) << 2 | data.bit(0,1);
} else {
characterBank = data.bit(0,3);
}
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) {
address = address >> !mirror & 0x0400 | (n10)address;
return ppu.readCIRAM(address);
}
address = characterBank << 13 | (n13)address;
return characterROM.read(address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) {
address = address >> !mirror & 0x0400 | (n10)address;
return ppu.writeCIRAM(address, data);
}
}
auto serialize(serializer& s) -> void override {
s(mirror);
s(programBank);
s(characterBank);
}
n1 mirror; //0 = horizontal, 1 = vertical
n2 programBank;
n4 characterBank;
};
+66
View File
@@ -0,0 +1,66 @@
struct JalecoJF16 : Interface {
static auto create(string id) -> Interface* {
if(id == "JALECO-JF-16") return new JalecoJF16(Revision::JF16);
if(id == "IREM-IF-12" ) return new JalecoJF16(Revision::IF12);
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
enum class Revision : u32 {
JF16,
IF12,
} revision;
JalecoJF16(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
n3 bank;
switch(address >> 14 & 1) {
case 0: bank = programBank; break;
case 1: bank = 7; break;
}
return programROM.read(bank << 14 | (n14)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
programBank = data.bit(0,2);
mirror = data.bit(3);
characterBank = data.bit(4,7);
}
auto addressCIRAM(n32 address) const -> n32 {
if(revision == Revision::IF12) {
return address >> !mirror & 0x0400 | (n10)address;
}
return mirror << 10 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
return characterROM.read(characterBank << 13 | (n13)address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
}
auto serialize(serializer& s) -> void override {
s(mirror);
s(programBank);
s(characterBank);
}
n1 mirror;
n3 programBank;
n4 characterBank;
};
+74
View File
@@ -0,0 +1,74 @@
//todo: uPD7756 ADPCM unsupported
struct JalecoJF17 : Interface {
static auto create(string id) -> Interface* {
if(id == "JALECO-JF-17") return new JalecoJF17(Revision::JF17);
if(id == "JALECO-JF-19") return new JalecoJF17(Revision::JF19);
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
enum class Revision : u32 {
JF17,
JF19,
} revision;
JalecoJF17(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
mirror = pak->attribute("mirror") == "vertical";
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
n4 bank;
switch(address >> 14 & 1) {
case 0: bank = (revision == Revision::JF17 ? programBank : (n4)0x0); break;
case 1: bank = (revision == Revision::JF19 ? programBank : (n4)0xf); break;
}
return programROM.read(bank << 14 | (n14)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
if(!programSelect && data.bit(7)) programBank = data.bit(0,3);
if(!characterSelect && data.bit(6)) characterBank = data.bit(0,3);
programSelect = data.bit(7);
characterSelect = data.bit(6);
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) {
address = address >> !mirror & 0x0400 | (n10)address;
return ppu.readCIRAM(address);
}
address = characterBank << 13 | (n13)address;
return characterROM.read(address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) {
address = address >> !mirror & 0x0400 | (n10)address;
return ppu.writeCIRAM(address, data);
}
}
auto serialize(serializer& s) -> void override {
s(mirror);
s(programSelect);
s(programBank);
s(characterSelect);
s(characterBank);
}
n1 mirror;
n1 programSelect;
n4 programBank;
n1 characterSelect;
n4 characterBank;
};
@@ -1,9 +1,14 @@
//JALECO-JF-(23A,24A,25,27B,29A,37,40)
//todo: uPD7756 ADPCM unsupported
struct JalecoJF : Interface {
struct JalecoJF23 : Interface {
static auto create(string id) -> Interface* {
if(id == "JALECO-JF") return new JalecoJF;
if(id == "JALECO-JF-23A") return new JalecoJF23;
if(id == "JALECO-JF-24A") return new JalecoJF23;
if(id == "JALECO-JF-25" ) return new JalecoJF23;
if(id == "JALECO-JF-27B") return new JalecoJF23;
if(id == "JALECO-JF-29A") return new JalecoJF23;
if(id == "JALECO-JF-37" ) return new JalecoJF23;
if(id == "JALECO-JF-40" ) return new JalecoJF23;
return nullptr;
}
+10 -1
View File
@@ -1,6 +1,7 @@
struct KonamiVRC2 : Interface {
static auto create(string id) -> Interface* {
if(id == "KONAMI-VRC-2") return new KonamiVRC2;
if(id == "KONAMI-VRC-2" ) return new KonamiVRC2(Revision::VRC2);
if(id == "KONAMI-VRC-2A") return new KonamiVRC2(Revision::VRC2A);
return nullptr;
}
@@ -9,6 +10,13 @@ struct KonamiVRC2 : Interface {
Memory::Readable<n8> characterROM;
Memory::Writable<n8> characterRAM;
enum class Revision : u32 {
VRC2,
VRC2A,
} revision;
KonamiVRC2(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(programRAM, "save.ram");
@@ -98,6 +106,7 @@ struct KonamiVRC2 : Interface {
auto addressCHR(n32 address) const -> n32 {
n8 bank = characterBank[address >> 10];
if(revision == Revision::VRC2A) bank >>= 1;
return bank << 10 | (n10)address;
}
+2
View File
@@ -43,6 +43,7 @@ struct KonamiVRC3 : Interface {
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x6000) return data;
if(address < 0x8000 && !programRAM) return data;
if(address < 0x8000) return programRAM.read((n13)address);
n4 bank = (address < 0xc000 ? programBank : (n4)0xf);
@@ -52,6 +53,7 @@ struct KonamiVRC3 : Interface {
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x6000) return;
if(address < 0x8000 && !programRAM) return;
if(address < 0x8000) return programRAM.write((n13)address, data);
switch(address & 0xf000) {
+2
View File
@@ -52,6 +52,7 @@ struct KonamiVRC4 : Interface {
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x6000) return data;
if(address < 0x8000 && !programRAM) return data;
if(address < 0x8000) return programRAM.read((n13)address);
n5 bank, banks = programROM.size() >> 13;
@@ -67,6 +68,7 @@ struct KonamiVRC4 : Interface {
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x6000) return;
if(address < 0x8000 && !programRAM) return;
if(address < 0x8000) return programRAM.write((n13)address, data);
bool a0 = address & pinA0;
+2
View File
@@ -147,12 +147,14 @@ struct KonamiVRC6 : Interface {
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x6000) return data;
if(address < 0x8000 && !programRAM) return data;
if(address < 0x8000) return programRAM.read((n13)address);
return programROM.read(addressPRG(address));
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x6000) return;
if(address < 0x8000 && !programRAM) return;
if(address < 0x8000) return programRAM.write((n13)address, data);
bool a0 = address & pinA0;
+19 -9
View File
@@ -16,6 +16,7 @@ struct KonamiVRC7 : Interface {
Interface::load(programRAM, "save.ram");
Interface::load(characterROM, "character.rom");
Interface::load(characterRAM, "character.ram");
pinA0 = 1 << pak->attribute("pinout/a0").natural();
stream = cartridge.node->append<Node::Audio::Stream>("YM2413");
stream->setChannels(1);
@@ -71,6 +72,7 @@ struct KonamiVRC7 : Interface {
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x6000) return data;
if(address < 0x8000 && !programRAM) return data;
if(address < 0x8000) return programRAM.read(address);
n8 bank;
@@ -86,29 +88,34 @@ struct KonamiVRC7 : Interface {
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x6000) return;
if(address < 0x8000 && !programRAM) return;
if(address < 0x8000) return programRAM.write(address, data);
bool a0 = address & pinA0;
address &= 0xf020;
address |= a0;
switch(address) {
case 0x8000: programBank[0] = data; break;
case 0x8010: programBank[1] = data; break;
case 0x8001: programBank[1] = data; break;
case 0x9000: programBank[2] = data; break;
case 0x9010: ym2413.address(data); break;
case 0x9030: ym2413.write(data); break;
case 0x9001: ym2413.address(data); break;
case 0x9021: ym2413.write(data); break;
case 0xa000: characterBank[0] = data; break;
case 0xa010: characterBank[1] = data; break;
case 0xa001: characterBank[1] = data; break;
case 0xb000: characterBank[2] = data; break;
case 0xb010: characterBank[3] = data; break;
case 0xb001: characterBank[3] = data; break;
case 0xc000: characterBank[4] = data; break;
case 0xc010: characterBank[5] = data; break;
case 0xc001: characterBank[5] = data; break;
case 0xd000: characterBank[6] = data; break;
case 0xd010: characterBank[7] = data; break;
case 0xd001: characterBank[7] = data; break;
case 0xe000:
if(disableFM && !data.bit(6)) ym2413.power(1);
mirror = data.bit(0,1);
disableFM = data.bit(6);
ramWritable = data.bit(7);
break;
case 0xe010:
case 0xe001:
irqLatch = data;
break;
case 0xf000:
@@ -121,7 +128,7 @@ struct KonamiVRC7 : Interface {
}
irqLine = 0;
break;
case 0xf010:
case 0xf001:
irqEnable = irqAcknowledge;
irqLine = 0;
break;
@@ -193,4 +200,7 @@ struct KonamiVRC7 : Interface {
i16 irqScalar;
n1 irqLine;
n6 divider;
//unserialized:
n8 pinA0;
};
+75
View File
@@ -0,0 +1,75 @@
struct MltAction52 : Interface {
static auto create(string id) -> Interface* {
if(id == "MLT-ACTION52") return new MltAction52();
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
n2 chipOffset;
switch(programChip) {
case 0: chipOffset = 0; break;
case 1: chipOffset = 1; break;
case 2: return data;
case 3: chipOffset = 2; break;
}
bool region = address.bit(14);
n5 bank = programMode ? programBank : (n5)(programBank & ~1 | region);
address = chipOffset << 19 | bank << 14 | (n14)address;
return programROM.read(address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
characterBank = address.bit(0,3) << 2 | data.bit(0,1);
programMode = address.bit(5);
programBank = address.bit(6,10);
programChip = address.bit(11,12);
mirror = address.bit(13);
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) {
address = address >> mirror & 0x0400 | (n10)address;
return ppu.readCIRAM(address);
}
address = characterBank << 13 | (n13)address;
if(characterROM) return characterROM.read(address);
return data;
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) {
address = address >> mirror & 0x0400 | (n10)address;
return ppu.writeCIRAM(address, data);
}
}
auto power() -> void override {
}
auto serialize(serializer& s) -> void override {
s(characterBank);
s(programMode);
s(programBank);
s(programChip);
s(mirror);
}
n6 characterBank;
n1 programMode;
n5 programBank;
n2 programChip;
n1 mirror;
};
+136
View File
@@ -0,0 +1,136 @@
struct Namco118 : Interface {
static auto create(string id) -> Interface* {
if(id == "NAMCO-118" ) return new Namco118(Revision::N118);
if(id == "NAMCO-3425") return new Namco118(Revision::N3425);
if(id == "NAMCO-3433") return new Namco118(Revision::N3433);
if(id == "NAMCO-3446") return new Namco118(Revision::N3446);
if(id == "NAMCO-3453") return new Namco118(Revision::N3453);
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
Memory::Writable<n8> characterCIRAM;
enum class Revision : u32 {
N118,
N3425,
N3433,
N3446,
N3453,
} revision;
Namco118(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
Interface::load(characterCIRAM, "character.ram");
mirror = pak->attribute("mirror") == "vertical";
}
auto save() -> void override {
Interface::save(characterCIRAM, "character.ram");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
n4 bank;
switch(address >> 13 & 3) {
case 0: bank = programBank[0]; break;
case 1: bank = programBank[1]; break;
case 2: bank = 0x0e; break;
case 3: bank = 0x0f; break;
}
return programROM.read(bank << 13 | (n13)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address >= 0x8000) nametableBank = data.bit(6);
switch(address & 0xe001) {
case 0x8000:
bankSelect = data.bit(0,2);
break;
case 0x8001:
switch(bankSelect) {
case 0: characterBank[0] = data >> 1; break;
case 1: characterBank[1] = data >> 1; break;
case 2: characterBank[2] = data; break;
case 3: characterBank[3] = data; break;
case 4: characterBank[4] = data; break;
case 5: characterBank[5] = data; break;
case 6: programBank[0] = data; break;
case 7: programBank[1] = data; break;
}
break;
}
}
auto addressCHR(n32 address) const -> n32 {
n32 chrAddress = 0;
if(revision == Revision::N3446) {
switch(address) {
case 0x0000 ... 0x07ff: chrAddress = characterBank[2] << 11 | (n11)address; break;
case 0x0800 ... 0x0fff: chrAddress = characterBank[3] << 11 | (n11)address; break;
case 0x1000 ... 0x17ff: chrAddress = characterBank[4] << 11 | (n11)address; break;
case 0x1800 ... 0xffff: chrAddress = characterBank[5] << 11 | (n11)address; break;
}
} else {
switch(address) {
case 0x0000 ... 0x07ff: chrAddress = characterBank[0] << 11 | (n11)address; break;
case 0x0800 ... 0x0fff: chrAddress = characterBank[1] << 11 | (n11)address; break;
case 0x1000 ... 0x13ff: chrAddress = characterBank[2] << 10 | (n10)address; break;
case 0x1400 ... 0x17ff: chrAddress = characterBank[3] << 10 | (n10)address; break;
case 0x1800 ... 0x1bff: chrAddress = characterBank[4] << 10 | (n10)address; break;
case 0x1c00 ... 0x1fff: chrAddress = characterBank[5] << 10 | (n10)address; break;
}
chrAddress |= (address & 0x1000) << 4;
}
return chrAddress;
}
auto addressCIRAM(n32 address) const -> n32 {
if(revision == Revision::N3425) {
n6 bank = characterBank[address >> 11 & 1];
return bank.bit(4) << 10 | (n10)address;
}
if(revision == Revision::N3453) {
return nametableBank << 10 | (n10)address;
}
return address >> !mirror & 0x0400 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) {
if(!characterCIRAM) return ppu.readCIRAM(addressCIRAM(address));
if(address & 0x0800) return characterCIRAM.read((n11)address);
return ppu.readCIRAM((n11)address);
}
return characterROM.read(addressCHR(address));
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) {
if(!characterCIRAM) return ppu.writeCIRAM(addressCIRAM(address), data);
if(address & 0x0800) return characterCIRAM.write((n11)address, data);
return ppu.writeCIRAM((n11)address, data);
}
}
auto serialize(serializer& s) -> void override {
s(characterCIRAM);
s(mirror);
s(bankSelect);
s(programBank);
s(characterBank);
s(nametableBank);
}
n1 mirror;
n3 bankSelect;
n4 programBank[2];
n6 characterBank[6];
n1 nametableBank;
};
+148
View File
@@ -0,0 +1,148 @@
//todo: sound
struct Namco163 : Interface {
static auto create(string id) -> Interface* {
if(id == "NAMCO-163") return new Namco163;
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Writable<n8> programRAM;
Memory::Readable<n8> characterROM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(programRAM, "save.ram");
Interface::load(characterROM, "character.rom");
}
auto save() -> void override {
Interface::save(programRAM, "save.ram");
}
auto main() -> void override {
cpu.irqLine(irqLine);
if(irqEnable) {
if(irqCounter != 0x7fff && ++irqCounter == 0x7fff) irqLine = 1;
}
tick();
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x4800) return data;
if(address < 0x5000) return data;
//if(address < 0x5000) return soundRAM.read(soundAddress);
if(address < 0x6000) {
if(address < 0x5800) return irqCounter.bit(0,7);
if(address < 0x6000) return irqCounter.bit(8,14) | irqEnable << 7;
}
if(address < 0x8000) {
if(!programRAM) return data;
return programRAM.read((n13)address);
}
n6 bank;
switch(address >> 13 & 3) {
case 0: bank = programBank[0]; break;
case 1: bank = programBank[1]; break;
case 2: bank = programBank[2]; break;
case 3: bank = 0x3f; break;
}
return programROM.read(bank << 13 | (n13)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address >= 0x6000 && address < 0x8000) {
if(!programRAM) return;
if(!ramEnable[address >> 11 & 3]) return;
return programRAM.write((n13)address, data);
}
switch(address & 0xf800) {
case 0x4800:
//soundRAM.write(soundAddres, data);
break;
case 0x5000:
irqCounter.bit(0,7) = data;
irqLine = 0;
break;
case 0x5800:
irqCounter.bit(8,14) = data.bit(0,6);
irqEnable = data.bit(7);
irqLine = 0;
break;
case 0x8000: characterBank[0] = data; break;
case 0x8800: characterBank[1] = data; break;
case 0x9000: characterBank[2] = data; break;
case 0x9800: characterBank[3] = data; break;
case 0xa000: characterBank[4] = data; break;
case 0xa800: characterBank[5] = data; break;
case 0xb000: characterBank[6] = data; break;
case 0xb800: characterBank[7] = data; break;
case 0xc000: characterBank[8] = data; break;
case 0xc800: characterBank[9] = data; break;
case 0xd000: characterBank[10] = data; break;
case 0xd800: characterBank[11] = data; break;
case 0xe000:
programBank[0] = data.bit(0,5);
//soundEnable = !data.bit(6);
break;
case 0xe800:
programBank[1] = data.bit(0,5);
ciramEnable[0] = !data.bit(6);
ciramEnable[1] = !data.bit(7);
break;
case 0xf000:
programBank[2] = data.bit(0,5);
break;
case 0xf800:
ramEnable[0] = data.bit(4,7) == 4 && !data.bit(0);
ramEnable[1] = data.bit(4,7) == 4 && !data.bit(1);
ramEnable[2] = data.bit(4,7) == 4 && !data.bit(2);
ramEnable[3] = data.bit(4,7) == 4 && !data.bit(3);
//soundAddress = data.bit(0,6);
//soundRepeat = data.bit(7);
break;
}
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) address.bit(12) = 0;
bool ciramSelect = address & 0x2000 || ciramEnable[address >> 12 & 1];
n8 bank = characterBank[address >> 10];
if(bank >= 0xe0 && ciramSelect) {
return ppu.readCIRAM(bank.bit(0) << 10 | (n10)address);
}
return characterROM.read(bank << 10 | (n10)address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) address.bit(12) = 0;
bool ciramSelect = address & 0x2000 || ciramEnable[address >> 12 & 1];
n8 bank = characterBank[address >> 10];
if(bank >= 0xe0 && ciramSelect) {
return ppu.writeCIRAM(bank.bit(0) << 10 | (n10)address, data);
}
}
auto serialize(serializer& s) -> void override {
s(programRAM);
s(ramEnable);
s(ciramEnable);
s(programBank);
s(characterBank);
s(irqCounter);
s(irqEnable);
s(irqLine);
}
n1 ramEnable[4];
n1 ciramEnable[2];
n6 programBank[3];
n8 characterBank[12];
n15 irqCounter;
n1 irqEnable;
n1 irqLine;
};
+108
View File
@@ -0,0 +1,108 @@
struct Namco340 : Interface {
static auto create(string id) -> Interface* {
if(id == "NAMCO-175") return new Namco340(Revision::N175);
if(id == "NAMCO-340") return new Namco340(Revision::N340);
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Writable<n8> programRAM;
Memory::Readable<n8> characterROM;
enum class Revision : u32 {
N175,
N340,
} revision;
Namco340(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(programRAM, "save.ram");
Interface::load(characterROM, "character.rom");
staticMirror = pak->attribute("mirror") == "vertical";
}
auto save() -> void override {
Interface::save(programRAM, "save.ram");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x6000) return data;
if(address < 0x8000) {
if(!ramEnable || !programRAM) return data;
return programRAM.read((n13)address);
}
n6 bank;
switch(address >> 13 & 3) {
case 0: bank = programBank[0]; break;
case 1: bank = programBank[1]; break;
case 2: bank = programBank[2]; break;
case 3: bank = 0x3f; break;
}
return programROM.read(bank << 13 | (n13)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x6000) return;
if(address < 0x8000) {
if(!ramEnable || !programRAM) return;
return programRAM.write((n13)address, data);
}
switch(address & 0xf800) {
case 0x8000: characterBank[0] = data; break;
case 0x8800: characterBank[1] = data; break;
case 0x9000: characterBank[2] = data; break;
case 0x9800: characterBank[3] = data; break;
case 0xa000: characterBank[4] = data; break;
case 0xa800: characterBank[5] = data; break;
case 0xb000: characterBank[6] = data; break;
case 0xb800: characterBank[7] = data; break;
case 0xc000: ramEnable = data.bit(0); break;
case 0xe000: programBank[0] = data.bit(0,5); mirror = data.bit(6,7); break;
case 0xe800: programBank[1] = data.bit(0,5); break;
case 0xf000: programBank[2] = data.bit(0,5); break;
}
}
auto addressCIRAM(n32 address) const -> n32 {
if(revision == Revision::N175) {
return address >> !staticMirror & 0x0400 | (n10)address;
}
switch(mirror) {
case 0: return 0x0000 | (n10)address;
case 1: return address >> 0 & 0x0400 | (n10)address;
case 2: return 0x0400 | (n10)address;
case 3: return address >> 1 & 0x0400 | (n10)address;
}
unreachable;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
n8 bank = characterBank[address >> 10 & 7];
return characterROM.read(bank << 10 | (n10)address);
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
}
auto serialize(serializer& s) -> void override {
s(programRAM);
s(mirror);
s(staticMirror);
s(ramEnable);
s(programBank);
s(characterBank);
}
n2 mirror;
n1 staticMirror;
n1 ramEnable;
n6 programBank[3];
n8 characterBank[8];
};
+2 -2
View File
@@ -66,7 +66,7 @@ struct Sunsoft5B : Interface {
bank &= 0x3f;
if(ramSelect) {
if(!ramEnable) return data;
if(!ramEnable || !programRAM) return data;
return programRAM.read((n13)address);
}
@@ -76,7 +76,7 @@ struct Sunsoft5B : Interface {
auto writePRG(n32 address, n8 data) -> void override {
if((address & 0xe000) == 0x6000) {
programRAM.write((n13)address, data);
if(programRAM) programRAM.write((n13)address, data);
}
if(address == 0x8000) {
+80
View File
@@ -0,0 +1,80 @@
struct TaitoTC0190 : Interface {
static auto create(string id) -> Interface* {
if(id == "TAITO-TC0190") return new TaitoTC0190;
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
n6 bank;
switch(address >> 13 & 3) {
case 0: bank = programBank[0]; break;
case 1: bank = programBank[1]; break;
case 2: bank = 0x3e; break;
case 3: bank = 0x3f; break;
}
return programROM.read(bank << 13 | (n13)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
switch(address & 0xa003) {
case 0x8000:
programBank[0] = data.bit(0,5);
mirror = data.bit(6);
break;
case 0x8001:
programBank[1] = data.bit(0,5);
break;
case 0x8002: characterBank[0] = data; break;
case 0x8003: characterBank[1] = data; break;
case 0xa000: characterBank[2] = data; break;
case 0xa001: characterBank[3] = data; break;
case 0xa002: characterBank[4] = data; break;
case 0xa003: characterBank[5] = data; break;
}
}
auto addressCHR(n32 address) const -> n32 {
if(address <= 0x07ff) return characterBank[0] << 11 | (n11)address;
if(address <= 0x0fff) return characterBank[1] << 11 | (n11)address;
if(address <= 0x13ff) return characterBank[2] << 10 | (n10)address;
if(address <= 0x17ff) return characterBank[3] << 10 | (n10)address;
if(address <= 0x1bff) return characterBank[4] << 10 | (n10)address;
if(address <= 0x1fff) return characterBank[5] << 10 | (n10)address;
unreachable;
}
auto addressCIRAM(n32 address) const -> n32 {
return address >> mirror & 0x0400 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
return characterROM.read(addressCHR(address));
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
}
auto serialize(serializer& s) -> void override {
s(mirror);
s(programBank);
s(characterBank);
}
n1 mirror;
n6 programBank[2];
n8 characterBank[6];
};
+130
View File
@@ -0,0 +1,130 @@
struct TaitoTC0690 : Interface {
static auto create(string id) -> Interface* {
if(id == "TAITO-TC0690") return new TaitoTC0690;
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Readable<n8> characterROM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(characterROM, "character.rom");
}
auto main() -> void override {
if(irqDelay) irqDelay--;
if(irqLineDelay && --irqLineDelay == 0) irqLine = 1;
cpu.irqLine(irqLine);
tick();
}
auto irqTest(n16 address) -> void {
if(!(characterAddress & 0x1000) && (address & 0x1000)) {
if(irqDelay == 0) {
if(irqCounter == 0) {
irqCounter = irqLatch + 1;
}
if(--irqCounter == 0) {
if(irqEnable) irqLineDelay = 6;
}
}
irqDelay = 6;
}
characterAddress = address;
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x8000) return data;
n6 bank;
switch(address >> 13 & 3) {
case 0: bank = programBank[0]; break;
case 1: bank = programBank[1]; break;
case 2: bank = 0x3e; break;
case 3: bank = 0x3f; break;
}
return programROM.read(bank << 13 | (n13)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address < 0x8000) return;
switch(address & 0xe003) {
case 0x8000: case 0x8001:
programBank[address & 1] = data.bit(0,5);
break;
case 0x8002: characterBank[0] = data; break;
case 0x8003: characterBank[1] = data; break;
case 0xa000: characterBank[2] = data; break;
case 0xa001: characterBank[3] = data; break;
case 0xa002: characterBank[4] = data; break;
case 0xa003: characterBank[5] = data; break;
case 0xc000:
irqLatch = ~data;
break;
case 0xc001:
irqCounter = 0;
break;
case 0xc002:
irqEnable = 1;
break;
case 0xc003:
irqEnable = 0;
irqLine = 0;
break;
case 0xe000:
mirror = data.bit(6);
break;
}
}
auto addressCHR(n32 address) const -> n32 {
if(address <= 0x07ff) return characterBank[0] << 11 | (n11)address;
if(address <= 0x0fff) return characterBank[1] << 11 | (n11)address;
if(address <= 0x13ff) return characterBank[2] << 10 | (n10)address;
if(address <= 0x17ff) return characterBank[3] << 10 | (n10)address;
if(address <= 0x1bff) return characterBank[4] << 10 | (n10)address;
if(address <= 0x1fff) return characterBank[5] << 10 | (n10)address;
unreachable;
}
auto addressCIRAM(n32 address) const -> n32 {
return address >> mirror & 0x0400 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
irqTest(address);
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
return characterROM.read(addressCHR(address));
}
auto writeCHR(n32 address, n8 data) -> void override {
irqTest(address);
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
}
auto serialize(serializer& s) -> void override {
s(mirror);
s(programBank);
s(characterBank);
s(irqLatch);
s(irqCounter);
s(irqEnable);
s(irqDelay);
s(irqLineDelay);
s(irqLine);
s(characterAddress);
}
n1 mirror;
n6 programBank[2];
n8 characterBank[6];
n8 irqLatch;
n8 irqCounter;
n1 irqEnable;
n8 irqDelay;
n8 irqLineDelay;
n1 irqLine;
n16 characterAddress;
};
+110
View File
@@ -0,0 +1,110 @@
struct TaitoX1005 : Interface {
static auto create(string id) -> Interface* {
if(id == "TAITO-X1-005" ) return new TaitoX1005(Revision::X1005);
if(id == "TAITO-X1-005A") return new TaitoX1005(Revision::X1005A);
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Writable<n8> programRAM;
Memory::Readable<n8> characterROM;
enum class Revision : u32 {
X1005,
X1005A,
} revision;
TaitoX1005(Revision revision) : revision(revision) {}
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(programRAM, "save.ram");
Interface::load(characterROM, "character.rom");
}
auto save() -> void override {
Interface::save(programRAM, "save.ram");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address < 0x7f00) return data;
if(address < 0x8000) {
if(!ramEnable) return data;
return programRAM.read((n7)address);
}
n6 bank;
switch(address >> 13 & 3) {
case 0: bank = programBank[0]; break;
case 1: bank = programBank[1]; break;
case 2: bank = programBank[2]; break;
case 3: bank = 0x3f; break;
}
return programROM.read(bank << 13 | (n13)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address >= 0x7f00 && address < 0x8000) {
if(!ramEnable) return;
return programRAM.write((n7)address, data);
}
switch(address) {
case 0x7ef0 ... 0x7ef1:
characterBank[address & 1] = data >> 1;
nametableBank[address & 1] = data.bit(7);
break;
case 0x7ef2: characterBank[2] = data; break;
case 0x7ef3: characterBank[3] = data; break;
case 0x7ef4: characterBank[4] = data; break;
case 0x7ef5: characterBank[5] = data; break;
case 0x7ef6 ... 0x7ef7: mirror = data.bit(0); break;
case 0x7ef8 ... 0x7ef9: ramEnable = data == 0xa3; break;
case 0x7efa ... 0x7efb: programBank[0] = data.bit(0,5); break;
case 0x7efc ... 0x7efd: programBank[1] = data.bit(0,5); break;
case 0x7efe ... 0x7eff: programBank[2] = data.bit(0,5); break;
}
}
auto addressCHR(n32 address) const -> n32 {
if(address <= 0x07ff) return characterBank[0] << 11 | (n11)address;
if(address <= 0x0fff) return characterBank[1] << 11 | (n11)address;
if(address <= 0x13ff) return characterBank[2] << 10 | (n10)address;
if(address <= 0x17ff) return characterBank[3] << 10 | (n10)address;
if(address <= 0x1bff) return characterBank[4] << 10 | (n10)address;
if(address <= 0x1fff) return characterBank[5] << 10 | (n10)address;
unreachable;
}
auto addressCIRAM(n32 address) const -> n32 {
if(revision == Revision::X1005A) {
return nametableBank[address >> 12 & 1] << 10 | (n10)address;
}
return address >> !mirror & 0x0400 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
return characterROM.read(addressCHR(address));
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
}
auto serialize(serializer& s) -> void override {
s(programRAM);
s(mirror);
s(ramEnable);
s(programBank);
s(characterBank);
s(nametableBank);
}
n1 mirror;
n1 ramEnable;
n6 programBank[3];
n8 characterBank[6];
n1 nametableBank[2];
};
+102
View File
@@ -0,0 +1,102 @@
struct TaitoX1017 : Interface {
static auto create(string id) -> Interface* {
if(id == "TAITO-X1-017") return new TaitoX1017;
return nullptr;
}
Memory::Readable<n8> programROM;
Memory::Writable<n8> programRAM;
Memory::Readable<n8> characterROM;
auto load() -> void override {
Interface::load(programROM, "program.rom");
Interface::load(programRAM, "save.ram");
Interface::load(characterROM, "character.rom");
}
auto save() -> void override {
Interface::save(programRAM, "save.ram");
}
auto readPRG(n32 address, n8 data) -> n8 override {
if(address >= 0x6000 && address < 0x7400) {
if(!ramEnable[address >> 11 & 3]) return data;
return programRAM.read((n13)address);
}
if(address < 0x8000) return data;
n6 bank;
switch(address >> 13 & 3) {
case 0: bank = programBank[0]; break;
case 1: bank = programBank[1]; break;
case 2: bank = programBank[2]; break;
case 3: bank = 0x3f; break;
}
return programROM.read(bank << 13 | (n13)address);
}
auto writePRG(n32 address, n8 data) -> void override {
if(address >= 0x6000 && address < 0x7400) {
if(!ramEnable[address >> 11 & 3]) return;
return programRAM.write((n13)address, data);
}
switch(address) {
case 0x7ef0: characterBank[0] = data >> 1; break;
case 0x7ef1: characterBank[1] = data >> 1; break;
case 0x7ef2: characterBank[2] = data; break;
case 0x7ef3: characterBank[3] = data; break;
case 0x7ef4: characterBank[4] = data; break;
case 0x7ef5: characterBank[5] = data; break;
case 0x7ef6:
mirror = data.bit(0);
characterMode = data.bit(1);
break;
case 0x7ef7: ramEnable[0] = data == 0xca; break;
case 0x7ef8: ramEnable[1] = data == 0x69; break;
case 0x7ef9: ramEnable[2] = data == 0x84; break;
case 0x7efa: programBank[0] = data >> 2; break;
case 0x7efb: programBank[1] = data >> 2; break;
case 0x7efc: programBank[2] = data >> 2; break;
}
}
auto addressCHR(n32 address) const -> n32 {
if(characterMode) address ^= 0x1000;
if(address <= 0x07ff) return characterBank[0] << 11 | (n11)address;
if(address <= 0x0fff) return characterBank[1] << 11 | (n11)address;
if(address <= 0x13ff) return characterBank[2] << 10 | (n10)address;
if(address <= 0x17ff) return characterBank[3] << 10 | (n10)address;
if(address <= 0x1bff) return characterBank[4] << 10 | (n10)address;
if(address <= 0x1fff) return characterBank[5] << 10 | (n10)address;
unreachable;
}
auto addressCIRAM(n32 address) const -> n32 {
return address >> !mirror & 0x0400 | (n10)address;
}
auto readCHR(n32 address, n8 data) -> n8 override {
if(address & 0x2000) return ppu.readCIRAM(addressCIRAM(address));
return characterROM.read(addressCHR(address));
}
auto writeCHR(n32 address, n8 data) -> void override {
if(address & 0x2000) return ppu.writeCIRAM(addressCIRAM(address), data);
}
auto serialize(serializer& s) -> void override {
s(programRAM);
s(mirror);
s(ramEnable);
s(programBank);
s(characterBank);
s(characterMode);
}
n1 mirror;
n1 ramEnable[3];
n6 programBank[3];
n8 characterBank[6];
n1 characterMode;
};
+3 -3
View File
@@ -138,6 +138,7 @@ auto PPU::renderScanline() -> void {
//257-320
for(u32 sprite : range(8)) {
if(enable()) io.oamAddress = 0;
u32 nametable = loadCHR(0x2000 | (n12)io.v.address);
step(1);
@@ -198,9 +199,8 @@ auto PPU::renderScanline() -> void {
//337-338
loadCHR(0x2000 | (n12)io.v.address);
step(1);
bool skip = enable() && io.field == 1 && io.ly == vlines() - 1;
step(1);
bool skip = !Region::PAL() && enable() && io.field == 1 && io.ly == vlines() - 1;
step(2);
//339
loadCHR(0x2000 | (n12)io.v.address);
+14 -8
View File
@@ -34,6 +34,18 @@ auto PPU::readTileCGB(bool select, u32 x, u32 y, n16& tiledata, n8& attributes)
if(attributes.bit(5)) tiledata = hflip(tiledata);
}
auto PPU::readObjectCGB(i16 y, n8 tile, n8 attributes, n16& tiledata) -> void {
const s32 Height = (status.obSize == 0 ? 8 : 16);
tile &= ~status.obSize;
y = status.ly - y;
if(attributes.bit(6)) y ^= Height - 1;
n14 tiledataAddress = (attributes.bit(3) ? 0x2000 : 0x0000) + (tile << 4) + (y << 1);
tiledata.byte(0) = vram[tiledataAddress + 0];
tiledata.byte(1) = vram[tiledataAddress + 1];
if(attributes.bit(5)) tiledata = hflip(tiledata);
}
auto PPU::scanlineCGB() -> void {
px = 0;
@@ -45,18 +57,11 @@ auto PPU::scanlineCGB() -> void {
Sprite& s = sprite[sprites];
s.y = oam[n + 0] - 16;
s.x = oam[n + 1] - 8;
s.tile = oam[n + 2] & ~status.obSize;
s.tile = oam[n + 2];
s.attributes = oam[n + 3];
if(s32(status.ly) < s.y) continue;
if(s32(status.ly) >= s.y + Height) continue;
s.y = status.ly - s.y;
if(s.attributes.bit(6)) s.y ^= Height - 1;
n14 tiledataAddress = (s.attributes.bit(3) ? 0x2000 : 0x0000) + (s.tile << 4) + (s.y << 1);
s.tiledata.byte(0) = vram[tiledataAddress + 0];
s.tiledata.byte(1) = vram[tiledataAddress + 1];
if(s.attributes.bit(5)) s.tiledata = hflip(s.tiledata);
if(++sprites == 10) break;
}
@@ -135,6 +140,7 @@ auto PPU::runObjectsCGB() -> void {
s32 tileX = px - s.x;
if(tileX < 0 || tileX > 7) continue;
if(tileX == 0 || px == 0) readObjectCGB(s.y, s.tile, s.attributes, s.tiledata);
n2 index;
index.bit(0) = s.tiledata.bit( 7 - tileX);
+15 -8
View File
@@ -23,6 +23,19 @@ auto PPU::readTileDMG(bool select, u32 x, u32 y, n16& tiledata) -> void {
tiledata.byte(1) = vram[tiledataAddress + 1];
}
auto PPU::readObjectDMG(i16 y, n8 tile, n8 attributes, n16& tiledata) -> void {
const s32 Height = (status.obSize == 0 ? 8 : 16);
tile &= ~status.obSize;
y = s32(status.ly) - y;
if(attributes.bit(6)) y ^= Height - 1;
n13 tiledataAddress = (tile << 4) + (y << 1);
tiledata.byte(0) = vram[tiledataAddress + 0];
tiledata.byte(1) = vram[tiledataAddress + 1];
if(attributes.bit(5)) tiledata = hflip(tiledata);
}
auto PPU::scanlineDMG() -> void {
px = 0;
@@ -34,18 +47,11 @@ auto PPU::scanlineDMG() -> void {
Sprite& s = sprite[sprites];
s.y = oam[n + 0] - 16;
s.x = oam[n + 1] - 8;
s.tile = oam[n + 2] & ~status.obSize;
s.tile = oam[n + 2];
s.attributes = oam[n + 3];
if(s32(status.ly) < s.y) continue;
if(s32(status.ly) >= s.y + Height) continue;
s.y = s32(status.ly) - s.y;
if(s.attributes.bit(6)) s.y ^= Height - 1;
n13 tiledataAddress = (s.tile << 4) + (s.y << 1);
s.tiledata.byte(0) = vram[tiledataAddress + 0];
s.tiledata.byte(1) = vram[tiledataAddress + 1];
if(s.attributes.bit(5)) s.tiledata = hflip(s.tiledata);
if(++sprites == 10) break;
}
@@ -125,6 +131,7 @@ auto PPU::runObjectsDMG() -> void {
s32 tileX = px - s.x;
if(tileX < 0 || tileX > 7) continue;
if(tileX == 0 || px == 0) readObjectDMG(s.y, s.tile, s.attributes, s.tiledata);
n2 index;
index.bit(0) = s.tiledata.bit( 7 - tileX);
+3 -3
View File
@@ -90,9 +90,6 @@ auto PPU::main() -> void {
status.lx = 0;
latch.windowDisplayEnable = status.windowDisplayEnable;
latch.wx = status.wx;
if(status.ly == 0) {
latch.wy = 0;
}
@@ -112,6 +109,9 @@ auto PPU::main() -> void {
scanline();
step(80);
latch.windowDisplayEnable = status.windowDisplayEnable;
latch.wx = status.wx;
if(status.ly >= status.wy && status.wx < 7) latch.wy++;
mode(3);
+2
View File
@@ -52,6 +52,7 @@ struct PPU : Thread {
//dmg.cpp
auto readTileDMG(bool select, u32 x, u32 y, n16& tiledata) -> void;
auto readObjectDMG(i16 y, n8 tile, n8 attributes, n16& tiledata) -> void;
auto scanlineDMG() -> void;
auto runDMG() -> void;
auto runBackgroundDMG() -> void;
@@ -60,6 +61,7 @@ struct PPU : Thread {
//cgb.cpp
auto readTileCGB(bool select, u32 x, u32 y, n16& tiledata, n8& attributes) -> void;
auto readObjectCGB(i16 y, n8 tile, n8 attributes, n16& tiledata) -> void;
auto scanlineCGB() -> void;
auto runCGB() -> void;
auto runBackgroundCGB() -> void;
+1 -1
View File
@@ -12,7 +12,7 @@ auto PPU::color(n32 color) -> n64 {
f64 lb = pow(B / 31.0, lcdGamma);
f64 lg = pow(G / 31.0, lcdGamma);
f64 lr = pow(R / 31.0, lcdGamma);
r = pow(( 0 * lb + 50 * lg + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
r = pow(( 0 * lb + 50 * lg + 240 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
g = pow(( 30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
b = pow((220 * lb + 10 * lg + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280);
}
+2 -8
View File
@@ -20,15 +20,8 @@ auto APU::unload() -> void {
}
auto APU::main() -> void {
//handle a bus switching request from the CPU
if(state.resLine) {
//switching requires a minimum of 9 cycles to allow the 68K to read back unavailable bus state
if(state.busreqLine && !state.busreqLatch) step(9);
state.busreqLatch = state.busreqLine;
}
//stall the APU until the CPU relinquishes control of the bus
if(!state.resLine || !busownerAPU()) {
if(!state.resLine || state.busreqLatch) {
return step(1);
}
@@ -50,6 +43,7 @@ auto APU::main() -> void {
auto APU::step(u32 clocks) -> void {
Thread::step(clocks);
state.busreqLatch = busownerCPU() ? 1 : 0;
Thread::synchronize(cpu, vdp, vdp.psg, opn2);
}
+6 -2
View File
@@ -21,8 +21,12 @@ struct APU : Z80, Z80::Bus, Thread {
} debugger;
auto synchronizing() const -> bool override { return scheduler.synchronizing(); }
auto busownerAPU() const -> bool { return (state.resLine & state.busreqLatch) == 0; } //Z80 has bus access
auto busownerCPU() const -> bool { return (state.resLine & state.busreqLatch) == 1; } //68K has bus access
auto busgrantedCPU() const -> bool { return state.resLine & state.busreqLatch; }
auto busownerCPU() const -> bool { return state.resLine & state.busreqLine; }
// Note: bus ownership is flagged according to line state, since it could be too slow
// to wait for latching with only instruction-level granularity on the Z80 emulation.
// At worst, a positive signal would indicate bus grant is imminent, which should be safe.
// (fixes Arkagis Revolution - Trial Version [Rev 00])
//z80.cpp
auto load(Node::Object) -> void;
+1 -1
View File
@@ -89,7 +89,7 @@ auto APU::writeExternal(n24 address, n8 data) -> void {
auto APU::in(n16 address) -> n8 {
//unused on Mega Drive
return 0x00;
return 0xff;
}
auto APU::out(n16 address, n8 data) -> void {
+40 -14
View File
@@ -27,7 +27,7 @@ inline auto Bus::read(n1 upper, n1 lower, n24 address, n16 data) -> n16 {
}
if(address >= 0xa00000 && address <= 0xa0ffff) {
if(!apu.busownerCPU()) return data;
if(!apu.busgrantedCPU()) return data;
if(cpu.active()) cpu.wait(3); //todo: inaccurate approximation of Z80 RAM access delay
address.bit(15) = 0; //a080000-a0ffff mirrors a00000-a07fff
//word reads load the even input byte into both output bytes
@@ -85,7 +85,7 @@ inline auto Bus::write(n1 upper, n1 lower, n24 address, n16 data) -> void {
}
if(address >= 0xa00000 && address <= 0xa0ffff) {
if(!apu.busownerCPU()) return;
if(!apu.busgrantedCPU()) return;
if(cpu.active()) cpu.wait(3); //todo: inaccurate approximation of Z80 RAM access delay
address.bit(15) = 0; //a08000-a0ffff mirrors a00000-a07fff
//word writes store the upper input byte into the lower output byte
@@ -114,22 +114,48 @@ inline auto Bus::write(n1 upper, n1 lower, n24 address, n16 data) -> void {
}
}
//0-127
inline auto Bus::waitRefreshExternal() -> void {
while(cpu.refresh.external >= 126) {
if(cpu.active()) cpu.wait(1);
if(scheduler.synchronizing()) break;
if(apu.active()) apu.step(1);
if(vdp.active()) break;
if(state.acquired & VDPDMA) return; // refresh is synched with VDP during DMA
if(cpu.refresh.external < cpu.refresh.externalLowBound) return;
if(cpu.refresh.externalEnd == 0)
cpu.refresh.externalEnd = min(cpu.refresh.external + cpu.refresh.externalLength, cpu.refresh.externalHighBound);
if(cpu.refresh.external < cpu.refresh.externalEnd) {
while(cpu.refresh.external < cpu.refresh.externalEnd) {
if(cpu.active()) cpu.wait(1);
if(apu.active()) apu.step(1);
if(scheduler.synchronizing()) return;
if(vdp.active()) return;
}
cpu.refresh.external -= cpu.refresh.externalEnd;
cpu.refresh.externalEnd = 0;
}
while(cpu.refresh.external >= cpu.refresh.externalHighBound) {
cpu.refresh.external -= cpu.refresh.externalHighBound;
cpu.refresh.externalEnd = 0;
}
}
//0-132
inline auto Bus::waitRefreshRAM() -> void {
while(cpu.refresh.ram >= 130) {
if(cpu.active()) cpu.wait(1);
if(scheduler.synchronizing()) break;
if(apu.active()) apu.step(1);
if(vdp.active()) break;
if(state.acquired & VDPDMA) return; // refresh is synched with VDP during DMA
if(cpu.refresh.ram < cpu.refresh.ramLowBound) return;
if(cpu.refresh.ramEnd == 0)
cpu.refresh.ramEnd = min(cpu.refresh.ram + cpu.refresh.ramLength, cpu.refresh.ramHighBound);
if(cpu.refresh.ram < cpu.refresh.ramEnd) {
while(cpu.refresh.ram < cpu.refresh.ramEnd) {
if(cpu.active()) cpu.wait(1);
if(apu.active()) apu.step(1);
if(scheduler.synchronizing()) return;
if(vdp.active()) return;
}
cpu.refresh.ram -= cpu.refresh.ramEnd;
cpu.refresh.ramEnd = 0;
}
while(cpu.refresh.ram >= cpu.refresh.ramHighBound) {
cpu.refresh.ram -= cpu.refresh.ramHighBound;
cpu.refresh.ramEnd = 0;
}
}
+6 -5
View File
@@ -4,15 +4,16 @@ struct Banked : Interface {
Memory::Writable<n16> wram;
Memory::Writable<n8 > uram;
Memory::Writable<n8 > lram;
u32 sramAddr, sramSize;
M24C m24c;
auto load() -> void override {
Interface::load(rom, "program.rom");
if(auto fp = pak->read("save.ram")) {
Interface::load(wram, uram, lram, "save.ram");
Interface::load(sramAddr, sramSize, wram, uram, lram, "save.ram");
}
if(auto fp = pak->read("save.eeprom")) {
Interface::load(m24c, "save.eeprom");
Interface::load(sramAddr, sramSize, m24c, "save.eeprom");
rsda = fp->attribute("rsda").natural();
wsda = fp->attribute("wsda").natural();
wscl = fp->attribute("wscl").natural();
@@ -29,7 +30,7 @@ struct Banked : Interface {
}
auto read(n1 upper, n1 lower, n22 address, n16 data) -> n16 override {
if(address >= 0x200000) {
if(address >= sramAddr && address < sramAddr+sramSize) {
if(wram && ramEnable) {
return wram[address >> 1];
}
@@ -62,7 +63,7 @@ struct Banked : Interface {
//emulating ramWritable will break commercial software:
//it does not appear that many (any?) games actually connect $a130f1.d1 to /WE;
//hence RAM ends up always being writable, and many games fail to set d1=1
if(address >= 0x200000) {
if(address >= sramAddr && address < sramAddr+sramSize) {
if(wram && ramEnable) {
if(upper) wram[address >> 1].byte(1) = data.byte(1);
if(lower) wram[address >> 1].byte(0) = data.byte(0);
@@ -80,7 +81,7 @@ struct Banked : Interface {
}
if(m24c) {
if(rom.size() * 2 > 0x200000 && upper && lower) {
if(rom.size() * 2 > sramAddr && upper && lower) {
eepromEnable = !data.bit(0);
return;
}
+6 -2
View File
@@ -26,11 +26,13 @@ auto Interface::load(Memory::Readable<n16>& rom, string name) -> bool {
return false;
}
auto Interface::load(Memory::Writable<n16>& wram, Memory::Writable<n8>& uram, Memory::Writable<n8>& lram, string name) -> bool {
auto Interface::load(u32& addr, u32& size, Memory::Writable<n16>& wram, Memory::Writable<n8>& uram, Memory::Writable<n8>& lram, string name) -> bool {
wram.reset();
uram.reset();
lram.reset();
if(auto fp = pak->read(name)) {
addr = fp->attribute("address").natural();
size = fp->size() << 1;
auto mode = fp->attribute("mode");
if(mode == "word") {
wram.allocate(fp->size() >> 1);
@@ -49,10 +51,12 @@ auto Interface::load(Memory::Writable<n16>& wram, Memory::Writable<n8>& uram, Me
return false;
}
auto Interface::load(M24C& m24c, string name) -> bool {
auto Interface::load(u32& addr, u32& size, M24C& m24c, string name) -> bool {
m24c.reset();
if(auto fp = pak->read(name)) {
auto mode = fp->attribute("mode");
addr = fp->attribute("address").natural();
size = 1;
m24c.reset();
if(mode == "X24C01" ) m24c.load(M24C::Type::X24C01 );
if(mode == "M24C01" ) m24c.load(M24C::Type::M24C01 );
+2 -2
View File
@@ -21,8 +21,8 @@ struct Interface {
virtual auto serialize(serializer&) -> void {}
auto load(Memory::Readable<n16>& rom, string name) -> bool;
auto load(Memory::Writable<n16>& wram, Memory::Writable<n8>& uram, Memory::Writable<n8>& lram, string name) -> bool;
auto load(M24C& m24c, string name) -> bool;
auto load(u32& addr, u32 &size, Memory::Writable<n16>& wram, Memory::Writable<n8>& uram, Memory::Writable<n8>& lram, string name) -> bool;
auto load(u32& addr, u32 &size, M24C& m24c, string name) -> bool;
auto save(Memory::Writable<n16>& wram, Memory::Writable<n8>& uram, Memory::Writable<n8>& lram, string name) -> bool;
auto save(M24C& m24c, string name) -> bool;
+9 -9
View File
@@ -4,15 +4,16 @@ struct Linear : Interface {
Memory::Writable<n16> wram;
Memory::Writable<n8 > uram;
Memory::Writable<n8 > lram;
u32 sramAddr, sramSize;
M24C m24c;
auto load() -> void override {
Interface::load(rom, "program.rom");
if(auto fp = pak->read("save.ram")) {
Interface::load(wram, uram, lram, "save.ram");
Interface::load(sramAddr, sramSize, wram, uram, lram, "save.ram");
}
if(auto fp = pak->read("save.eeprom")) {
Interface::load(m24c, "save.eeprom");
Interface::load(sramAddr, sramSize, m24c, "save.eeprom");
rsda = fp->attribute("rsda").natural();
wsda = fp->attribute("wsda").natural();
wscl = fp->attribute("wscl").natural();
@@ -29,7 +30,7 @@ struct Linear : Interface {
}
auto read(n1 upper, n1 lower, n22 address, n16 data) -> n16 override {
if(address >= 0x200000) {
if(address >= sramAddr && address < sramAddr+sramSize) {
if(wram && ramEnable) {
return wram[address >> 1];
}
@@ -60,7 +61,7 @@ struct Linear : Interface {
//emulating ramWritable will break commercial software:
//it does not appear that many (any?) games actually connect $a130f1.d1 to /WE;
//hence RAM ends up always being writable, and many games fail to set d1=1
if(address >= 0x200000) {
if(address >= sramAddr && address < sramAddr+sramSize) {
if(wram && ramEnable) {
if(upper) wram[address >> 1].byte(1) = data.byte(1);
if(lower) wram[address >> 1].byte(0) = data.byte(0);
@@ -78,7 +79,7 @@ struct Linear : Interface {
}
if(m24c) {
if(rom.size() * 2 > 0x200000 && upper && lower) {
if(rom.size() * 2 > sramAddr && upper && lower) {
eepromEnable = !data.bit(0);
return;
}
@@ -98,17 +99,16 @@ struct Linear : Interface {
}
auto writeIO(n1 upper, n1 lower, n24 address, n16 data) -> void override {
if(!lower) return; //todo: unconfirmed
if(address == 0xa130f0) {
if(rom.size() * 2 > sramAddr && address == 0xa130f0) {
ramEnable = data.bit(0);
ramWritable = data.bit(1);
}
}
auto power(bool reset) -> void override {
ramEnable = 1;
ramEnable = rom.size() * 2 <= sramAddr;
ramWritable = 1;
eepromEnable = rom.size() * 2 <= 0x200000;
eepromEnable = rom.size() * 2 <= sramAddr;
m24c.power();
}
+5 -4
View File
@@ -3,6 +3,7 @@ struct Mega32X : Interface {
Memory::Writable<n16> wram;
Memory::Writable<n8 > uram;
Memory::Writable<n8 > lram;
u32 sramAddr, sramSize;
M24C m24c;
auto load() -> void override {
@@ -14,11 +15,11 @@ struct Mega32X : Interface {
}
if(auto fp = pak->read("save.ram")) {
Interface::load(wram, uram, lram, "save.ram");
Interface::load(sramAddr, sramSize, wram, uram, lram, "save.ram");
}
if(auto fp = pak->read("save.eeprom")) {
Interface::load(m24c, "save.eeprom");
Interface::load(sramAddr, sramSize, m24c, "save.eeprom");
rsda = fp->attribute("rsda").natural();
wsda = fp->attribute("wsda").natural();
wscl = fp->attribute("wscl").natural();
@@ -36,7 +37,7 @@ struct Mega32X : Interface {
}
auto read(n1 upper, n1 lower, n22 address, n16 data) -> n16 override {
if(address >= 0x200000) {
if(address >= sramAddr && address < sramAddr+sramSize) {
if(wram) {
return wram[address >> 1];
}
@@ -60,7 +61,7 @@ struct Mega32X : Interface {
}
auto write(n1 upper, n1 lower, n22 address, n16 data) -> void override {
if(address >= 0x200000) {
if(address >= sramAddr && address < sramAddr+sramSize) {
if(wram) {
if(upper) wram[address >> 1].byte(1) = data.byte(1);
if(lower) wram[address >> 1].byte(0) = data.byte(0);
+3 -2
View File
@@ -1,6 +1,7 @@
auto CPU::read(n1 upper, n1 lower, n24 address, n16 data) -> n16 {
auto CPU::read(n1 upper, n1 lower, n24 address, n16) -> n16 {
while(bus.acquired()) wait(1);
return bus.read(upper, lower, address, data);
//using m68k prefetch for open-bus data
return bus.read(upper, lower, address, r.irc);
}
auto CPU::write(n1 upper, n1 lower, n24 address, n16 data) -> void {
-1
View File
@@ -61,7 +61,6 @@ auto CPU::main() -> void {
auto CPU::step(u32 clocks) -> void {
refresh.ram += clocks;
while(refresh.ram >= 133) refresh.ram -= 133;
refresh.external += clocks;
Thread::step(clocks);
cyclesUntilSync -= clocks;
+17 -3
View File
@@ -5,6 +5,10 @@ struct CPU : M68000, Thread {
Memory::Readable<n16> tmss;
Memory::Writable<n16> ram;
// Bus locking is unavailable for the main cpu of MegaDrive models 1 & 2,
// preventing the TAS instruction from working correctly in most cases.
auto lockable() -> bool override { return false; }
struct Debugger {
//debugger.cpp
auto load(Node::Object) -> void;
@@ -43,7 +47,7 @@ struct CPU : M68000, Thread {
auto power(bool reset) -> void;
//bus.cpp
auto read(n1 upper, n1 lower, n24 address, n16 data = 0) -> n16 override;
auto read(n1 upper, n1 lower, n24 address, n16 _ = 0) -> n16 override;
auto write(n1 upper, n1 lower, n24 address, n16 data) -> void override;
//io.cpp
@@ -62,8 +66,18 @@ struct CPU : M68000, Thread {
} io;
struct Refresh {
n8 ram;
n7 external;
int ram;
int ramEnd;
int external;
int externalEnd;
static constexpr int ramLowBound = 113;
static constexpr int ramHighBound = 132;
static constexpr int ramLength = 3;
static constexpr int externalLowBound = 126;
static constexpr int externalHighBound = 132;
static constexpr int externalLength = 2;
} refresh;
struct State {
+4 -4
View File
@@ -2,9 +2,9 @@
auto CPU::readIO(n1 upper, n1 lower, n24 address, n16 data) -> n16 {
if(address >= 0xa10000 && address <= 0xa100ff) {
if(!lower) return data; //even byte writes ignored
address.bit(5,7) = 0; //a10020-a100ff mirrors a10000-a1001f
if(!lower) return data.byte(0) << 8;
address.bit(5,7) = 0; //a10020-a100ff mirrors a10000-a1001f
switch(address) {
case 0xa10000:
data.bit(0) = io.version; //0 = Model 1; 1 = Model 2+
@@ -38,11 +38,11 @@ auto CPU::readIO(n1 upper, n1 lower, n24 address, n16 data) -> n16 {
break;
}
return data;
return data.byte(1)=data.byte(0), data;
}
if(address >= 0xa11100 && address <= 0xa111ff) {
data.bit(8) = apu.busownerAPU();
data.bit(8) = !apu.busgrantedCPU();
return data;
}
+2
View File
@@ -6,6 +6,8 @@ auto CPU::serialize(serializer& s) -> void {
s(io.romEnable);
s(io.vdpEnable);
s(refresh.ram);
s(refresh.ramEnd);
s(refresh.external);
s(refresh.externalEnd);
s(state.interruptPending);
}
+1 -1
View File
@@ -17,7 +17,7 @@ auto M32X::SH7604::Debugger::load(Node::Object parent) -> void {
}
auto M32X::SH7604::Debugger::instruction() -> void {
if(tracer.instruction->enabled() && tracer.instruction->address(self->PC - 4)) {
if(tracer.instruction->enabled() && tracer.instruction->address(self->regs.PC - 4)) {
tracer.instruction->notify(self->disassembleInstruction(), self->disassembleContext());
}
}
+10
View File
@@ -50,6 +50,16 @@ auto M32X::PWM::step(u32 clocks) -> void {
auto M32X::PWM::power(bool reset) -> void {
Thread::create(23'020'200, {&M32X::PWM::main, this});
lmode = 0;
rmode = 0;
mono = 0;
dreqIRQ = 0;
timer = 0;
cycle = 0;
periods = 0;
counter = 0;
lsample = 0;
rsample = 0;
lfifo.flush();
rfifo.flush();
}
+10 -10
View File
@@ -14,27 +14,27 @@ auto M32X::SH7604::unload() -> void {
}
auto M32X::SH7604::main() -> void {
if(!SH2::inDelaySlot() && !SH2::ID) {
if(!SH2::inDelaySlot() && !regs.ID) {
if(irq.vres.active && irq.vres.enable) {
debugger.interrupt("VRES");
irq.vres.active = 0;
return ET = 1, interrupt(14, 71);
return regs.ET = 1, interrupt(14, 71);
}
if(irq.vint.active && irq.vint.enable && SR.I < 12) {
if(irq.vint.active && irq.vint.enable && regs.SR.I < 12) {
debugger.interrupt("VINT");
return ET = 1, interrupt(12, 70);
return regs.ET = 1, interrupt(12, 70);
}
if(irq.hint.active && irq.hint.enable && SR.I < 10) {
if(irq.hint.active && irq.hint.enable && regs.SR.I < 10) {
debugger.interrupt("HINT");
return ET = 1, interrupt(10, 69);
return regs.ET = 1, interrupt(10, 69);
}
if(irq.cmd.active && irq.cmd.enable && SR.I < 8) {
if(irq.cmd.active && irq.cmd.enable && regs.SR.I < 8) {
debugger.interrupt("CMD");
return ET = 1, interrupt(8, 68);
return regs.ET = 1, interrupt(8, 68);
}
if(irq.pwm.active && irq.pwm.enable && SR.I < 6) {
if(irq.pwm.active && irq.pwm.enable && regs.SR.I < 6) {
debugger.interrupt("PWM");
return ET = 1, interrupt(6, 67);
return regs.ET = 1, interrupt(6, 67);
}
}
+11
View File
@@ -13,6 +13,17 @@ auto M32X::VDP::unload() -> void {
auto M32X::VDP::power(bool reset) -> void {
dram.fill(0);
cram.fill(0);
mode = 0;
lines = 0;
priority = 0;
dotshift = 0;
autofillLength = 0;
autofillAddress = 0;
autofillData = 0;
framebufferAccess = 0;
framebufferActive = 0;
framebufferSelect = 0;
hblank = 0;
vblank = 1;
selectFramebuffer(framebufferSelect);
}
+8 -8
View File
@@ -54,17 +54,15 @@ auto MCD::CDD::clock() -> void {
}
auto MCD::CDD::advance() -> void {
//is the next sector still within the current track?
if(auto track = session.inTrack(io.sector + 1)) {
if(track() == io.track) {
io.sector++;
io.sample = 0;
return;
}
io.track = track();
io.sector++;
io.sample = 0;
return;
}
//if not, then the track has been completed
io.status = Status::Paused;
io.status = Status::LeadOut;
io.track = 0xaa;
}
auto MCD::CDD::sample() -> void {
@@ -244,6 +242,8 @@ auto MCD::CDD::process() -> void {
io.status = Status::Playing;
} break;
default:
io.status = Status::CommandError;
}
status[0] = io.status;
+36 -24
View File
@@ -11,6 +11,7 @@ auto MCD::GPU::step(u32 clocks) -> void {
if(!--image.vdots) {
active = 0;
irq.raise();
break;
}
}
}
@@ -26,11 +27,20 @@ auto MCD::GPU::write(n19 address, n4 data) -> void {
}
auto MCD::GPU::render(n19 address, n9 width) -> void {
n8 stampShift = 11 + 4 + stamp.tile.size;
n8 mapShift = (4 << stamp.map.size) - stamp.tile.size;
n4 stampShift = 4;
n4 mapShift = 4 << stamp.map.size;
n11 indexMask = ~0;
n5 pixelOffsetMask = 0x0f;
n2 stampMask = !stamp.tile.size ? 1 : 3;
n23 mapMask = !stamp.map.size ? 0x07ffff : 0x7fffff;
if(stamp.tile.size) {
stampShift++;
mapShift--;
indexMask &= ~3;
pixelOffsetMask |= 0x10;
}
n19 imageWidth = image.vcells+1 << 6;
n24 mapMask = !stamp.map.size ? 0x07ffff : 0x7fffff;
n24 x = mcd.wram[vector.address++] << 8; //13.3 -> 13.11
n24 y = mcd.wram[vector.address++] << 8; //13.3 -> 13.11
@@ -44,30 +54,32 @@ auto MCD::GPU::render(n19 address, n9 width) -> void {
y &= mapMask;
}
n4 output;
n4 output = 0;
if(bool outside = (x | y) & ~mapMask; !outside) {
auto xstamp = x >> stampShift;
auto ystamp = y >> stampShift << mapShift;
auto xtrunc = x >> 11;
auto ytrunc = y >> 11;
auto xstamp = xtrunc >> stampShift;
auto ystamp = ytrunc >> stampShift;
auto data = mcd.wram[stamp.map.address + xstamp + ystamp];
auto index = n10(data >> 0);
auto lroll = n1 (data >> 13); //0 = 0 degrees; 1 = 90 degrees
auto hroll = n1 (data >> 14); //0 = 0 degrees; 1 = 180 degrees
auto hflip = n1 (data >> 15);
auto mapEntry = mcd.wram[stamp.map.address + (ystamp << mapShift) + xstamp];
n11 index = mapEntry & indexMask;
n1 lroll = mapEntry >> 13; //0 = 0 degrees; 1 = 90 degrees
n1 hroll = mapEntry >> 14; //0 = 0 degrees; 1 = 180 degrees
n1 hflip = mapEntry >> 15;
if(index) { //stamp index 0 is not rendered
auto xpixel = n6(x >> 11);
auto ypixel = n6(y >> 11);
if(index) {
if(hflip) { xtrunc = ~xtrunc; }
if(hroll) { xtrunc = ~xtrunc; ytrunc = ~ytrunc; }
if(lroll) { auto t = xtrunc; xtrunc = ~ytrunc; ytrunc = t; }
if(hflip) { xpixel = ~xpixel; }
if(hroll) { xpixel = ~xpixel; ypixel = ~ypixel; }
if(lroll) { auto tpixel = xpixel; xpixel = ~ypixel; ypixel = tpixel; }
n5 xpixel = xtrunc & pixelOffsetMask;
n5 ypixel = ytrunc & pixelOffsetMask;
n6 pixel = n3(xpixel) + n3(ypixel) * 8;
xpixel = xpixel >> 3 & stampMask;
ypixel = ypixel >> 3 & stampMask;
n4 cell = ypixel + xpixel * (1 + stampMask);
output = read(index << 8 | cell << 6 | pixel);
output = read(
index << 8 |
(xpixel & ~7) << stampShift |
ypixel << 3 |
xpixel & 7);
}
}
@@ -79,7 +91,7 @@ auto MCD::GPU::render(n19 address, n9 width) -> void {
case 3: output = input; break;
}
write(address, output);
if(!(++address & 7)) address += (image.vcells + 1 << 6) - 8;
if(!(++address & 7)) address += imageWidth - 8;
x += xstep;
y += ystep;
+1 -1
View File
@@ -252,7 +252,7 @@ auto MCD::writeIO(n1 upper, n1 lower, n24 address, n16 data) -> void {
if(address == 0xff8030) {
if(lower) {
timer.frequency = data.byte(0);
timer.counter = timer.frequency = data.byte(0);
}
}
+2 -2
View File
@@ -67,7 +67,7 @@ auto System::load(Node::System& root, string name) -> bool {
information.name = "Mega Drive";
information.mega32X = 1;
information.megaCD = 0;
cpu.minCyclesBetweenSyncs = 15; // sync approx every 25-26 pixels
cpu.minCyclesBetweenSyncs = 14; // sync approx every 24-25 pixels
}
if(name.match("[Sega] Mega CD (*)")) {
information.name = "Mega Drive";
@@ -159,7 +159,7 @@ auto System::power(bool reset) -> void {
bus.power(reset);
cpu.power(reset);
apu.power(reset); //apu.power() calls opn2.power()
vdp.power(reset); //vdp.power() calls vdp.psg.power()
if(!reset) vdp.power(reset); //vdp.power() calls vdp.psg.power()
controllerPort1.power(reset);
controllerPort2.power(reset);
extensionPort.power(reset);
+7 -2
View File
@@ -1,6 +1,11 @@
auto VDP::DAC::pixel(u32 x) -> void {
if(!pixels) return;
if(!vdp.displayEnable() || vdp.vcounter() == 0x1ff) {
output(0b101 << 9 | vdp.cram.color(vdp.io.backgroundColor));
return;
}
Pixel g = {vdp.io.backgroundColor, 0, 1};
Pixel a = vdp.layerA.pixel(x);
Pixel b = vdp.layerB.pixel(x);
@@ -15,8 +20,8 @@ auto VDP::DAC::pixel(u32 x) -> void {
s = {};
}
auto& bg = a.above() || a.color && !b.above() ? a : b.color ? b : g;
auto& fg = s.above() || s.color && !b.above() && !a.above() ? s : bg;
auto& bg = a.above() || a.solid() && !b.above() ? a : b.solid() ? b : g;
auto& fg = s.above() || s.solid() && !b.above() && !a.above() ? s : bg;
auto pixel = fg;
auto mode = 1; //0 = shadow, 1 = normal, 2 = highlight
+2
View File
@@ -23,6 +23,7 @@ auto VDP::DMA::run() -> bool {
}
auto VDP::DMA::load() -> void {
if(delay > 0) { delay--; return; }
auto address = mode.bit(0) << 23 | source << 1;
auto data = bus.read(1, 1, address);
vdp.writeDataPort(data);
@@ -76,6 +77,7 @@ auto VDP::DMA::power(bool reset) -> void {
mode = 0;
source = 0;
length = 0;
data = 0;
wait = 1;
read = 0;
enable = 0;
+26 -21
View File
@@ -151,22 +151,17 @@ auto VDP::readControlPort() -> n16 {
command.latch = 0;
n16 result;
result.bit( 0) = Region::PAL();
result.bit( 1) = command.pending;
result.bit( 2) = hblank();
result.bit( 3) = vblank() || !io.displayEnable;
result.bit( 4) = io.interlaceMode.bit(0) && field();
result.bit( 5) = sprite.collision;
result.bit( 6) = sprite.overflow;
result.bit( 7) = irq.vblank.pending;
result.bit( 8) = fifo.full();
result.bit( 9) = fifo.empty();
result.bit(10) = 1; //constants (bits 10-15)
result.bit(11) = 0; //todo: should these bits be open bus instead?
result.bit(12) = 1;
result.bit(13) = 1;
result.bit(14) = 0;
result.bit(15) = 0;
result.bit( 0) = Region::PAL();
result.bit( 1) = command.pending;
result.bit( 2) = hblank();
result.bit( 3) = vblank() || !io.displayEnable;
result.bit( 4) = io.interlaceMode.bit(0) && field();
result.bit( 5) = sprite.collision;
result.bit( 6) = sprite.overflow;
result.bit( 7) = irq.vblank.pending;
result.bit( 8) = fifo.full();
result.bit( 9) = fifo.empty();
result.bit(10,15) = cpu.irc().bit(10,15); // open bus
sprite.collision = 0;
sprite.overflow = 0;
@@ -175,6 +170,13 @@ auto VDP::readControlPort() -> n16 {
auto VDP::writeControlPort(n16 data) -> void {
//command write (lo)
// Note: A pending interrupt will be delayed when a register write
// is used to enable that interrupt. Further testing is required,
// but the current method should be sufficient to handle most cases.
// Required for Sesame Street Counting Cafe et al.
irq.delay = 2; // 4 pixel delay (4-6 M68k clocks) from this write
if(command.latch) {
command.latch = 0;
@@ -185,6 +187,7 @@ auto VDP::writeControlPort(n16 data) -> void {
prefetch.read(command.target, command.address);
if(command.pending && dma.mode == 1) dma.delay = 4; // based on measurement noted by Mask of Destiny
dma.wait = dma.mode == 2;
dma.synchronize();
return;
@@ -203,7 +206,9 @@ auto VDP::writeControlPort(n16 data) -> void {
debugger.io(n5(data >> 8), n8(data));
//register write (d13 is ignored)
switch(data.bit(8,12)) {
u5 reg = data.bit(8,12);
if(!io.videoMode5 && reg > 0xA) return;
switch(reg) {
//mode register 1
case 0x00: {
@@ -214,7 +219,6 @@ auto VDP::writeControlPort(n16 data) -> void {
irq.hblank.enable = data.bit(4);
io.leftColumnBlank = data.bit(5);
irq.poll();
if(!io.videoMode4) debug(unimplemented, "[VDP] M4=0");
return;
}
@@ -222,13 +226,15 @@ auto VDP::writeControlPort(n16 data) -> void {
//mode register 2
case 0x01: {
io.videoMode5 = data.bit(2);
io.overscan = data.bit(3);
if(io.overscan ^ data.bit(3)) {
io.overscan = data.bit(3);
vblankcheck();
}
dma.enable = data.bit(4);
irq.vblank.enable = data.bit(5);
io.displayEnable = data.bit(6);
vram.mode = data.bit(7);
irq.poll();
if(!io.videoMode5) debug(unimplemented, "[VDP] M5=0");
return;
}
@@ -281,7 +287,6 @@ auto VDP::writeControlPort(n16 data) -> void {
layers.vscrollMode = data.bit(2);
irq.external.enable = data.bit(3);
irq.poll();
return;
}
+11 -7
View File
@@ -1,32 +1,35 @@
auto VDP::IRQ::poll() -> void {
if(delay) { delay--; return; }
if(external.enable && external.pending) {
vdp.debugger.interrupt(CPU::Interrupt::External);
cpu.raise(CPU::Interrupt::External);
} else {
external.pending = 0;
cpu.lower(CPU::Interrupt::External);
}
if(hblank.enable && hblank.pending) {
vdp.debugger.interrupt(CPU::Interrupt::HorizontalBlank);
cpu.raise(CPU::Interrupt::HorizontalBlank);
} else {
// note: pending H-INT is not cleared when disabled
cpu.lower(CPU::Interrupt::HorizontalBlank);
}
if(vblank.enable && vblank.pending) {
vdp.debugger.interrupt(CPU::Interrupt::VerticalBlank);
cpu.raise(CPU::Interrupt::VerticalBlank);
} else {
vblank.pending = 0;
cpu.lower(CPU::Interrupt::VerticalBlank);
}
}
auto VDP::IRQ::acknowledge(u8 level) -> void {
if(level == 2) external.pending = 0;
if(level == 4) hblank.pending = 0;
if(level == 4) {
// H-INT ack can errantly cancel V-INT if they coincide.
// Required for Fatal Rewind et al.
if(vblank.pending && vblank.enable)
vblank.pending = 0;
else
hblank.pending = 0;
}
if(level == 6) vblank.pending = 0;
}
@@ -34,4 +37,5 @@ auto VDP::IRQ::power(bool reset) -> void {
external = {};
hblank = {};
vblank = {};
delay = 0;
}
Loaded 100 of 560 files, more files were not shown because too many files have changed in this diff. Show more