Compare commits

...
32 Commits
Author SHA1 Message Date
Near 01184dc6bd Update to ares v115 release.
[No official changelog available for this version. -Ed.]
2020-07-24 21:18:00 +00:00
Near 17f1f24dc2 Update to ares v114r25 release.
- PlayStation: implemented all GTE instructions (though certainly with
    many serious bugs remaining)
  - ares: improved Debug class notifications
2020-07-23 03:48:00 +00:00
Near e2a5547ae7 Update to ares v114r24 release.
Ridge Racer now boots and gets in-game, but likely GTE errors prevent it
from being very playable yet.

  - PlayStation: added DMA IRQ support
  - PlayStation: added more GTE instructions
  - ares: started on a new Debug class for notifications (unimplemented
    features, etc.)
2020-07-19 19:53:00 +00:00
Near 6447903966 Update to ares v114r23 release.
- PlayStation: improved timer support
  - PlayStation: added more GPU GP0 rendering commands
  - lucia: split the emulator list and emulator options into separate
    settings panels
  - lucia: added fast boot option for PlayStation and Neo Geo Pocket
    cores
2020-07-17 20:14:00 +00:00
Near f97a1f954e Update to ares v114r22 release.
- PlayStation: fixed masking bug in LWL and LWR instructions
  - PlayStation: improved timer support
  - PlayStation: added EXE side-loading support
  - PlayStation: added fast boot support
  - PlayStation: added libc putchar logging support
2020-07-17 00:07:00 +00:00
Near 5c6ef3eb4d Update to ares v114r21 release.
- PlayStation: improved GTE support
  - PlayStation: improved CD-ROM support
2020-07-15 19:50:00 +00:00
Near ce2abced51 Update to ares v114r20 release.
- PlayStation: implemented CD-DA support
  - PlayStation: implemented CD data seeking and reading support
  - PlayStation: implemented CD-ROM DMA support
2020-07-12 15:18:00 +00:00
Near 50b62604a8 Update to ares v114r19 release.
- PlayStation: started implementing controller support
  - PlayStation: improved texture semi-transparency support
  - PlayStation: fixed a bug in render clipping
2020-07-10 18:43:00 +00:00
Near fb855d62af Update to ares v114r18 release.
- PlayStation: implemented free-running timer mode
  - PlayStation: implemented draw rectangle commands
2020-07-09 19:43:00 +00:00
Near 5f035496bb Update to ares v114r17 release.
- PlayStation: started implementing timers
  - MSX: added more cartridge mappers (Konami SCC, ASCII 8kbit, ASCII
    16kbit, etc)
2020-07-08 11:59:00 +00:00
Near bfdb287505 Update to ares v114r16 release.
- Super Famicom: mosaic fix wasn't exactly right before; now it should
    be
  - PlayStation: started implementing CD interface
  - PlayStation: started implementing GTE coprocessor
2020-07-04 19:46:00 +00:00
Near a37e5ba378 Update to ares v114r15 release.
- PlayStation: added reverb support
2020-07-03 14:37:00 +00:00
Near b12ac07464 Update to ares v114r14 release.
- Super Famicom: fixed bugs in hires + interlaced mosaic rendering
  - PlayStation: started implementing the SPU (no DMA, CD-DA, reverb, or
    sweep support yet)
2020-07-02 11:18:00 +00:00
Near 46bba9b798 Update to ares v114r13 release.
- PlayStation: added I/O handling for the SPU (no emulation yet)
  - PlayStation: added gaussian interpolation table generation
  - Super Famicom: replaced hard-coded constants with gaussian
    interpolation table generation
2020-07-01 08:09:00 +00:00
Near b1b4452d23 Update to ares v114r12 release.
- PlayStation: added dithering, shaded texture, and partial semi-
    transparency rendering support
2020-06-29 12:31:00 +00:00
Near 60bddfc33f Update to ares v114r11 release.
- PlayStation: added gouraud shaded and textured triangle rendering
2020-06-28 06:47:00 +00:00
Near c2a9cc9fbc Update to ares v114r10 release.
- PlayStation: started on GPU renderer (solid triangles only so far)
2020-06-27 08:02:00 +00:00
Near f376ce8499 Update to ares v114r09 release.
- PlayStation: improved DMA support somewhat
  - PlayStation: implemented some GP0 and GP1 commands
2020-06-25 19:31:00 +00:00
Near 0ed46cc2b1 Update to ares v114r08 release.
- PlayStation: fixed a bug in the SLLV instruction
  - PlayStation: implemented interrupts
2020-06-24 09:25:00 +00:00
Near d9ea05c4c4 Update to ares v114r07 release.
- PlayStation: started implementing the CPU SCC (missing some
    registers still)
  - PlayStation: implemented basic DMA support
2020-06-22 21:49:00 +00:00
Near a4caa85c0b Update to ares v114r06 release.
- PlayStation: implemented all core CPU instructions (no SCC or GTE
    instructions yet)
2020-06-19 00:12:00 +00:00
Near 8b0359aa78 Update to ares v114r05 release.
I've started on a Sony PlayStation emulation core with this WIP. The
goal is to work on the MIPS CPU core while I am still well-versed with
the MIPS ISA. The Nintendo 64 core will remain my primary focus,
however.

  - PlayStation: implemented initial driver skeleton (no emulation code
    yet)
  - lucia: added option to group the load menu options into submenus by
    manufacturer
  - lucia: connected Cocoa-specific application menu options to their
    appropriate callbacks
  - hiro/Cocoa: fixed compilation issues for HexEdit (the widget is not
    implemented, however)
  - hiro/Cocoa: fixed a subpixel precision rendering issue causing
    blurry fonts [LIJI]
2020-06-18 15:02:00 +00:00
Near ba05897d75 Update to ares v114r04 release.
This WIP adds non-SIMD implementations of all RSP vector unit
functionality. This allows compiling without SSE, but was mainly added
for debugging SSE issues. It's also useful for documenting in code what
the SSE instructions are doing in C++ code.

  - Nintendo 64: added non-SSE implementation of RSP vector unit
2020-06-16 03:45:00 +00:00
Near 6cd757dae8 Update to ares v114r03 release.
- nall: added bump_allocator class
  - Nintendo 64: restructured dynamic recompilers to be cleaner
2020-06-13 20:40:00 +00:00
Near fb9859ad2f Update to ares v114r02 release.
The new recompilers increase the framerate in Namco Museum from 60fps to
160fps, and in Zelda: Ocarina of Time from 55fps to 135fps (presuming no
RDP renderer.)

  - Nintendo 64: completed basic CPU dynamic recompiler
  - Nintendo 64: completed basic RSP dynamic recompiler
2020-06-12 17:27:00 +00:00
Near f518bcb374 Update to ares v114r01 release.
- Nintendo 64: started work on CPU dynamic recompiler
2020-06-11 21:07:00 +00:00
Near 20469c66e9 Update to ares v114 release.
First public release of ares. Bumped the version number early for the
milestone.

  - SFC: added missing SA1 board definition (for boards without BWRAM)
2020-06-07 14:38:00 +00:00
Near 3559a7659b Update to ares v113r05 release.
- N64: added FPU support for ordered and unordered comparisons
  - N64: reduced red tape in the CPU and RSP instruction decoder switch
    tables
2020-06-01 13:57:00 +00:00
Near 1f45125d45 Update to ares v113r04 release.
Initial required work to attempt implementing a cached interpreter ...

  - N64: moved all CPU and RSP instruction decoding out of opcode
    handlers
2020-05-30 17:32:00 +00:00
Near 03f7fe2b25 Update to ares v113r03 release.
- N64: redesigned the bus handler
  - N64: execute eight CPU instructions per synchronization event
  - N64: range test the CPU Compare register
  - N64: decode more RDP display list commands
2020-05-28 14:24:00 +00:00
Near a05937bfa4 Update to ares v113r02 release.
- ruby: added new FreeBSD UHID driver (to support hotplugging and the
    Xbox 360 D-pad properly)
  - N64: started on Nintendo 64DD support
2020-05-27 11:01:00 +00:00
Near d9d208d615 Update to ares v113r01 release.
- N64: better input mapping for C-buttons
  - lucia: improved input mapping code
  - ruby: disabled FreeBSD SDL joypad hotplugging hack (causes input
    issues in games)
2020-05-26 02:58:00 +00:00
275 changed files with 15700 additions and 3699 deletions

No files matched your search

+4
View File
@@ -46,6 +46,10 @@ ifneq ($(filter $(cores),md),)
include $(ares.path)/md/GNUmakefile
endif
ifneq ($(filter $(cores),ps1),)
include $(ares.path)/ps1/GNUmakefile
endif
ifneq ($(filter $(cores),pce),)
include $(ares.path)/pce/GNUmakefile
endif
Whitespace-only changes.
+12 -2
View File
@@ -1,5 +1,5 @@
database
revision: 2020-01-21
revision: 2020-06-07
//Boards (Production)
@@ -587,7 +587,7 @@ board: SHVC-YJ0N-01
//Boards (Generic)
database
revision: 2020-01-01
revision: 2020-06-07
board: ARM-LOROM-RAM
memory type=ROM content=Program
@@ -887,6 +887,16 @@ board: OBC1-LOROM-RAM
map address=70-71,f0-f1:6000-7fff,e000-ffff mask=0xe000
memory type=RAM content=Save
board: SA1
processor architecture=W65C816S
map address=00-3f,80-bf:2200-23ff
mcu
map address=00-3f,80-bf:8000-ffff mask=0x408000
map address=c0-ff:0000-ffff
memory type=ROM content=Program
memory type=RAM content=Internal
map address=00-3f,80-bf:3000-37ff size=0x800
board: SA1-RAM
processor architecture=W65C816S
map address=00-3f,80-bf:2200-23ff
+1
View File
@@ -1,4 +1,5 @@
#include <ares/ares.hpp>
#include <ares/debug/debug.cpp>
#include <ares/node/node.cpp>
#include <ares/resource/resource.cpp>
+3
View File
@@ -6,6 +6,7 @@
#include <nall/adaptive-array.hpp>
#include <nall/any.hpp>
#include <nall/array.hpp>
#include <nall/bump-allocator.hpp>
#include <nall/chrono.hpp>
#include <nall/directory.hpp>
#include <nall/dl.hpp>
@@ -17,6 +18,7 @@
#include <nall/set.hpp>
#include <nall/shared-pointer.hpp>
#include <nall/string.hpp>
#include <nall/terminal.hpp>
#include <nall/traits.hpp>
#include <nall/unique-pointer.hpp>
#include <nall/variant.hpp>
@@ -58,6 +60,7 @@ namespace ares {
#include <ares/information.hpp>
#include <ares/types.hpp>
#include <ares/random.hpp>
#include <ares/debug/debug.hpp>
#include <ares/node/node.hpp>
#include <ares/platform.hpp>
#include <ares/interface.hpp>
+17
View File
@@ -0,0 +1,17 @@
namespace ares {
Debug _debug;
auto Debug::reset() -> void {
_unimplementedNotices.reset();
}
auto Debug::_unimplemented(const string& text) -> void {
//only warn about missing unimplemented functionality once per type
if(_unimplementedNotices.find(text)) return;
_unimplementedNotices.append(text);
print(terminal::color::magenta("[unimplemented] "), text, "\n");
}
}
+22
View File
@@ -0,0 +1,22 @@
namespace ares {
struct Debug {
static constexpr bool enabled = true;
auto reset() -> void;
template<typename... P> auto unimplemented(P&&... p) -> void {
return _unimplemented({forward<P>(p)...});
}
private:
auto _unimplemented(const string&) -> void;
vector<string> _unimplementedNotices;
};
extern Debug _debug;
}
#define debug(function, ...) if constexpr(ares::_debug.enabled) ares::_debug.function(__VA_ARGS__)
+8 -5
View File
@@ -1,11 +1,14 @@
#pragma once
namespace ares {
static const string Name = "ares";
static const string Version = "113";
static const string License = "GPLv3+";
static const string Website = "https://ares.dev";
static const string Name = "ares";
static const string Version = "115";
static const string Copyright = "ares team";
static const string License = "ISC";
static const string LicenseURI = "https://opensource.org/licenses/ISC";
static const string Website = "ares.dev";
static const string WebsiteURI = "https://ares.dev";
//incremented only when serialization format changes
static const string SerializerVersion = "112";
static const string SerializerVersion = "115";
}
@@ -237,7 +237,7 @@ auto SM83::instruction() -> void {
op(0xee, XOR_Direct_Data, A)
op(0xef, RST_Implied, 0x28)
op(0xf0, LDH_Direct_Address, A)
op(0xf1, POP_Direct, AF)
op(0xf1, POP_Direct_AF, AF)
op(0xf2, LDH_Direct_Indirect, A, C)
op(0xf3, DI)
op(0xf5, PUSH_Direct, AF)
@@ -271,6 +271,10 @@ auto SM83::instructionPOP_Direct(uint16& data) -> void {
data = pop();
}
auto SM83::instructionPOP_Direct_AF(uint16& data) -> void {
data = pop() & ~15; //flag bits 0-3 are forced to zero
}
auto SM83::instructionPUSH_Direct(uint16& data) -> void {
idle();
push(data);
+1 -1
View File
@@ -3,7 +3,7 @@
namespace ares {
#include "registers.cpp"
#include "registers.hpp"
#include "memory.cpp"
#include "algorithms.cpp"
#include "instruction.cpp"
+1
View File
@@ -115,6 +115,7 @@ struct SM83 {
auto instructionOR_Direct_Direct(uint8&, uint8&) -> void;
auto instructionOR_Direct_Indirect(uint8&, uint16&) -> void;
auto instructionPOP_Direct(uint16&) -> void;
auto instructionPOP_Direct_AF(uint16&) -> void;
auto instructionPUSH_Direct(uint16&) -> void;
auto instructionRES_Index_Direct(uint3, uint8&) -> void;
auto instructionRES_Index_Indirect(uint3, uint16&) -> void;
+1 -1
View File
@@ -4,7 +4,7 @@
namespace ares {
#include "disassembler.cpp"
#include "registers.cpp"
#include "registers.hpp"
#include "memory.cpp"
#include "instruction.cpp"
#include "algorithms.cpp"
+43
View File
@@ -0,0 +1,43 @@
//ASCII 16kbit
struct ASC16 : Interface {
using Interface::Interface;
Memory::Readable<uint8> rom;
auto load(Markup::Node document) -> void override {
auto board = document["game/board"];
Interface::load(rom, board["memory(type=ROM,content=Program)"]);
}
auto save(Markup::Node document) -> void override {
}
auto unload() -> void override {
}
auto read(uint16 address, uint8 data) -> uint8 override {
if(address >= 0x4000 && address <= 0x7fff) data = rom.read(bank[0] << 14 | (uint14)address);
if(address >= 0x8000 && address <= 0xbfff) data = rom.read(bank[1] << 14 | (uint14)address);
if(address >= 0xc000 && address <= 0xffff) data = rom.read(bank[0] << 14 | (uint14)address);
if(address >= 0x0000 && address <= 0x3fff) data = rom.read(bank[1] << 14 | (uint14)address);
return data;
}
auto write(uint16 address, uint8 data) -> void override {
if(address >= 0x6000 && address <= 0x6fff) bank[0] = data;
if(address >= 0x7000 && address <= 0xbfff) bank[1] = data;
}
auto power() -> void override {
bank[0] = 0x0f; //R-Type = 0x0f; others = 0x00
bank[1] = 0x00;
}
auto serialize(serializer& s) -> void override {
s.array(bank);
}
uint8 bank[2];
};
+51
View File
@@ -0,0 +1,51 @@
//ASCII 8kbit
struct ASC8 : Interface {
using Interface::Interface;
Memory::Readable<uint8> rom;
auto load(Markup::Node document) -> void override {
auto board = document["game/board"];
Interface::load(rom, board["memory(type=ROM,content=Program)"]);
}
auto save(Markup::Node document) -> void override {
}
auto unload() -> void override {
}
auto read(uint16 address, uint8 data) -> uint8 override {
if(address >= 0x4000 && address <= 0x5fff) data = rom.read(bank[0] << 13 | (uint13)address);
if(address >= 0x6000 && address <= 0x7fff) data = rom.read(bank[1] << 13 | (uint13)address);
if(address >= 0x8000 && address <= 0x9fff) data = rom.read(bank[2] << 13 | (uint13)address);
if(address >= 0xa000 && address <= 0xbfff) data = rom.read(bank[3] << 13 | (uint13)address);
if(address >= 0xc000 && address <= 0xdfff) data = rom.read(bank[0] << 13 | (uint13)address);
if(address >= 0xe000 && address <= 0xffff) data = rom.read(bank[1] << 13 | (uint13)address);
if(address >= 0x0000 && address <= 0x1fff) data = rom.read(bank[2] << 13 | (uint13)address);
if(address >= 0x2000 && address <= 0x3fff) data = rom.read(bank[3] << 13 | (uint13)address);
return data;
}
auto write(uint16 address, uint8 data) -> void override {
if(address >= 0x6000 && address <= 0x67ff) bank[0] = data;
if(address >= 0x6800 && address <= 0x6fff) bank[1] = data;
if(address >= 0x7000 && address <= 0x77ff) bank[2] = data;
if(address >= 0x7800 && address <= 0x7fff) bank[3] = data;
}
auto power() -> void override {
bank[0] = 0;
bank[1] = 0;
bank[2] = 0;
bank[3] = 0;
}
auto serialize(serializer& s) -> void override {
s.array(bank);
}
uint8 bank[4];
};
+50
View File
@@ -0,0 +1,50 @@
namespace Board {
#include "asc16.cpp"
#include "asc8.cpp"
#include "cross-blaim.cpp"
#include "konami.cpp"
#include "konami-scc.cpp"
#include "linear.cpp"
#include "super-lode-runner.cpp"
#include "super-pierrot.cpp"
auto Interface::load(Memory::Readable<uint8>& memory, Markup::Node node) -> bool {
if(!node) return false;
memory.allocate(node["size"].natural());
auto name = string{node["content"].string(), ".", node["type"].string()}.downcase();
if(auto fp = platform->open(cartridge.node, name, File::Read, File::Required)) {
memory.load(fp);
return true;
}
return false;
}
auto Interface::load(Memory::Writable<uint8>& memory, Markup::Node node) -> bool {
if(!node) return false;
memory.allocate(node["size"].natural());
if(node["volatile"]) return true;
auto name = string{node["content"].string(), ".", node["type"].string()}.downcase();
if(auto fp = platform->open(cartridge.node, name, File::Read)) {
memory.load(fp);
return true;
}
return false;
}
auto Interface::save(Memory::Writable<uint8>& memory, Markup::Node node) -> bool {
if(!node) return false;
if(node["volatile"]) return true;
auto name = string{node["content"].string(), ".", node["type"].string()}.downcase();
if(auto fp = platform->open(cartridge.node, name, File::Write)) {
memory.save(fp);
return true;
}
return false;
}
auto Interface::main() -> void {
cartridge.step(system.colorburst());
}
}
+22
View File
@@ -0,0 +1,22 @@
namespace Board {
struct Interface {
Interface(Cartridge& cartridge) : cartridge(cartridge) {}
virtual ~Interface() = default;
virtual auto load(Markup::Node) -> void {}
virtual auto save(Markup::Node) -> void {}
virtual auto unload() -> void {}
virtual auto main() -> void;
virtual auto read(uint16 address, uint8 data) -> uint8 { return data; }
virtual auto write(uint16 address, uint8 data) -> void {}
virtual auto power() -> void {}
virtual auto serialize(serializer&) -> void {}
auto load(Memory::Readable<uint8>&, Markup::Node) -> bool;
auto load(Memory::Writable<uint8>&, Markup::Node) -> bool;
auto save(Memory::Writable<uint8>&, Markup::Node) -> bool;
Cartridge& cartridge;
};
}
+56
View File
@@ -0,0 +1,56 @@
//Cross Blaim
struct CrossBlaim : Interface {
using Interface::Interface;
Memory::Readable<uint8> rom;
auto load(Markup::Node document) -> void override {
auto board = document["game/board"];
Interface::load(rom, board["memory(type=ROM,content=Program)"]);
}
auto save(Markup::Node document) -> void override {
}
auto unload() -> void override {
}
auto read(uint16 address, uint8 data) -> uint8 override {
if(mode == 0 || mode == 1) {
if(address >> 14 == 0) data = rom.read((uint14)address + 16_KiB);
if(address >> 14 == 1) data = rom.read((uint14)address);
if(address >> 14 == 2) data = rom.read((uint14)address + 16_KiB);
if(address >> 14 == 3) data = rom.read((uint14)address + 16_KiB);
}
if(mode == 2) {
if(address >> 14 == 0) data = 0xff;
if(address >> 14 == 1) data = rom.read((uint14)address);
if(address >> 14 == 2) data = rom.read((uint14)address + 32_KiB);
if(address >> 14 == 3) data = 0xff;
}
if(mode == 3) {
if(address >> 14 == 0) data = 0xff;
if(address >> 14 == 1) data = rom.read((uint14)address);
if(address >> 14 == 2) data = rom.read((uint14)address + 48_KiB);
if(address >> 14 == 3) data = 0xff;
}
return data;
}
auto write(uint16 address, uint8 data) -> void override {
mode = data;
}
auto power() -> void override {
mode = 0;
}
auto serialize(serializer& s) -> void override {
s.integer(mode);
}
uint2 mode;
};
+252
View File
@@ -0,0 +1,252 @@
//Konami (with Sound Creative Chip)
struct KonamiSCC : Interface {
using Interface::Interface;
Memory::Readable<uint8> rom;
Node::Stream stream;
auto load(Markup::Node document) -> void override {
auto board = document["game/board"];
Interface::load(rom, board["memory(type=ROM,content=Program)"]);
stream = cartridge.node->append<Node::Stream>("SCC");
stream->setChannels(1);
stream->setFrequency(system.colorburst() / 16.0);
stream->addHighPassFilter(20.0, 1);
}
auto save(Markup::Node document) -> void override {
}
auto unload() -> void override {
}
auto main() -> void override {
int sample = 256 * 5;
for(auto& voice : voices) {
if(voice.frequency <= 8) continue; //voice is halted when frequency < 9
voice.clock += 32;
while(voice.clock > voice.frequency) {
voice.clock -= voice.frequency + 1;
voice.counter++;
}
sample += voice.wave[voice.counter] * voice.volume * voice.key >> 3;
}
stream->sample(mixer[sample] / 32768.0);
cartridge.step(16);
}
auto read(uint16 address, uint8 data) -> uint8 override {
if(address >= 0x4000 && address <= 0x5fff) data = rom.read(bank[0] << 13 | (uint13)address);
if(address >= 0x6000 && address <= 0x7fff) data = rom.read(bank[1] << 13 | (uint13)address);
if(address >= 0x8000 && address <= 0x9fff) data = rom.read(bank[2] << 13 | (uint13)address);
if(address >= 0xa000 && address <= 0xbfff) data = rom.read(bank[3] << 13 | (uint13)address);
if(address >= 0xc000 && address <= 0xdfff) data = rom.read(bank[0] << 13 | (uint13)address);
if(address >= 0xe000 && address <= 0xffff) data = rom.read(bank[1] << 13 | (uint13)address);
if(address >= 0x0000 && address <= 0x1fff) data = rom.read(bank[2] << 13 | (uint13)address);
if(address >= 0x2000 && address <= 0x3fff) data = rom.read(bank[3] << 13 | (uint13)address);
address.bit(8) = 0; //SCC ignores A8
if(address >= 0x9800 && address <= 0x981f) {
data = voices[0].wave[address & 0x1f];
if(test.bit(6)) data = voices[0].wave[address + voices[0].counter & 0x1f];
}
if(address >= 0x9820 && address <= 0x983f) {
data = voices[1].wave[address & 0x1f];
if(test.bit(6)) data = voices[1].wave[address + voices[1].counter & 0x1f];
}
if(address >= 0x9840 && address <= 0x985f) {
data = voices[2].wave[address & 0x1f];
if(test.bit(6)) data = voices[2].wave[address + voices[2].counter & 0x1f];
}
if(address >= 0x9860 && address <= 0x987f) {
data = voices[3].wave[address & 0x1f];
if(test.bit(6) || test.bit(7)) data = voices[3].wave[address + voices[3 + test.bit(6)].counter & 0x1f];
}
if(address >= 0x9880 && address <= 0x98df) {
data = 0xff;
}
if(address >= 0x98e0 && address <= 0x98ff) {
//reading the test register sets it to 0xff
data = test = 0xff;
}
return data;
}
auto write(uint16 address, uint8 data) -> void override {
if(address >= 0x5000 && address <= 0x57ff) bank[0] = data;
if(address >= 0x7000 && address <= 0x77ff) bank[1] = data;
if(address >= 0x9000 && address <= 0x97ff) bank[2] = data;
if(address >= 0xb000 && address <= 0xb7ff) bank[3] = data;
address.bit(8) = 0; //SCC ignores A8
if(address >= 0x9800 && address <= 0x981f && !test.bit(6)) {
voices[0].wave[address & 0x1f] = data;
}
if(address >= 0x9820 && address <= 0x983f && !test.bit(6)) {
voices[1].wave[address & 0x1f] = data;
}
if(address >= 0x9840 && address <= 0x985f && !test.bit(6)) {
voices[2].wave[address & 0x1f] = data;
}
if(address >= 0x9860 && address <= 0x987f && !test.bit(6) && !test.bit(7)) {
voices[3].wave[address & 0x1f] = data;
voices[4].wave[address & 0x1f] = data; //shares data with wave channel 3
}
if(address == 0x9880) {
voices[0].frequency.bit(0, 7) = data.bit(0,7);
if(voices[0].frequency < 9) voices[0].clock = 0;
if(test.bit(5)) voices[0].clock = 0, voices[0].counter = 0;
}
if(address == 0x9881) {
voices[0].frequency.bit(8,11) = data.bit(0,3);
if(voices[0].frequency < 9) voices[0].clock = 0;
if(test.bit(5)) voices[0].clock = 0, voices[0].counter = 0;
}
if(address == 0x9882) {
voices[1].frequency.bit(0, 7) = data.bit(0,7);
if(voices[1].frequency < 9) voices[1].clock = 0;
if(test.bit(5)) voices[1].clock = 0, voices[1].counter = 0;
}
if(address == 0x9883) {
voices[1].frequency.bit(8,11) = data.bit(0,3);
if(voices[1].frequency < 9) voices[1].clock = 0;
if(test.bit(5)) voices[1].clock = 0, voices[1].counter = 0;
}
if(address == 0x9884) {
voices[2].frequency.bit(0, 7) = data.bit(0,7);
if(voices[2].frequency < 9) voices[2].clock = 0;
if(test.bit(5)) voices[2].clock = 0, voices[2].counter = 0;
}
if(address == 0x9885) {
voices[2].frequency.bit(8,11) = data.bit(0,3);
if(voices[2].frequency < 9) voices[2].clock = 0;
if(test.bit(5)) voices[2].clock = 0, voices[2].counter = 0;
}
if(address == 0x9886) {
voices[3].frequency.bit(0, 7) = data.bit(0,7);
if(voices[3].frequency < 9) voices[3].clock = 0;
if(test.bit(5)) voices[3].clock = 0, voices[3].counter = 0;
}
if(address == 0x9887) {
voices[3].frequency.bit(8,11) = data.bit(0,3);
if(voices[3].frequency < 9) voices[3].clock = 0;
if(test.bit(5)) voices[3].clock = 0, voices[3].counter = 0;
}
if(address == 0x9888) {
voices[4].frequency.bit(0, 7) = data.bit(0,7);
if(voices[4].frequency < 9) voices[4].clock = 0;
if(test.bit(5)) voices[4].clock = 0, voices[4].counter = 0;
}
if(address == 0x9889) {
voices[4].frequency.bit(8,11) = data.bit(0,3);
if(voices[4].frequency < 9) voices[4].clock = 0;
if(test.bit(5)) voices[4].clock = 0, voices[4].counter = 0;
}
if(address == 0x988a) {
voices[0].volume = data.bit(0,3);
}
if(address == 0x988b) {
voices[1].volume = data.bit(0,3);
}
if(address == 0x988c) {
voices[2].volume = data.bit(0,3);
}
if(address == 0x988d) {
voices[3].volume = data.bit(0,3);
}
if(address == 0x988e) {
voices[4].volume = data.bit(0,3);
}
if(address == 0x988f) {
voices[0].key = data.bit(0);
voices[1].key = data.bit(1);
voices[2].key = data.bit(2);
voices[3].key = data.bit(3);
voices[4].key = data.bit(4);
}
if(address >= 0x98e0 && address <= 0x98ff) test = data;
}
auto power() -> void override {
bank[0] = 0;
bank[1] = 1;
bank[2] = 2;
bank[3] = 3;
voices[0] = {};
voices[1] = {};
voices[2] = {};
voices[3] = {};
voices[4] = {};
test = 0;
mixer.resize(512 * 5);
auto table = mixer.data() + 256 * 5;
for(int n : range(256 * 5)) {
int16 volume = n * 8 * 16 / 5;
table[+n] = +volume;
table[-n] = -volume;
}
}
auto serialize(serializer& s) -> void override {
s.array(bank);
for(auto& voice : voices) {
s.integer(voice.clock);
s.integer(voice.frequency);
s.integer(voice.counter);
s.integer(voice.volume);
s.integer(voice.key);
s.array(voice.wave);
}
s.integer(test);
}
uint8 bank[4];
struct Voice {
uint16 clock;
uint12 frequency;
uint5 counter;
uint4 volume;
uint1 key;
int8 wave[32];
} voices[5];
uint8 test;
//unserialized:
vector<int16> mixer;
};
+45
View File
@@ -0,0 +1,45 @@
//Konami (without Sound Creative Chip)
struct Konami : Interface {
using Interface::Interface;
Memory::Readable<uint8> rom;
auto load(Markup::Node document) -> void override {
auto board = document["game/board"];
Interface::load(rom, board["memory(type=ROM,content=Program)"]);
}
auto save(Markup::Node document) -> void override {
}
auto unload() -> void override {
}
auto read(uint16 address, uint8 data) -> uint8 override {
if(address >> 13 == 2) data = rom.read(bank[0] << 13 | (uint13)address);
if(address >> 13 == 3) data = rom.read(bank[1] << 13 | (uint13)address);
if(address >> 13 == 4) data = rom.read(bank[2] << 13 | (uint13)address);
if(address >> 13 == 5) data = rom.read(bank[3] << 13 | (uint13)address);
return data;
}
auto write(uint16 address, uint8 data) -> void override {
if(address >> 13 == 2) bank[0] = 0;
if(address >> 13 == 3) bank[1] = data;
if(address >> 13 == 4) bank[2] = data;
if(address >> 13 == 5) bank[3] = data;
}
auto power() -> void override {
bank[0] = 0;
bank[1] = 1;
bank[2] = 0;
bank[3] = 0;
}
auto serialize(serializer& s) -> void override {
s.array(bank);
}
uint8 bank[4];
};
+29
View File
@@ -0,0 +1,29 @@
struct Linear : Interface {
using Interface::Interface;
Memory::Readable<uint8> rom;
auto load(Markup::Node document) -> void override {
auto board = document["game/board"];
Interface::load(rom, board["memory(type=ROM,content=Program)"]);
}
auto save(Markup::Node document) -> void override {
}
auto unload() -> void override {
}
auto read(uint16 address, uint8 data) -> uint8 override {
data = rom.read(address);
return data;
}
auto write(uint16 address, uint8 data) -> void override {
}
auto power() -> void override {
}
auto serialize(serializer& s) -> void override {
}
};
@@ -0,0 +1,37 @@
//Super Lode Runner
//(not working: requires MSX BASIC)
struct SuperLodeRunner : Interface {
using Interface::Interface;
Memory::Readable<uint8> rom;
auto load(Markup::Node document) -> void override {
auto board = document["game/board"];
Interface::load(rom, board["memory(type=ROM,content=Program)"]);
}
auto save(Markup::Node document) -> void override {
}
auto unload() -> void override {
}
auto read(uint16 address, uint8 data) -> uint8 override {
if(address >= 0x8000 && address <= 0xbfff) data = rom.read(bank << 14 | (uint14)address);
return data;
}
auto write(uint16 address, uint8 data) -> void override {
if(address >= 0x0000 && address <= 0x3fff) bank = data;
}
auto power() -> void override {
bank = 0;
}
auto serialize(serializer& s) -> void override {
s.integer(bank);
}
uint8 bank;
};
@@ -0,0 +1,47 @@
//Super Pierrot
//(not working)
struct SuperPierrot : Interface {
using Interface::Interface;
Memory::Readable<uint8> rom;
auto load(Markup::Node document) -> void override {
auto board = document["game/board"];
Interface::load(rom, board["memory(type=ROM,content=Program)"]);
}
auto save(Markup::Node document) -> void override {
}
auto unload() -> void override {
}
auto read(uint16 address, uint8 data) -> uint8 override {
if(address >= 0x4000 && address <= 0x7fff) data = rom.read(bank[0] << 14 | (uint14)address);
if(address >= 0x8000 && address <= 0xbfff) data = rom.read(bank[1] << 14 | (uint14)address);
return data;
}
auto write(uint16 address, uint8 data) -> void override {
if(address >= 0x4000 && address <= 0x4fff) bank[0] = data;
if(address >= 0x6000 && address <= 0x6fff) bank[0] = data;
if(address >= 0x8000 && address <= 0x8fff) bank[0] = data;
if(address >= 0xa000 && address <= 0xafff) bank[0] = data;
if(address >= 0x5000 && address <= 0x5fff) bank[1] = data;
if(address >= 0x7000 && address <= 0x7fff) bank[1] = data;
if(address >= 0x9000 && address <= 0x9fff) bank[1] = data;
if(address >= 0xa000 && address <= 0xafff) bank[1] = data;
}
auto power() -> void override {
bank[0] = 0;
bank[1] = 0;
}
auto serialize(serializer& s) -> void override {
s.array(bank);
}
uint8 bank[2];
};
+29 -59
View File
@@ -4,6 +4,7 @@ namespace ares::MSX {
Cartridge& cartridge = cartridgeSlot.cartridge;
Cartridge& expansion = expansionSlot.cartridge;
#include "board/board.cpp"
#include "slot.cpp"
#include "serialization.cpp"
@@ -23,87 +24,56 @@ auto Cartridge::connect() -> void {
auto document = BML::unserialize(information.manifest);
information.name = document["game/label"].string();
information.region = document["game/region"].string();
information.board = document["game/board"].string();
if(auto memory = document["game/board/memory(type=ROM,content=Program)"]) {
rom.allocate(memory["size"].natural());
if(auto fp = platform->open(node, "program.rom", File::Read, File::Required)) {
rom.load(fp);
}
}
if(auto memory = document["game/board/memory(type=RAM,content=Save)"]) {
ram.allocate(memory["size"].natural());
if(auto fp = platform->open(node, "save.ram", File::Read)) {
ram.load(fp);
}
}
if(information.board == "ASC16") board = new Board::ASC16{*this};
if(information.board == "ASC8") board = new Board::ASC8{*this};
if(information.board == "CrossBlaim") board = new Board::CrossBlaim{*this};
if(information.board == "Konami") board = new Board::Konami{*this};
if(information.board == "KonamiSCC") board = new Board::KonamiSCC{*this};
if(information.board == "Linear") board = new Board::Linear{*this};
if(information.board == "SuperLodeRunner") board = new Board::SuperLodeRunner{*this};
if(information.board == "SuperPierrot") board = new Board::SuperPierrot{*this};
if(!board) board = new Board::KonamiSCC{*this};
board->load(document);
power();
}
auto Cartridge::disconnect() -> void {
if(!node) return;
save();
rom.reset();
ram.reset();
node = {};
if(board) board->unload(), board.reset();
node.reset();
}
auto Cartridge::save() -> void {
if(!node) return;
auto document = BML::unserialize(information.manifest);
board->save(document);
}
if(auto memory = document["game/board/memory(type=RAM,content=Save)"]) {
if(auto fp = platform->open(node, "save.ram", File::Write)) {
ram.save(fp);
}
}
auto Cartridge::main() -> void {
if(board) return board->main();
step(system.colorburst());
}
auto Cartridge::step(uint clocks) -> void {
Thread::step(clocks);
Thread::synchronize(cpu);
}
auto Cartridge::power() -> void {
Thread::create(system.colorburst(), {&Cartridge::main, this});
if(board) board->power();
}
uint2 RB; //Cross Blaim
uint8 B8K[4]={0,1,0,0}; //Konami 8K (non-SCC)
auto Cartridge::read(uint16 address) -> uint8 {
if(!rom) return 0xff;
/*
if(RB==0||RB==1){
if(address>>14==0)return rom.read((uint14)address+16_KiB);
if(address>>14==1)return rom.read((uint14)address);
if(address>>14==2)return rom.read((uint14)address+16_KiB);
if(address>>14==3)return rom.read((uint14)address+16_KiB);
}
if(RB==2){
if(address>>14==0)return 0xff;
if(address>>14==1)return rom.read((uint14)address);
if(address>>14==2)return rom.read((uint14)address+32_KiB);
if(address>>14==3)return 0xff;
}
if(RB==3){
if(address>>14==0)return 0xff;
if(address>>14==1)return rom.read((uint14)address);
if(address>>14==2)return rom.read((uint14)address+48_KiB);
if(address>>14==3)return 0xff;
}
*/
if(address>>13==2)return rom.read(B8K[0]<<13|(uint13)address);
if(address>>13==3)return rom.read(B8K[1]<<13|(uint13)address);
if(address>>13==4)return rom.read(B8K[2]<<13|(uint13)address);
if(address>>13==5)return rom.read(B8K[3]<<13|(uint13)address);
return rom.read(address);
if(board) return board->read(address, 0xff);
return 0xff;
}
auto Cartridge::write(uint16 address, uint8 data) -> void {
RB = data;
if(address>>13==2)B8K[0]=0;
if(address>>13==3)B8K[1]=data;
if(address>>13==4)B8K[2]=data;
if(address>>13==5)B8K[3]=data;
if(board) return board->write(address, data);
}
}
+9 -1
View File
@@ -1,4 +1,7 @@
struct Cartridge {
struct Cartridge;
#include "board/board.hpp"
struct Cartridge : Thread {
Node::Peripheral node;
Memory::Readable<uint8> rom;
Memory::Writable<uint8> ram;
@@ -13,6 +16,8 @@ struct Cartridge {
auto disconnect() -> void;
auto save() -> void;
auto main() -> void;
auto step(uint clocks) -> void;
auto power() -> void;
auto read(uint16 address) -> uint8;
@@ -21,11 +26,14 @@ struct Cartridge {
//serialization.cpp
auto serialize(serializer&) -> void;
unique_pointer<Board::Interface> board;
private:
struct Information {
string manifest;
string name;
string region;
string board;
} information;
};
+1 -1
View File
@@ -1,3 +1,3 @@
auto Cartridge::serialize(serializer& s) -> void {
if(ram) s.array(ram.data(), ram.size());
if(board) board->serialize(s);
}
+2 -1
View File
@@ -1,5 +1,5 @@
ares.objects += ares-n64-interface ares-n64-memory ares-n64-system
ares.objects += ares-n64-cartridge ares-n64-controller
ares.objects += ares-n64-cartridge ares-n64-controller ares-n64-dd
ares.objects += ares-n64-mi ares-n64-vi ares-n64-ai
ares.objects += ares-n64-pi ares-n64-ri ares-n64-si
ares.objects += ares-n64-rdram ares-n64-cpu ares-n64-rdp ares-n64-rsp
@@ -9,6 +9,7 @@ $(object.path)/ares-n64-memory.o: $(ares.path)/n64/memory/memory.cpp
$(object.path)/ares-n64-system.o: $(ares.path)/n64/system/system.cpp
$(object.path)/ares-n64-cartridge.o: $(ares.path)/n64/cartridge/cartridge.cpp
$(object.path)/ares-n64-controller.o: $(ares.path)/n64/controller/controller.cpp
$(object.path)/ares-n64-dd.o: $(ares.path)/n64/dd/dd.cpp
$(object.path)/ares-n64-sp.o: $(ares.path)/n64/sp/sp.cpp
$(object.path)/ares-n64-dp.o: $(ares.path)/n64/dp/dp.cpp
$(object.path)/ares-n64-mi.o: $(ares.path)/n64/mi/mi.cpp
+3 -3
View File
@@ -1,6 +1,6 @@
//Audio Interface
struct AI : Thread {
struct AI : Thread, Memory::IO<AI> {
Node::Component node;
Node::Stream stream;
@@ -23,8 +23,8 @@ struct AI : Thread {
auto power() -> void;
//io.cpp
auto readIO(u32 address) -> u32;
auto writeIO(u32 address, uint32 data) -> void;
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
+3 -2
View File
@@ -7,7 +7,7 @@ static const vector<string> registerNames = {
"AI_BITRATE",
};
auto AI::readIO(u32 address) -> u32 {
auto AI::readWord(u32 address) -> u32 {
address = (address & 0xfffff) >> 2;
uint32 data;
@@ -31,8 +31,9 @@ auto AI::readIO(u32 address) -> u32 {
return data;
}
auto AI::writeIO(u32 address, uint32 data) -> void {
auto AI::writeWord(u32 address, u32 data_) -> void {
address = (address & 0xfffff) >> 2;
uint32 data = data_;
if(address == 0) {
//AI_DRAM_ADDRESS
+2
View File
@@ -29,6 +29,8 @@ auto Cartridge::connect() -> void {
if(auto fp = platform->open(node, "program.rom", File::Read, File::Required)) {
rom.load(fp);
}
} else {
rom.allocate(16);
}
power();
+1 -1
View File
@@ -1,6 +1,6 @@
struct Cartridge {
Node::Peripheral node;
Memory rom;
Memory::Readable rom;
auto manifest() const -> string { return information.manifest; }
auto name() const -> string { return information.name; }
+2 -2
View File
@@ -38,8 +38,8 @@ auto Gamepad::read() -> uint32 {
platform->input(start);
uint32 data;
data.byte(0) = y->value() >> 8;
data.byte(1) = x->value() >> 8;
data.byte(0) = -y->value() >> 8;
data.byte(1) = +x->value() >> 8;
data.bit(16) = cameraRight->value();
data.bit(17) = cameraLeft->value();
data.bit(18) = cameraDown->value();
+100 -3
View File
@@ -3,13 +3,105 @@
#include "scc-registers.cpp"
#include "fpu-registers.cpp"
#include "memory.cpp"
#include "instruction.cpp"
#include "decoder.cpp"
#include "cpu-instructions.cpp"
#include "scc-instructions.cpp"
#include "fpu-instructions.cpp"
#include "recompiler.cpp"
#include "disassembler.cpp"
#include "serialization.cpp"
auto CPU::raiseException(uint code, uint coprocessor) -> void {
if(debugger.tracer.exception->enabled()) {
if(code != 0) debugger.exception(hex(code, 2L));
}
if(!scc.status.exceptionLevel) {
scc.epc = PC;
scc.status.exceptionLevel = 1;
scc.cause.exceptionCode = code;
scc.cause.coprocessorError = coprocessor;
if(scc.cause.branchDelay = branch.inDelaySlot()) scc.epc -= 4;
} else {
scc.cause.exceptionCode = code;
scc.cause.coprocessorError = coprocessor;
}
u64 vectorBase = !scc.status.vectorLocation ? i32(0x8000'0000) : i32(0xbfc0'0200);
u32 vectorOffset = (code == 2 || code == 3) ? 0x0000 : 0x0180;
PC = vectorBase + vectorOffset;
branch.exception();
context.setMode();
}
auto CPU::instruction() -> void {
if(auto interrupts = scc.cause.interruptPending & scc.status.interruptMask) {
if(scc.status.interruptEnable && !scc.status.exceptionLevel && !scc.status.errorLevel) {
if(debugger.tracer.interrupt->enabled()) {
debugger.interrupt(hex(scc.cause.interruptPending, 2L));
}
scc.cause.interruptPending = interrupts;
step(2);
return raiseException(0);
}
}
//devirtualize the program counter
auto address = readAddress(PC)(0);
if constexpr(Accuracy::CPU::Interpreter == 0) {
auto block = recompiler.block(address);
block->execute();
step(block->step);
}
if constexpr(Accuracy::CPU::Interpreter == 1) {
pipeline.address = PC;
pipeline.instruction = bus.readWord(address);
debugger.instruction();
//instructionDebug();
decoderEXECUTE();
instructionEpilogue();
step(2);
}
}
auto CPU::instructionEpilogue() -> bool {
GPR[0].u64 = 0;
if(--scc.random.index < scc.wired.index) {
scc.random.index = 31;
}
switch(branch.state) {
case Branch::Step: PC += 4; return 0;
case Branch::Take: PC += 4; branch.delaySlot(); return 0;
case Branch::DelaySlot: PC = branch.pc; branch.reset(); return 1;
case Branch::Exception: branch.reset(); return 1;
case Branch::Discard: PC += 8; branch.reset(); return 1;
}
unreachable;
}
auto CPU::instructionDebug() -> void {
pipeline.address = PC;
pipeline.instruction = readWord(pipeline.address)(0);
static vector<bool> mask;
if(!mask) mask.resize(0x0800'0000);
if(mask[(PC & 0x1fff'ffff) >> 2]) return;
mask[(PC & 0x1fff'ffff) >> 2] = 1;
static uint counter = 0;
//if(++counter > 100) return;
print(
disassembler.hint(hex(pipeline.address, 8L)), " ",
//disassembler.hint(hex(pipeline.instruction, 8L)), " ",
disassembler.disassemble(pipeline.address, pipeline.instruction), "\n"
);
}
auto CPU::powerR4300(bool reset) -> void {
for(uint n : range(32)) GPR[n].u64 = 0;
scc = {};
@@ -17,11 +109,16 @@ auto CPU::powerR4300(bool reset) -> void {
fpu = {};
LO.u64 = 0;
HI.u64 = 0;
GPR[Core::Register::SP].u64 = i32(0xa400'1ff0);
PC = i32(0xbfc00000);
GPR[Core::Register::SP].u64 = u32(0xa400'1ff0);
PC = u32(0xbfc0'0000);
branch.reset();
fesetround(FE_TONEAREST);
context.setMode();
if constexpr(Accuracy::CPU::Interpreter == 0) {
recompiler.allocator.resize(512_MiB, bump_allocator::executable | bump_allocator::zero_fill);
recompiler.reset();
}
}
auto CPU::Context::setMode() -> void {
+15 -9
View File
@@ -1,5 +1,9 @@
//{
//core.cpp
auto raiseException(uint, uint = 0) -> void;
auto instruction() -> void;
auto instructionEpilogue() -> bool;
auto instructionDebug() -> void;
auto powerR4300(bool reset) -> void;
//memory.cpp
@@ -16,15 +20,16 @@
auto writeWord (u32 address, u32 data) -> bool;
auto writeDouble (u32 address, u64 data) -> bool;
//instruction.cpp
auto raiseException(uint, uint = 0) -> void;
auto instruction() -> void;
auto instructionDEBUG() -> void;
auto instructionEXECUTE() -> void;
auto instructionSPECIAL() -> void;
auto instructionREGIMM() -> void;
auto instructionCOP0() -> void;
auto instructionCOP1() -> void;
//decoder.cpp
auto decoderEXECUTE() -> void;
auto decoderSPECIAL() -> void;
auto decoderREGIMM() -> void;
auto decoderCOP0() -> void;
auto decoderCOP1() -> void;
auto instructionCOP2() -> void;
auto instructionCOP3() -> void;
auto instructionINVALID() -> void;
enum Interrupt : uint {
Software0 = 0,
@@ -58,6 +63,7 @@
#include "cpu.hpp"
#include "scc.hpp"
#include "fpu.hpp"
#include "recompiler.hpp"
#include "disassembler.hpp"
static constexpr bool Endian = 1; //0 = little, 1 = big
+280 -234
View File
@@ -1,46 +1,102 @@
auto CPU::instructionADD() -> void {
//if(RS.u32 > ~RT.u32) return exception.arithmeticOverflow();
RD.u64 = i32(RS.u32 + RT.u32);
auto CPU::instructionADD(r64& rd, cr64& rs, cr64& rt) -> void {
//if(rs.u32 > ~rt.u32) return exception.arithmeticOverflow();
rd.u64 = i32(rs.u32 + rt.u32);
}
auto CPU::instructionADDI() -> void {
//if(RS.i32 > ~IMMi16) return exception.arithmeticOverflow();
RT.u64 = i32(RS.u32 + IMMi16);
auto CPU::instructionADDI(r64& rt, cr64& rs, i16 imm) -> void {
//if(rs.i32 > ~imm) return exception.arithmeticOverflow();
rt.u64 = i32(rs.u32 + imm);
}
auto CPU::instructionADDIU() -> void {
RT.u64 = i32(RS.u32 + IMMi16);
auto CPU::instructionADDIU(r64& rt, cr64& rs, i16 imm) -> void {
rt.u64 = i32(rs.u32 + imm);
}
auto CPU::instructionADDU() -> void {
RD.u64 = i32(RS.u32 + RT.u32);
auto CPU::instructionADDU(r64& rd, cr64& rs, cr64& rt) -> void {
rd.u64 = i32(rs.u32 + rt.u32);
}
auto CPU::instructionAND() -> void {
RD.u64 = RS.u64 & RT.u64;
auto CPU::instructionAND(r64& rd, cr64& rs, cr64& rt) -> void {
rd.u64 = rs.u64 & rt.u64;
}
auto CPU::instructionANDI() -> void {
RT.u64 = RS.u64 & IMMu16;
auto CPU::instructionANDI(r64& rt, cr64& rs, u16 imm) -> void {
rt.u64 = rs.u64 & imm;
}
auto CPU::instructionB(bool take) -> void {
if(take) branch.take(PC + 4 + (IMMi16 << 2));
auto CPU::instructionBEQ(cr64& rs, cr64& rt, i16 imm) -> void {
if(rs.u64 == rt.u64) branch.take(PC + 4 + (imm << 2));
}
auto CPU::instructionBAL(bool take) -> void {
RA.u64 = i32(PC + 8);
if(take) branch.take(PC + 4 + (IMMi16 << 2));
}
auto CPU::instructionBALL(bool take) -> void {
RA.u64 = i32(PC + 8);
if(take) branch.take(PC + 4 + (IMMi16 << 2));
auto CPU::instructionBEQL(cr64& rs, cr64& rt, i16 imm) -> void {
if(rs.u64 == rt.u64) branch.take(PC + 4 + (imm << 2));
else branch.discard();
}
auto CPU::instructionBL(bool take) -> void {
if(take) branch.take(PC + 4 + (IMMi16 << 2));
auto CPU::instructionBGEZ(cr64& rs, i16 imm) -> void {
if(rs.i64 >= 0) branch.take(PC + 4 + (imm << 2));
}
auto CPU::instructionBGEZAL(cr64& rs, i16 imm) -> void {
RA.u64 = i32(PC + 8);
if(rs.i64 >= 0) branch.take(PC + 4 + (imm << 2));
}
auto CPU::instructionBGEZALL(cr64& rs, i16 imm) -> void {
RA.u64 = i32(PC + 8);
if(rs.i64 >= 0) branch.take(PC + 4 + (imm << 2));
else branch.discard();
}
auto CPU::instructionBGEZL(cr64& rs, i16 imm) -> void {
if(rs.i64 >= 0) branch.take(PC + 4 + (imm << 2));
else branch.discard();
}
auto CPU::instructionBGTZ(cr64& rs, i16 imm) -> void {
if(rs.i64 > 0) branch.take(PC + 4 + (imm << 2));
}
auto CPU::instructionBGTZL(cr64& rs, i16 imm) -> void {
if(rs.i64 > 0) branch.take(PC + 4 + (imm << 2));
else branch.discard();
}
auto CPU::instructionBLEZ(cr64& rs, i16 imm) -> void {
if(rs.i64 <= 0) branch.take(PC + 4 + (imm << 2));
}
auto CPU::instructionBLEZL(cr64& rs, i16 imm) -> void {
if(rs.i64 <= 0) branch.take(PC + 4 + (imm << 2));
else branch.discard();
}
auto CPU::instructionBLTZ(cr64& rs, i16 imm) -> void {
if(rs.i64 < 0) branch.take(PC + 4 + (imm << 2));
}
auto CPU::instructionBLTZAL(cr64& rs, i16 imm) -> void {
RA.u64 = i32(PC + 8);
if(rs.i64 < 0) branch.take(PC + 4 + (imm << 2));
}
auto CPU::instructionBLTZALL(cr64& rs, i16 imm) -> void {
RA.u64 = i32(PC + 8);
if(rs.i64 < 0) branch.take(PC + 4 + (imm << 2));
else branch.discard();
}
auto CPU::instructionBLTZL(cr64& rs, i16 imm) -> void {
if(rs.i64 < 0) branch.take(PC + 4 + (imm << 2));
else branch.discard();
}
auto CPU::instructionBNE(cr64& rs, cr64& rt, i16 imm) -> void {
if(rs.u64 != rt.u64) branch.take(PC + 4 + (imm << 2));
}
auto CPU::instructionBNEL(cr64& rs, cr64& rt, i16 imm) -> void {
if(rs.u64 != rt.u64) branch.take(PC + 4 + (imm << 2));
else branch.discard();
}
@@ -48,10 +104,8 @@ auto CPU::instructionBREAK() -> void {
exception.breakpoint();
}
auto CPU::instructionCACHE() -> void {
auto CPU::instructionCACHE(u8 cache, u8 operation) -> void {
//todo
uint cache = OP >> 16 & 3;
uint operation = OP >> 18 & 3;
if(cache == 0) {
//instruction
if(operation == 0) {
@@ -99,440 +153,432 @@ auto CPU::instructionCACHE() -> void {
}
}
auto CPU::instructionDADD() -> void {
//if(RS.u64 > ~RT.u64) return exception.arithmeticOverflow();
RD.u64 = RS.u64 + RT.u64;
auto CPU::instructionDADD(r64& rd, cr64& rs, cr64& rt) -> void {
//if(rs.u64 > ~rt.u64) return exception.arithmeticOverflow();
rd.u64 = rs.u64 + rt.u64;
}
auto CPU::instructionDADDI() -> void {
//if(RS.i64 > ~IMM16i) return exception.arithmeticOverflow();
RT.u64 = RS.u64 + i64(IMMi16);
auto CPU::instructionDADDI(r64& rt, cr64& rs, i16 imm) -> void {
//if(rs.i64 > ~imm) return exception.arithmeticOverflow();
rt.u64 = rs.u64 + imm;
}
auto CPU::instructionDADDIU() -> void {
RT.u64 = RS.u64 + i64(IMMi16);
auto CPU::instructionDADDIU(r64& rt, cr64& rs, i16 imm) -> void {
rt.u64 = rs.u64 + imm;
}
auto CPU::instructionDADDU() -> void {
RD.u64 = RS.u64 + RT.u64;
auto CPU::instructionDADDU(r64& rd, cr64& rs, cr64& rt) -> void {
rd.u64 = rs.u64 + rt.u64;
}
auto CPU::instructionDDIV() -> void {
if(RT.i64) {
auto CPU::instructionDDIV(cr64& rs, cr64& rt) -> void {
if(rt.i64) {
//cast to i128 to prevent exception on INT64_MIN / -1
LO.u64 = i128(RS.i64) / i128(RT.i64);
HI.u64 = i128(RS.i64) % i128(RT.i64);
LO.u64 = i128(rs.i64) / i128(rt.i64);
HI.u64 = i128(rs.i64) % i128(rt.i64);
} else {
LO.u64 = RS.i64 < 0 ? +1 : -1;
HI.u64 = RS.i64;
LO.u64 = rs.i64 < 0 ? +1 : -1;
HI.u64 = rs.i64;
}
}
auto CPU::instructionDDIVU() -> void {
if(RT.u64) {
LO.u64 = RS.u64 / RT.u64;
HI.u64 = RS.u64 % RT.u64;
auto CPU::instructionDDIVU(cr64& rs, cr64& rt) -> void {
if(rt.u64) {
LO.u64 = rs.u64 / rt.u64;
HI.u64 = rs.u64 % rt.u64;
} else {
LO.u64 = -1;
HI.u64 = RS.u64;
HI.u64 = rs.u64;
}
}
auto CPU::instructionDIV() -> void {
if(RT.i32) {
auto CPU::instructionDIV(cr64& rs, cr64& rt) -> void {
if(rt.i32) {
//cast to i64 to prevent exception on INT32_MIN / -1
LO.u64 = i32(i64(RS.i32) / i64(RT.i32));
HI.u64 = i32(i64(RS.i32) % i64(RT.i32));
LO.u64 = i32(i64(rs.i32) / i64(rt.i32));
HI.u64 = i32(i64(rs.i32) % i64(rt.i32));
} else {
LO.u64 = RS.i32 < 0 ? +1 : -1;
HI.u64 = RS.i32;
LO.u64 = rs.i32 < 0 ? +1 : -1;
HI.u64 = rs.i32;
}
}
auto CPU::instructionDIVU() -> void {
if(RT.u32) {
LO.u64 = i32(RS.u32 / RT.u32);
HI.u64 = i32(RS.u32 % RT.u32);
auto CPU::instructionDIVU(cr64& rs, cr64& rt) -> void {
if(rt.u32) {
LO.u64 = i32(rs.u32 / rt.u32);
HI.u64 = i32(rs.u32 % rt.u32);
} else {
LO.u64 = -1;
HI.u64 = RS.i32;
HI.u64 = rs.i32;
}
}
auto CPU::instructionDMULT() -> void {
u128 result = RS.i128() * RT.i128();
auto CPU::instructionDMULT(cr64& rs, cr64& rt) -> void {
u128 result = rs.i128() * rt.i128();
LO.u64 = result >> 0;
HI.u64 = result >> 64;
}
auto CPU::instructionDMULTU() -> void {
u128 result = RS.u128() * RT.u128();
auto CPU::instructionDMULTU(cr64& rs, cr64& rt) -> void {
u128 result = rs.u128() * rt.u128();
LO.u64 = result >> 0;
HI.u64 = result >> 64;
}
auto CPU::instructionDSLL() -> void {
RD.u64 = RT.u64 << SA;
auto CPU::instructionDSLL(r64& rd, cr64& rt, u8 sa) -> void {
rd.u64 = rt.u64 << sa;
}
auto CPU::instructionDSLL32() -> void {
RD.u64 = RT.u64 << SA + 32;
auto CPU::instructionDSLLV(r64& rd, cr64& rt, cr64& rs) -> void {
rd.u64 = rt.u64 << (rs.u32 & 63);
}
auto CPU::instructionDSLLV() -> void {
RD.u64 = RT.u64 << (RS.u32 & 63);
auto CPU::instructionDSRA(r64& rd, cr64& rt, u8 sa) -> void {
rd.u64 = rt.i64 >> sa;
}
auto CPU::instructionDSRA() -> void {
RD.u64 = RT.i64 >> SA;
auto CPU::instructionDSRAV(r64& rd, cr64& rt, cr64& rs) -> void {
rd.u64 = rt.i64 >> (rs.u32 & 63);
}
auto CPU::instructionDSRA32() -> void {
RD.u64 = RT.i64 >> SA + 32;
auto CPU::instructionDSRL(r64& rd, cr64& rt, u8 sa) -> void {
rd.u64 = rt.u64 >> sa;
}
auto CPU::instructionDSRAV() -> void {
RD.u64 = RT.i64 >> (RS.u32 & 63);
auto CPU::instructionDSRLV(r64& rd, cr64& rt, cr64& rs) -> void {
rd.u64 = rt.u64 >> (rs.u32 & 63);
}
auto CPU::instructionDSRL() -> void {
RD.u64 = RT.u64 >> SA;
auto CPU::instructionDSUB(r64& rd, cr64& rs, cr64& rt) -> void {
//if(rs.u64 < rt.u64) return exception.arithmeticOverflow();
rd.u64 = rs.u64 - rt.u64;
}
auto CPU::instructionDSRL32() -> void {
RD.u64 = RT.u64 >> SA + 32;
auto CPU::instructionDSUBU(r64& rd, cr64& rs, cr64& rt) -> void {
rd.u64 = rs.u64 - rt.u64;
}
auto CPU::instructionDSRLV() -> void {
RD.u64 = RT.u64 >> (RS.u32 & 63);
auto CPU::instructionJ(u32 imm) -> void {
branch.take((PC + 4 & 0xf000'0000) | (imm << 2));
}
auto CPU::instructionDSUB() -> void {
//if(RS.u64 < RT.u64) return exception.arithmeticOverflow();
RD.u64 = RS.u64 - RT.u64;
}
auto CPU::instructionDSUBU() -> void {
RD.u64 = RS.u64 - RT.u64;
}
auto CPU::instructionJ() -> void {
branch.take((PC + 4 & 0xf000'0000) | (IMMu26 << 2));
}
auto CPU::instructionJAL() -> void {
branch.take((PC + 4 & 0xf000'0000) | (IMMu26 << 2));
auto CPU::instructionJAL(u32 imm) -> void {
RA.u64 = i32(PC + 8);
branch.take((PC + 4 & 0xf000'0000) | (imm << 2));
}
auto CPU::instructionJALR() -> void {
branch.take(RS.u32);
RD.u64 = i32(PC + 8);
auto CPU::instructionJALR(r64& rd, cr64& rs) -> void {
rd.u64 = i32(PC + 8);
branch.take(rs.u32);
}
auto CPU::instructionJR() -> void {
branch.take(RS.u32);
auto CPU::instructionJR(cr64& rs) -> void {
branch.take(rs.u32);
}
auto CPU::instructionLB() -> void {
if(auto data = readByte(RS.u32 + IMMi16)) RT.u64 = i8(*data);
auto CPU::instructionLB(r64& rt, cr64& rs, i16 imm) -> void {
if(auto data = readByte(rs.u32 + imm)) rt.u64 = i8(*data);
}
auto CPU::instructionLBU() -> void {
if(auto data = readByte(RS.u32 + IMMi16)) RT.u64 = u8(*data);
auto CPU::instructionLBU(r64& rt, cr64& rs, i16 imm) -> void {
if(auto data = readByte(rs.u32 + imm)) rt.u64 = u8(*data);
}
auto CPU::instructionLD() -> void {
if(auto data = readDouble(RS.u32 + IMMi16)) RT.u64 = *data;
auto CPU::instructionLD(r64& rt, cr64& rs, i16 imm) -> void {
if(auto data = readDouble(rs.u32 + imm)) rt.u64 = *data;
}
auto CPU::instructionLDL() -> void {
auto address = RS.u32 + IMMi16;
auto CPU::instructionLDL(r64& rt, cr64& rs, i16 imm) -> void {
auto address = rs.u32 + imm;
auto shift = 8 * ((address ^ FlipLE) & 7);
auto mask = u64(0) - 1 << shift;
if(auto data = readDouble(address & ~7)) {
RT.u64 = RT.u64 & ~mask | *data << shift;
rt.u64 = rt.u64 & ~mask | *data << shift;
}
}
auto CPU::instructionLDR() -> void {
auto address = RS.u32 + IMMi16;
auto CPU::instructionLDR(r64& rt, cr64& rs, i16 imm) -> void {
auto address = rs.u32 + imm;
auto shift = 8 * ((address ^ FlipBE) & 7);
auto mask = u64(0) - 1 >> shift;
if(auto data = readDouble(address & ~7)) {
RT.u64 = RT.u64 & ~mask | *data >> shift;
rt.u64 = rt.u64 & ~mask | *data >> shift;
}
}
auto CPU::instructionLH() -> void {
if(auto data = readHalf(RS.u32 + IMMi16)) RT.u64 = i16(*data);
auto CPU::instructionLH(r64& rt, cr64& rs, i16 imm) -> void {
if(auto data = readHalf(rs.u32 + imm)) rt.u64 = i16(*data);
}
auto CPU::instructionLHU() -> void {
if(auto data = readHalf(RS.u32 + IMMi16)) RT.u64 = u16(*data);
auto CPU::instructionLHU(r64& rt, cr64& rs, i16 imm) -> void {
if(auto data = readHalf(rs.u32 + imm)) rt.u64 = u16(*data);
}
auto CPU::instructionLL() -> void {
if(auto data = readWord(RS.u32 + IMMi16)) {
RT.u64 = i32(*data);
auto CPU::instructionLL(r64& rt, cr64& rs, i16 imm) -> void {
if(auto data = readWord(rs.u32 + imm)) {
rt.u64 = i32(*data);
scc.ll = tlb.physicalAddress >> 4;
scc.llbit = 1;
}
}
auto CPU::instructionLLD() -> void {
if(auto data = readDouble(RS.u32 + IMMi16)) {
RT.u64 = *data;
auto CPU::instructionLLD(r64& rt, cr64& rs, i16 imm) -> void {
if(auto data = readDouble(rs.u32 + imm)) {
rt.u64 = *data;
scc.ll = tlb.physicalAddress >> 4;
scc.llbit = 1;
}
}
auto CPU::instructionLUI() -> void {
RT.u64 = i32(IMMu16 << 16);
auto CPU::instructionLUI(r64& rt, u16 imm) -> void {
rt.u64 = i32(imm << 16);
}
auto CPU::instructionLW() -> void {
if(auto data = readWord(RS.u32 + IMMi16)) RT.u64 = i32(*data);
auto CPU::instructionLW(r64& rt, cr64& rs, i16 imm) -> void {
if(auto data = readWord(rs.u32 + imm)) rt.u64 = i32(*data);
}
auto CPU::instructionLWL() -> void {
auto address = RS.u32 + IMMi16;
auto CPU::instructionLWL(r64& rt, cr64& rs, i16 imm) -> void {
auto address = rs.u32 + imm;
auto shift = 8 * ((address ^ FlipLE) & 3);
auto mask = u32(0) - 1 << shift;
if(auto data = readWord(address & ~3)) {
RT.u64 = i32(RT.u32 & ~mask | *data << shift);
rt.u64 = i32(rt.u32 & ~mask | *data << shift);
}
}
auto CPU::instructionLWR() -> void {
auto address = RS.u32 + IMMi16;
auto CPU::instructionLWR(r64& rt, cr64& rs, i16 imm) -> void {
auto address = rs.u32 + imm;
auto shift = 8 * ((address ^ FlipBE) & 3);
auto mask = u32(0) - 1 >> shift;
if(auto data = readWord(address & ~3)) {
RT.u64 = i32(RT.u32 & ~mask | *data >> shift);
rt.u64 = i32(rt.u32 & ~mask | *data >> shift);
}
}
auto CPU::instructionLWU() -> void {
if(auto data = readWord(RS.u32 + IMMi16)) RT.u64 = u32(*data);
auto CPU::instructionLWU(r64& rt, cr64& rs, i16 imm) -> void {
if(auto data = readWord(rs.u32 + imm)) rt.u64 = u32(*data);
}
auto CPU::instructionMFHI() -> void {
RD.u64 = HI.u64;
auto CPU::instructionMFHI(r64& rd) -> void {
rd.u64 = HI.u64;
}
auto CPU::instructionMFLO() -> void {
RD.u64 = LO.u64;
auto CPU::instructionMFLO(r64& rd) -> void {
rd.u64 = LO.u64;
}
auto CPU::instructionMTHI() -> void {
HI.u64 = RS.u64;
auto CPU::instructionMTHI(cr64& rs) -> void {
HI.u64 = rs.u64;
}
auto CPU::instructionMTLO() -> void {
LO.u64 = RS.u64;
auto CPU::instructionMTLO(cr64& rs) -> void {
LO.u64 = rs.u64;
}
auto CPU::instructionMULT() -> void {
u64 result = i64(RS.i32) * i64(RT.i32);
auto CPU::instructionMULT(cr64& rs, cr64& rt) -> void {
u64 result = i64(rs.i32) * i64(rt.i32);
LO.u64 = i32(result >> 0);
HI.u64 = i32(result >> 32);
}
auto CPU::instructionMULTU() -> void {
u64 result = u64(RS.u32) * u64(RT.u32);
auto CPU::instructionMULTU(cr64& rs, cr64& rt) -> void {
u64 result = u64(rs.u32) * u64(rt.u32);
LO.u64 = i32(result >> 0);
HI.u64 = i32(result >> 32);
}
auto CPU::instructionNOR() -> void {
RD.u64 = ~(RS.u64 | RT.u64);
auto CPU::instructionNOR(r64& rd, cr64& rs, cr64& rt) -> void {
rd.u64 = ~(rs.u64 | rt.u64);
}
auto CPU::instructionOR() -> void {
RD.u64 = RS.u64 | RT.u64;
auto CPU::instructionOR(r64& rd, cr64& rs, cr64& rt) -> void {
rd.u64 = rs.u64 | rt.u64;
}
auto CPU::instructionORI() -> void {
RT.u64 = RS.u64 | IMMu16;
auto CPU::instructionORI(r64& rt, cr64& rs, u16 imm) -> void {
rt.u64 = rs.u64 | imm;
}
auto CPU::instructionSB() -> void {
writeByte(RS.u32 + IMMi16, RT.u32);
auto CPU::instructionSB(cr64& rt, cr64& rs, i16 imm) -> void {
writeByte(rs.u32 + imm, rt.u32);
}
auto CPU::instructionSC() -> void {
auto CPU::instructionSC(r64& rt, cr64& rs, i16 imm) -> void {
if(scc.llbit) {
scc.llbit = 0;
RT.u64 = writeWord(RS.u32 + IMMi16, RT.u32);
rt.u64 = writeWord(rs.u32 + imm, rt.u32);
} else {
RT.u64 = 0;
rt.u64 = 0;
}
}
auto CPU::instructionSCD() -> void {
auto CPU::instructionSCD(r64& rt, cr64& rs, i16 imm) -> void {
if(scc.llbit) {
scc.llbit = 0;
RT.u64 = writeDouble(RS.u32 + IMMi16, RT.u64);
rt.u64 = writeDouble(rs.u32 + imm, rt.u64);
} else {
RT.u64 = 0;
rt.u64 = 0;
}
}
auto CPU::instructionSD() -> void {
writeDouble(RS.u32 + IMMi16, RT.u64);
auto CPU::instructionSD(cr64& rt, cr64& rs, i16 imm) -> void {
writeDouble(rs.u32 + imm, rt.u64);
}
auto CPU::instructionSDL() -> void {
auto address = RS.u32 + IMMi16;
auto CPU::instructionSDL(cr64& rt, cr64& rs, i16 imm) -> void {
auto address = rs.u32 + imm;
auto shift = 8 * ((address ^ FlipLE) & 7);
auto mask = u64(0) - 1 >> shift;
if(auto data = readDouble(address & ~7)) {
writeDouble(address & ~7, *data & ~mask | RT.u64 >> shift);
writeDouble(address & ~7, *data & ~mask | rt.u64 >> shift);
}
}
auto CPU::instructionSDR() -> void {
auto address = RS.u32 + IMMi16;
auto CPU::instructionSDR(cr64& rt, cr64& rs, i16 imm) -> void {
auto address = rs.u32 + imm;
auto shift = 8 * ((address ^ FlipBE) & 7);
auto mask = u64(0) - 1 << shift;
if(auto data = readDouble(address & ~7)) {
writeDouble(address & ~7, *data & ~mask | RT.u64 << shift);
writeDouble(address & ~7, *data & ~mask | rt.u64 << shift);
}
}
auto CPU::instructionSH() -> void {
writeHalf(RS.u32 + IMMi16, RT.u32);
auto CPU::instructionSH(cr64& rt, cr64& rs, i16 imm) -> void {
writeHalf(rs.u32 + imm, rt.u32);
}
auto CPU::instructionSLL() -> void {
RD.u64 = i32(RT.u32 << SA);
auto CPU::instructionSLL(r64& rd, cr64& rt, u8 sa) -> void {
rd.u64 = i32(rt.u32 << sa);
}
auto CPU::instructionSLLV() -> void {
RD.u64 = i32(RT.u32 << (RS.u32 & 31));
auto CPU::instructionSLLV(r64& rd, cr64& rt, cr64& rs) -> void {
rd.u64 = i32(rt.u32 << (rs.u32 & 31));
}
auto CPU::instructionSLT() -> void {
RD.u64 = RS.i64 < RT.i64;
auto CPU::instructionSLT(r64& rd, cr64& rs, cr64& rt) -> void {
rd.u64 = rs.i64 < rt.i64;
}
auto CPU::instructionSLTI() -> void {
RT.u64 = RS.i64 < i64(IMMi16);
auto CPU::instructionSLTI(r64& rt, cr64& rs, i16 imm) -> void {
rt.u64 = rs.i64 < imm;
}
auto CPU::instructionSLTIU() -> void {
RT.u64 = RS.u64 < u64(IMMi16);
auto CPU::instructionSLTIU(r64& rt, cr64& rs, i16 imm) -> void {
rt.u64 = rs.u64 < imm;
}
auto CPU::instructionSLTU() -> void {
RD.u64 = RS.u64 < RT.u64;
auto CPU::instructionSLTU(r64& rd, cr64& rs, cr64& rt) -> void {
rd.u64 = rs.u64 < rt.u64;
}
auto CPU::instructionSRA() -> void {
RD.u64 = RT.i32 >> SA;
auto CPU::instructionSRA(r64& rd, cr64& rt, u8 sa) -> void {
rd.u64 = rt.i32 >> sa;
}
auto CPU::instructionSRAV() -> void {
RD.u64 = RT.i32 >> (RS.u32 & 31);
auto CPU::instructionSRAV(r64& rd, cr64& rt, cr64& rs) -> void {
rd.u64 = rt.i32 >> (rs.u32 & 31);
}
auto CPU::instructionSRL() -> void {
RD.u64 = i32(RT.u32 >> SA);
auto CPU::instructionSRL(r64& rd, cr64& rt, u8 sa) -> void {
rd.u64 = i32(rt.u32 >> sa);
}
auto CPU::instructionSRLV() -> void {
RD.u64 = i32(RT.u32 >> (RS.u32 & 31));
auto CPU::instructionSRLV(r64& rd, cr64& rt, cr64& rs) -> void {
rd.u64 = i32(rt.u32 >> (rs.u32 & 31));
}
auto CPU::instructionSUB() -> void {
//if(RS.u32 < RT.u32) return exception.arithmeticOverflow();
RD.u64 = i32(RS.u32 - RT.u32);
auto CPU::instructionSUB(r64& rd, cr64& rs, cr64& rt) -> void {
//if(rs.u32 < rt.u32) return exception.arithmeticOverflow();
rd.u64 = i32(rs.u32 - rt.u32);
}
auto CPU::instructionSUBU() -> void {
RD.u64 = i32(RS.u32 - RT.u32);
auto CPU::instructionSUBU(r64& rd, cr64& rs, cr64& rt) -> void {
rd.u64 = i32(rs.u32 - rt.u32);
}
auto CPU::instructionSW() -> void {
writeWord(RS.u32 + IMMi16, RT.u32);
auto CPU::instructionSW(cr64& rt, cr64& rs, i16 imm) -> void {
writeWord(rs.u32 + imm, rt.u32);
}
auto CPU::instructionSWL() -> void {
auto address = RS.u32 + IMMi16;
auto CPU::instructionSWL(cr64& rt, cr64& rs, i16 imm) -> void {
auto address = rs.u32 + imm;
auto shift = 8 * ((address ^ FlipLE) & 3);
auto mask = u32(0) - 1 >> shift;
if(auto data = readWord(address & ~3)) {
writeWord(address & ~3, *data & ~mask | RT.u32 >> shift);
writeWord(address & ~3, *data & ~mask | rt.u32 >> shift);
}
}
auto CPU::instructionSWR() -> void {
auto address = RS.u32 + IMMi16;
auto CPU::instructionSWR(cr64& rt, cr64& rs, i16 imm) -> void {
auto address = rs.u32 + imm;
auto shift = 8 * ((address ^ FlipBE) & 3);
auto mask = u32(0) - 1 << shift;
if(auto data = readWord(address & ~3)) {
writeWord(address & ~3, *data & ~mask | RT.u32 << shift);
writeWord(address & ~3, *data & ~mask | rt.u32 << shift);
}
}
auto CPU::instructionSYNC() -> void {
//no operation; for compatibility with R4000-series code
}
auto CPU::instructionSYSCALL() -> void {
exception.systemCall();
}
auto CPU::instructionTEQ() -> void {
if(RS.u64 == RT.u64) exception.trap();
auto CPU::instructionTEQ(cr64& rs, cr64& rt) -> void {
if(rs.u64 == rt.u64) exception.trap();
}
auto CPU::instructionTEQI() -> void {
if(RS.u64 == u64(IMMi16)) exception.trap();
auto CPU::instructionTEQI(cr64& rs, i16 imm) -> void {
if(rs.i64 == imm) exception.trap();
}
auto CPU::instructionTGE() -> void {
if(RS.i64 >= RT.i64) exception.trap();
auto CPU::instructionTGE(cr64& rs, cr64& rt) -> void {
if(rs.i64 >= rt.i64) exception.trap();
}
auto CPU::instructionTGEI() -> void {
if(RS.i64 >= i64(IMMi16)) exception.trap();
auto CPU::instructionTGEI(cr64& rs, i16 imm) -> void {
if(rs.i64 >= imm) exception.trap();
}
auto CPU::instructionTGEIU() -> void {
if(RS.u64 >= u64(IMMi16)) exception.trap();
auto CPU::instructionTGEIU(cr64& rs, i16 imm) -> void {
if(rs.u64 >= imm) exception.trap();
}
auto CPU::instructionTGEU() -> void {
if(RS.u64 >= RT.u64) exception.trap();
auto CPU::instructionTGEU(cr64& rs, cr64& rt) -> void {
if(rs.u64 >= rt.u64) exception.trap();
}
auto CPU::instructionTLT() -> void {
if(RS.i64 < RT.i64) exception.trap();
auto CPU::instructionTLT(cr64& rs, cr64& rt) -> void {
if(rs.i64 < rt.i64) exception.trap();
}
auto CPU::instructionTLTI() -> void {
if(RS.i64 < i64(IMMi16)) exception.trap();
auto CPU::instructionTLTI(cr64& rs, i16 imm) -> void {
if(rs.i64 < imm) exception.trap();
}
auto CPU::instructionTLTIU() -> void {
if(RS.u64 < u64(IMMi16)) exception.trap();
auto CPU::instructionTLTIU(cr64& rs, i16 imm) -> void {
if(rs.u64 < imm) exception.trap();
}
auto CPU::instructionTLTU() -> void {
if(RS.u64 < RT.u64) exception.trap();
auto CPU::instructionTLTU(cr64& rs, cr64& rt) -> void {
if(rs.u64 < rt.u64) exception.trap();
}
auto CPU::instructionTNE() -> void {
if(RS.u64 != RT.u64) exception.trap();
auto CPU::instructionTNE(cr64& rs, cr64& rt) -> void {
if(rs.u64 != rt.u64) exception.trap();
}
auto CPU::instructionTNEI() -> void {
if(RS.u64 != u64(IMMi16)) exception.trap();
auto CPU::instructionTNEI(cr64& rs, i16 imm) -> void {
if(rs.i64 != imm) exception.trap();
}
auto CPU::instructionXOR() -> void {
RD.u64 = RS.u64 ^ RT.u64;
auto CPU::instructionXOR(r64& rd, cr64& rs, cr64& rt) -> void {
rd.u64 = rs.u64 ^ rt.u64;
}
auto CPU::instructionXORI() -> void {
RT.u64 = RS.u64 ^ IMMu16;
auto CPU::instructionXORI(r64& rt, cr64& rs, u16 imm) -> void {
rt.u64 = rs.u64 ^ imm;
}
+115 -100
View File
@@ -1,12 +1,15 @@
//{
union cpu64 {
union r64 {
struct { int32_t order_msb2(i32h, i32); };
struct { uint32_t order_msb2(u32h, u32); };
struct { float32_t order_msb2(f32h, f32); };
struct { int64_t i64; };
struct { uint64_t u64; };
struct { float64_t f64; };
auto i128() const -> int128_t { return (int128_t)i64; }
auto u128() const -> uint128_t { return (uint128_t)u64; }
};
using cr64 = const r64;
struct Core {
enum Register : uint {
@@ -24,10 +27,10 @@
RA, //return address
};
cpu64 r[32];
cpu64 lo;
cpu64 hi;
u64 pc; //program counter
r64 r[32];
r64 lo;
r64 hi;
u64 pc; //program counter
} core;
struct Branch {
@@ -45,101 +48,113 @@
} branch;
//cpu-instructions.cpp
auto instructionADD() -> void;
auto instructionADDI() -> void;
auto instructionADDIU() -> void;
auto instructionADDU() -> void;
auto instructionAND() -> void;
auto instructionANDI() -> void;
auto instructionB(bool) -> void;
auto instructionBAL(bool) -> void;
auto instructionBALL(bool) -> void;
auto instructionBL(bool) -> void;
auto instructionADD(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionADDI(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionADDIU(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionADDU(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionAND(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionANDI(r64& rt, cr64& rs, u16 imm) -> void;
auto instructionBEQ(cr64& rs, cr64& rt, i16 imm) -> void;
auto instructionBEQL(cr64& rs, cr64& rt, i16 imm) -> void;
auto instructionBGEZ(cr64& rs, i16 imm) -> void;
auto instructionBGEZAL(cr64& rs, i16 imm) -> void;
auto instructionBGEZALL(cr64& rs, i16 imm) -> void;
auto instructionBGEZL(cr64& rs, i16 imm) -> void;
auto instructionBGTZ(cr64& rs, i16 imm) -> void;
auto instructionBGTZL(cr64& rs, i16 imm) -> void;
auto instructionBLEZ(cr64& rs, i16 imm) -> void;
auto instructionBLEZL(cr64& rs, i16 imm) -> void;
auto instructionBLTZ(cr64& rs, i16 imm) -> void;
auto instructionBLTZAL(cr64& rs, i16 imm) -> void;
auto instructionBLTZALL(cr64& rs, i16 imm) -> void;
auto instructionBLTZL(cr64& rs, i16 imm) -> void;
auto instructionBNE(cr64& rs, cr64& rt, i16 imm) -> void;
auto instructionBNEL(cr64& rs, cr64& rt, i16 imm) -> void;
auto instructionBAL(bool take, i16 imm) -> void;
auto instructionBALL(bool take, i16 imm) -> void;
auto instructionBREAK() -> void;
auto instructionCACHE() -> void;
auto instructionDADD() -> void;
auto instructionDADDI() -> void;
auto instructionDADDIU() -> void;
auto instructionDADDU() -> void;
auto instructionDDIV() -> void;
auto instructionDDIVU() -> void;
auto instructionDIV() -> void;
auto instructionDIVU() -> void;
auto instructionDMULT() -> void;
auto instructionDMULTU() -> void;
auto instructionDSLL() -> void;
auto instructionDSLL32() -> void;
auto instructionDSLLV() -> void;
auto instructionDSRA() -> void;
auto instructionDSRA32() -> void;
auto instructionDSRAV() -> void;
auto instructionDSRL() -> void;
auto instructionDSRL32() -> void;
auto instructionDSRLV() -> void;
auto instructionDSUB() -> void;
auto instructionDSUBU() -> void;
auto instructionJ() -> void;
auto instructionJAL() -> void;
auto instructionJALR() -> void;
auto instructionJR() -> void;
auto instructionLB() -> void;
auto instructionLBU() -> void;
auto instructionLD() -> void;
auto instructionLDL() -> void;
auto instructionLDR() -> void;
auto instructionLH() -> void;
auto instructionLHU() -> void;
auto instructionLUI() -> void;
auto instructionLL() -> void;
auto instructionLLD() -> void;
auto instructionLW() -> void;
auto instructionLWL() -> void;
auto instructionLWR() -> void;
auto instructionLWU() -> void;
auto instructionMFHI() -> void;
auto instructionMFLO() -> void;
auto instructionMTHI() -> void;
auto instructionMTLO() -> void;
auto instructionMULT() -> void;
auto instructionMULTU() -> void;
auto instructionNOR() -> void;
auto instructionOR() -> void;
auto instructionORI() -> void;
auto instructionSB() -> void;
auto instructionSC() -> void;
auto instructionSD() -> void;
auto instructionSCD() -> void;
auto instructionSDL() -> void;
auto instructionSDR() -> void;
auto instructionSH() -> void;
auto instructionSLL() -> void;
auto instructionSLLV() -> void;
auto instructionSLT() -> void;
auto instructionSLTI() -> void;
auto instructionSLTIU() -> void;
auto instructionSLTU() -> void;
auto instructionSRA() -> void;
auto instructionSRAV() -> void;
auto instructionSRL() -> void;
auto instructionSRLV() -> void;
auto instructionSUB() -> void;
auto instructionSUBU() -> void;
auto instructionSW() -> void;
auto instructionSWL() -> void;
auto instructionSWR() -> void;
auto instructionCACHE(u8 cache, u8 operation) -> void;
auto instructionDADD(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionDADDI(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionDADDIU(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionDADDU(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionDDIV(cr64& rs, cr64& rt) -> void;
auto instructionDDIVU(cr64& rs, cr64& rt) -> void;
auto instructionDIV(cr64& rs, cr64& rt) -> void;
auto instructionDIVU(cr64& rs, cr64& rt) -> void;
auto instructionDMULT(cr64& rs, cr64& rt) -> void;
auto instructionDMULTU(cr64& rs, cr64& rt) -> void;
auto instructionDSLL(r64& rd, cr64& rt, u8 sa) -> void;
auto instructionDSLLV(r64& rd, cr64& rt, cr64& rs) -> void;
auto instructionDSRA(r64& rd, cr64& rt, u8 sa) -> void;
auto instructionDSRAV(r64& rd, cr64& rt, cr64& rs) -> void;
auto instructionDSRL(r64& rd, cr64& rt, u8 sa) -> void;
auto instructionDSRLV(r64& rd, cr64& rt, cr64& rs) -> void;
auto instructionDSUB(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionDSUBU(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionJ(u32 imm) -> void;
auto instructionJAL(u32 imm) -> void;
auto instructionJALR(r64& rd, cr64& rs) -> void;
auto instructionJR(cr64& rs) -> void;
auto instructionLB(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLBU(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLD(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLDL(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLDR(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLH(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLHU(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLUI(r64& rt, u16 imm) -> void;
auto instructionLL(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLLD(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLW(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLWL(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLWR(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionLWU(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionMFHI(r64& rd) -> void;
auto instructionMFLO(r64& rd) -> void;
auto instructionMTHI(cr64& rs) -> void;
auto instructionMTLO(cr64& rs) -> void;
auto instructionMULT(cr64& rs, cr64& rt) -> void;
auto instructionMULTU(cr64& rs, cr64& rt) -> void;
auto instructionNOR(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionOR(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionORI(r64& rt, cr64& rs, u16 imm) -> void;
auto instructionSB(cr64& rt, cr64& rs, i16 imm) -> void;
auto instructionSC(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionSD(cr64& rt, cr64& rs, i16 imm) -> void;
auto instructionSCD(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionSDL(cr64& rt, cr64& rs, i16 imm) -> void;
auto instructionSDR(cr64& rt, cr64& rs, i16 imm) -> void;
auto instructionSH(cr64& rt, cr64& rs, i16 imm) -> void;
auto instructionSLL(r64& rd, cr64& rt, u8 sa) -> void;
auto instructionSLLV(r64& rd, cr64& rt, cr64& rs) -> void;
auto instructionSLT(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionSLTI(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionSLTIU(r64& rt, cr64& rs, i16 imm) -> void;
auto instructionSLTU(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionSRA(r64& rd, cr64& rt, u8 sa) -> void;
auto instructionSRAV(r64& rd, cr64& rt, cr64& rs) -> void;
auto instructionSRL(r64& rd, cr64& rt, u8 sa) -> void;
auto instructionSRLV(r64& rd, cr64& rt, cr64& rs) -> void;
auto instructionSUB(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionSUBU(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionSW(cr64& rt, cr64& rs, i16 imm) -> void;
auto instructionSWL(cr64& rt, cr64& rs, i16 imm) -> void;
auto instructionSWR(cr64& rt, cr64& rs, i16 imm) -> void;
auto instructionSYNC() -> void;
auto instructionSYSCALL() -> void;
auto instructionTEQ() -> void;
auto instructionTEQI() -> void;
auto instructionTGE() -> void;
auto instructionTGEI() -> void;
auto instructionTGEIU() -> void;
auto instructionTGEU() -> void;
auto instructionTLT() -> void;
auto instructionTLTI() -> void;
auto instructionTLTIU() -> void;
auto instructionTLTU() -> void;
auto instructionTNE() -> void;
auto instructionTNEI() -> void;
auto instructionXOR() -> void;
auto instructionXORI() -> void;
auto instructionTEQ(cr64& rs, cr64& rt) -> void;
auto instructionTEQI(cr64& rs, i16 imm) -> void;
auto instructionTGE(cr64& rs, cr64& rt) -> void;
auto instructionTGEI(cr64& rs, i16 imm) -> void;
auto instructionTGEIU(cr64& rs, i16 imm) -> void;
auto instructionTGEU(cr64& rs, cr64& rt) -> void;
auto instructionTLT(cr64& rs, cr64& rt) -> void;
auto instructionTLTI(cr64& rs, i16 imm) -> void;
auto instructionTLTIU(cr64& rs, i16 imm) -> void;
auto instructionTLTU(cr64& rs, cr64& rt) -> void;
auto instructionTNE(cr64& rs, cr64& rt) -> void;
auto instructionTNEI(cr64& rs, i16 imm) -> void;
auto instructionXOR(r64& rd, cr64& rs, cr64& rt) -> void;
auto instructionXORI(r64& rt, cr64& rs, u16 imm) -> void;
//};
+66
View File
@@ -0,0 +1,66 @@
#define OP pipeline.instruction
#define RD GPR[RDn]
#define RT GPR[RTn]
#define RS GPR[RSn]
#define jp(id, name, ...) case id: return decoder##name(__VA_ARGS__)
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__)
#define br(id, name, ...) case id: return instruction##name(__VA_ARGS__)
auto CPU::decoderEXECUTE() -> void {
#define DECODER_EXECUTE
#include "decoder.hpp"
}
auto CPU::decoderSPECIAL() -> void {
#define DECODER_SPECIAL
#include "decoder.hpp"
}
auto CPU::decoderREGIMM() -> void {
#define DECODER_REGIMM
#include "decoder.hpp"
}
auto CPU::decoderCOP0() -> void {
if(!scc.status.enable.coprocessor0) {
if(context.mode != Context::Mode::Kernel) return exception.coprocessor0();
}
#define DECODER_COP0
#include "decoder.hpp"
//undefined instructions do not throw a reserved instruction exception
}
auto CPU::decoderCOP1() -> void {
if(!scc.status.enable.coprocessor1) {
return exception.coprocessor1();
}
#define DECODER_COP1
#include "decoder.hpp"
//undefined instructions do not throw a reserved instruction exception
}
auto CPU::instructionCOP2() -> void {
exception.coprocessor2();
}
auto CPU::instructionCOP3() -> void {
exception.coprocessor3();
}
auto CPU::instructionINVALID() -> void {
exception.reservedInstruction();
}
#undef jp
#undef op
#undef br
#undef OP
#undef RD
#undef RT
#undef RS
+353
View File
@@ -0,0 +1,353 @@
//shares instruction decoding between interpreter and dynamic recompiler
#define SA (OP >> 6 & 31)
#define RDn (OP >> 11 & 31)
#define RTn (OP >> 16 & 31)
#define RSn (OP >> 21 & 31)
#define FD (OP >> 6 & 31)
#define FS (OP >> 11 & 31)
#define FT (OP >> 16 & 31)
#define IMMi16 i16(OP)
#define IMMu16 u16(OP)
#define IMMu26 (OP & 0x03ff'ffff)
#ifdef DECODER_EXECUTE
{
switch(OP >> 26) {
jp(0x00, SPECIAL);
jp(0x01, REGIMM);
br(0x02, J, IMMu26);
br(0x03, JAL, IMMu26);
br(0x04, BEQ, RS, RT, IMMi16);
br(0x05, BNE, RS, RT, IMMi16);
br(0x06, BLEZ, RS, IMMi16);
br(0x07, BGTZ, RS, IMMi16);
op(0x08, ADDI, RT, RS, IMMi16);
op(0x09, ADDIU, RT, RS, IMMi16);
op(0x0a, SLTI, RT, RS, IMMi16);
op(0x0b, SLTIU, RT, RS, IMMi16);
op(0x0c, ANDI, RT, RS, IMMu16);
op(0x0d, ORI, RT, RS, IMMu16);
op(0x0e, XORI, RT, RS, IMMu16);
op(0x0f, LUI, RT, IMMu16);
jp(0x10, COP0);
jp(0x11, COP1);
op(0x12, COP2);
op(0x13, COP3);
br(0x14, BEQL, RS, RT, IMMi16);
br(0x15, BNEL, RS, RT, IMMi16);
br(0x16, BLEZL, RS, IMMi16);
br(0x17, BGTZL, RS, IMMi16);
op(0x18, DADDI, RT, RS, IMMi16);
op(0x19, DADDIU, RT, RS, IMMi16);
op(0x1a, LDL, RT, RS, IMMi16);
op(0x1b, LDR, RT, RS, IMMi16);
op(0x1c, INVALID);
op(0x1d, INVALID);
op(0x1e, INVALID);
op(0x1f, INVALID);
op(0x20, LB, RT, RS, IMMi16);
op(0x21, LH, RT, RS, IMMi16);
op(0x22, LWL, RT, RS, IMMi16);
op(0x23, LW, RT, RS, IMMi16);
op(0x24, LBU, RT, RS, IMMi16);
op(0x25, LHU, RT, RS, IMMi16);
op(0x26, LWR, RT, RS, IMMi16);
op(0x27, LWU, RT, RS, IMMi16);
op(0x28, SB, RT, RS, IMMi16);
op(0x29, SH, RT, RS, IMMi16);
op(0x2a, SWL, RT, RS, IMMi16);
op(0x2b, SW, RT, RS, IMMi16);
op(0x2c, SDL, RT, RS, IMMi16);
op(0x2d, SDR, RT, RS, IMMi16);
op(0x2e, SWR, RT, RS, IMMi16);
op(0x2f, CACHE, OP >> 16 & 3, OP >> 18 & 3);
op(0x30, LL, RT, RS, IMMi16);
op(0x31, LWC1, FT, RS, IMMi16);
op(0x32, COP2); //LWC2
op(0x33, COP3); //LWC3
op(0x34, LLD, RT, RS, IMMi16);
op(0x35, LDC1, FT, RS, IMMi16);
op(0x36, COP2); //LDC2
op(0x37, LD, RT, RS, IMMi16);
op(0x38, SC, RT, RS, IMMi16);
op(0x39, SWC1, FT, RS, IMMi16);
op(0x3a, COP2); //SWC2
op(0x3b, COP3); //SWC3
op(0x3c, SCD, RT, RS, IMMi16);
op(0x3d, SDC1, FT, RS, IMMi16);
op(0x3e, COP2); //SDC2
op(0x3f, SD, RT, RS, IMMi16);
}
}
#undef DECODER_EXECUTE
#endif
#ifdef DECODER_SPECIAL
{
switch(OP & 0x3f) {
op(0x00, SLL, RD, RT, SA);
op(0x01, INVALID);
op(0x02, SRL, RD, RT, SA);
op(0x03, SRA, RD, RT, SA);
op(0x04, SLLV, RD, RT, RS);
op(0x05, INVALID);
op(0x06, SRLV, RD, RT, RS);
op(0x07, SRAV, RD, RT, RS);
br(0x08, JR, RS);
br(0x09, JALR, RD, RS);
op(0x0a, INVALID);
op(0x0b, INVALID);
br(0x0c, SYSCALL);
br(0x0d, BREAK);
op(0x0e, INVALID);
op(0x0f, SYNC);
op(0x10, MFHI, RD);
op(0x11, MTHI, RS);
op(0x12, MFLO, RD);
op(0x13, MTLO, RS);
op(0x14, DSLLV, RD, RT, RS);
op(0x15, INVALID);
op(0x16, DSRLV, RD, RT, RS);
op(0x17, DSRAV, RD, RT, RS);
op(0x18, MULT, RS, RT);
op(0x19, MULTU, RS, RT);
op(0x1a, DIV, RS, RT);
op(0x1b, DIVU, RS, RT);
op(0x1c, DMULT, RS, RT);
op(0x1d, DMULTU, RS, RT);
op(0x1e, DDIV, RS, RT);
op(0x1f, DDIVU, RS, RT);
op(0x20, ADD, RD, RS, RT);
op(0x21, ADDU, RD, RS, RT);
op(0x22, SUB, RD, RS, RT);
op(0x23, SUBU, RD, RS, RT);
op(0x24, AND, RD, RS, RT);
op(0x25, OR, RD, RS, RT);
op(0x26, XOR, RD, RS, RT);
op(0x27, NOR, RD, RS, RT);
op(0x28, INVALID);
op(0x29, INVALID);
op(0x2a, SLT, RD, RS, RT);
op(0x2b, SLTU, RD, RS, RT);
op(0x2c, DADD, RD, RS, RT);
op(0x2d, DADDU, RD, RS, RT);
op(0x2e, DSUB, RD, RS, RT);
op(0x2f, DSUBU, RD, RS, RT);
op(0x30, TGE, RS, RT);
op(0x31, TGEU, RS, RT);
op(0x32, TLT, RS, RT);
op(0x33, TLTU, RS, RT);
op(0x34, TEQ, RS, RT);
op(0x35, INVALID);
op(0x36, TNE, RS, RT);
op(0x37, INVALID);
op(0x38, DSLL, RD, RT, SA);
op(0x39, INVALID);
op(0x3a, DSRL, RD, RT, SA);
op(0x3b, DSRA, RD, RT, SA);
op(0x3c, DSLL, RD, RT, SA + 32);
op(0x3d, INVALID);
op(0x3e, DSRL, RD, RT, SA + 32);
op(0x3f, DSRA, RD, RT, SA + 32);
}
}
#undef DECODER_SPECIAL
#endif
#ifdef DECODER_REGIMM
{
switch(OP >> 16 & 0x1f) {
br(0x00, BLTZ, RS, IMMi16);
br(0x01, BGEZ, RS, IMMi16);
br(0x02, BLTZL, RS, IMMi16);
br(0x03, BGEZL, RS, IMMi16);
op(0x04, INVALID);
op(0x05, INVALID);
op(0x06, INVALID);
op(0x07, INVALID);
op(0x08, TGEI, RS, IMMi16);
op(0x09, TGEIU, RS, IMMi16);
op(0x0a, TLTI, RS, IMMi16);
op(0x0b, TLTIU, RS, IMMi16);
op(0x0c, TEQI, RS, IMMi16);
op(0x0d, INVALID);
op(0x0e, TNEI, RS, IMMi16);
op(0x0f, INVALID);
br(0x10, BLTZAL, RS, IMMi16);
br(0x11, BGEZAL, RS, IMMi16);
br(0x12, BLTZALL, RS, IMMi16);
br(0x13, BGEZALL, RS, IMMi16);
op(0x14, INVALID);
op(0x15, INVALID);
op(0x16, INVALID);
op(0x17, INVALID);
op(0x18, INVALID);
op(0x19, INVALID);
op(0x1a, INVALID);
op(0x1b, INVALID);
op(0x1c, INVALID);
op(0x1d, INVALID);
op(0x1e, INVALID);
op(0x1f, INVALID);
}
}
#undef DECODER_REGIMM
#endif
#ifdef DECODER_COP0
{
switch(OP >> 21 & 0x1f) {
op(0x00, MFC0, RT, RDn);
op(0x01, DMFC0, RT, RDn);
op(0x02, INVALID); //CFC0
op(0x03, INVALID);
op(0x04, MTC0, RT, RDn);
op(0x05, DMTC0, RT, RDn);
op(0x06, INVALID); //CTC0
op(0x07, INVALID);
op(0x08, INVALID); //BC0
op(0x09, INVALID);
op(0x0a, INVALID);
op(0x0b, INVALID);
op(0x0c, INVALID);
op(0x0d, INVALID);
op(0x0e, INVALID);
op(0x0f, INVALID);
}
switch(OP & 0x3f) {
op(0x01, TLBR);
op(0x02, TLBWI);
op(0x06, TLBWR);
op(0x08, TLBP);
br(0x18, ERET);
}
}
#undef DECODER_COP0
#endif
#ifdef DECODER_COP1
{
switch(OP >> 21 & 0x1f) {
op(0x00, MFC1, RT, FS);
op(0x01, DMFC1, RT, FS);
op(0x02, CFC1, RT, RDn);
op(0x03, INVALID);
op(0x04, MTC1, RT, FS);
op(0x05, DMTC1, RT, FS);
op(0x06, CTC1, RT, RDn);
op(0x07, INVALID);
br(0x08, BC1, OP >> 16 & 1, OP >> 17 & 1, IMMi16);
op(0x09, INVALID);
op(0x0a, INVALID);
op(0x0b, INVALID);
op(0x0c, INVALID);
op(0x0d, INVALID);
op(0x0e, INVALID);
op(0x0f, INVALID);
}
if((OP >> 21 & 31) == 16)
switch(OP & 0x3f) {
op(0x00, FADD_S, FD, FS, FT);
op(0x01, FSUB_S, FD, FS, FT);
op(0x02, FMUL_S, FD, FS, FT);
op(0x03, FDIV_S, FD, FS, FT);
op(0x04, FSQRT_S, FD, FS);
op(0x05, FABS_S, FD, FS);
op(0x06, FMOV_S, FD, FS);
op(0x07, FNEG_S, FD, FS);
op(0x08, FROUND_L_S, FD, FS);
op(0x09, FTRUNC_L_S, FD, FS);
op(0x0a, FCEIL_L_S, FD, FS);
op(0x0b, FFLOOR_L_S, FD, FS);
op(0x0c, FROUND_W_S, FD, FS);
op(0x0d, FTRUNC_W_S, FD, FS);
op(0x0e, FCEIL_W_S, FD, FS);
op(0x0f, FFLOOR_W_S, FD, FS);
op(0x21, FCVT_D_S, FD, FS);
op(0x24, FCVT_W_S, FD, FS);
op(0x25, FCVT_L_S, FD, FS);
op(0x30, FC_F_S, FS, FT);
op(0x31, FC_UN_S, FS, FT);
op(0x32, FC_EQ_S, FS, FT);
op(0x33, FC_UEQ_S, FS, FT);
op(0x34, FC_OLT_S, FS, FT);
op(0x35, FC_ULT_S, FS, FT);
op(0x36, FC_OLE_S, FS, FT);
op(0x37, FC_ULE_S, FS, FT);
op(0x38, FC_SF_S, FS, FT);
op(0x39, FC_NGLE_S, FS, FT);
op(0x3a, FC_SEQ_S, FS, FT);
op(0x3b, FC_NGL_S, FS, FT);
op(0x3c, FC_LT_S, FS, FT);
op(0x3d, FC_NGE_S, FS, FT);
op(0x3e, FC_LE_S, FS, FT);
op(0x3f, FC_NGT_S, FS, FT);
}
if((OP >> 21 & 31) == 17)
switch(OP & 0x3f) {
op(0x00, FADD_D, FD, FS, FT);
op(0x01, FSUB_D, FD, FS, FT);
op(0x02, FMUL_D, FD, FS, FT);
op(0x03, FDIV_D, FD, FS, FT);
op(0x04, FSQRT_D, FD, FS);
op(0x05, FABS_D, FD, FS);
op(0x06, FMOV_D, FD, FS);
op(0x07, FNEG_D, FD, FS);
op(0x08, FROUND_L_D, FD, FS);
op(0x09, FTRUNC_L_D, FD, FS);
op(0x0a, FCEIL_L_D, FD, FS);
op(0x0b, FFLOOR_L_D, FD, FS);
op(0x0c, FROUND_W_D, FD, FS);
op(0x0d, FTRUNC_W_D, FD, FS);
op(0x0e, FCEIL_W_D, FD, FS);
op(0x0f, FFLOOR_W_D, FD, FS);
op(0x20, FCVT_S_D, FD, FS);
op(0x24, FCVT_W_D, FD, FS);
op(0x25, FCVT_L_D, FD, FS);
op(0x30, FC_F_D, FS, FT);
op(0x31, FC_UN_D, FS, FT);
op(0x32, FC_EQ_D, FS, FT);
op(0x33, FC_UEQ_D, FS, FT);
op(0x34, FC_OLT_D, FS, FT);
op(0x35, FC_ULT_D, FS, FT);
op(0x36, FC_OLE_D, FS, FT);
op(0x37, FC_ULE_D, FS, FT);
op(0x38, FC_SF_D, FS, FT);
op(0x39, FC_NGLE_D, FS, FT);
op(0x3a, FC_SEQ_D, FS, FT);
op(0x3b, FC_NGL_D, FS, FT);
op(0x3c, FC_LT_D, FS, FT);
op(0x3d, FC_NGE_D, FS, FT);
op(0x3e, FC_LE_D, FS, FT);
op(0x3f, FC_NGT_D, FS, FT);
}
if((OP >> 21 & 31) == 20)
switch(OP & 0x3f) {
op(0x20, FCVT_S_W, FD, FS);
op(0x21, FCVT_D_W, FD, FS);
}
if((OP >> 21 & 31) == 21)
switch(OP & 0x3f) {
op(0x20, FCVT_S_L, FD, FS);
op(0x21, FCVT_D_L, FD, FS);
}
}
#undef DECODER_COP1
#endif
#undef SA
#undef RDn
#undef RTn
#undef RSn
#undef FD
#undef FS
#undef FT
#undef IMMi16
#undef IMMu16
#undef IMMu26
+19 -11
View File
@@ -379,16 +379,24 @@ auto CPU::Disassembler::FPU() -> vector<string> {
case 0x0f: return DS (s ? "floorws" : "floorwd");
case 0x20: return DS (i ? (s ? "cvtsw" : "cvtsl") : "cvtsd");
case 0x21: return DS (i ? (s ? "cvtdw" : "cvtdl") : "cvtds");
case 0x24: return DS (s ? "cvtws" : "cvtwd");
case 0x25: return DS (s ? "cvtls" : "cvtld");
case 0x30: case 0x38: return ST(s ? "cfs" : "cfd" );
case 0x31: case 0x39: return ST(s ? "cuns" : "cund" );
case 0x32: case 0x3a: return ST(s ? "ceqs" : "ceqd" );
case 0x33: case 0x3b: return ST(s ? "cueqs" : "cueqd");
case 0x34: case 0x3c: return ST(s ? "colts" : "coltd");
case 0x35: case 0x3d: return ST(s ? "cults" : "cultd");
case 0x36: case 0x3e: return ST(s ? "coles" : "coled");
case 0x37: case 0x3f: return ST(s ? "cules" : "culed");
case 0x24: return DS (s ? "cvtws" : "cvtwd" );
case 0x25: return DS (s ? "cvtls" : "cvtld" );
case 0x30: return ST(s ? "cfs" : "cfd" );
case 0x31: return ST(s ? "cuns" : "cund" );
case 0x32: return ST(s ? "ceqs" : "ceqd" );
case 0x33: return ST(s ? "cueqs" : "cueqd" );
case 0x34: return ST(s ? "colts" : "coltd" );
case 0x35: return ST(s ? "cults" : "cultd" );
case 0x36: return ST(s ? "coles" : "coled" );
case 0x37: return ST(s ? "cules" : "culed" );
case 0x38: return ST(s ? "csfs" : "csfd" );
case 0x39: return ST(s ? "cngles" : "cngled");
case 0x3a: return ST(s ? "cseqs" : "cseqd" );
case 0x3b: return ST(s ? "cngls" : "cngld" );
case 0x3c: return ST(s ? "clts" : "cltd" );
case 0x3d: return ST(s ? "cnges" : "cnged" );
case 0x3e: return ST(s ? "cles" : "cled" );
case 0x3f: return ST(s ? "cngts" : "cngtd" );
}
return {};
@@ -437,7 +445,7 @@ auto CPU::Disassembler::sccRegisterName(uint index) const -> string {
}
auto CPU::Disassembler::sccRegisterValue(uint index) const -> string {
if(showValues) return {sccRegisterName(index), hint("{$", hex(self.getControlRegister(index)), "}")};
if(showValues) return {sccRegisterName(index), hint("{$", hex(self.getControlRegister(index), 8L), "}")};
return sccRegisterName(index);
}
+141 -250
View File
@@ -1,300 +1,191 @@
#define CF fpu.csr.compare
#define FD(type) fgr<type>(OP >> 6 & 31)
#define FS(type) fgr<type>(OP >> 11 & 31)
#define FT(type) fgr<type>(OP >> 16 & 31)
#define FPU_SINGLE ((OP & 1 << 21) == 0)
#define FPU_DOUBLE ((OP & 1 << 21) != 0)
#define FPU_REAL ((OP & 1 << 23) == 0)
#define FPU_INTEGER ((OP & 1 << 23) != 0)
#define FD(type) fgr<type>(fd)
#define FS(type) fgr<type>(fs)
#define FT(type) fgr<type>(ft)
auto CPU::instructionBC1() -> void {
bool condition = OP >> 16 & 1;
bool likely = OP >> 17 & 1;
if(CF == condition) branch.take(PC + 4 + (IMMi16 << 2));
auto CPU::instructionBC1(bool value, bool likely, i16 imm) -> void {
if(CF == value) branch.take(PC + 4 + (imm << 2));
else if(likely) branch.discard();
}
auto CPU::instructionCFC1() -> void {
RT.u64 = i32(getControlRegisterFPU(RDn));
auto CPU::instructionCFC1(r64& rt, u8 rd) -> void {
rt.u64 = i32(getControlRegisterFPU(rd));
}
auto CPU::instructionCTC1() -> void {
setControlRegisterFPU(RDn, RT.u32);
auto CPU::instructionCTC1(cr64& rt, u8 rd) -> void {
setControlRegisterFPU(rd, rt.u32);
}
auto CPU::instructionDMFC1() -> void {
RT.u64 = FS(u64);
auto CPU::instructionDMFC1(r64& rt, u8 fs) -> void {
rt.u64 = FS(u64);
}
auto CPU::instructionDMTC1() -> void {
FS(u64) = RT.u64;
auto CPU::instructionDMTC1(cr64& rt, u8 fs) -> void {
FS(u64) = rt.u64;
}
auto CPU::instructionFABS() -> void {
if(FPU_SINGLE) {
FD(f32) = fabs(FS(f32));
} else {
FD(f64) = fabs(FS(f64));
auto CPU::instructionFABS_S(u8 fd, u8 fs) -> void { FD(f32) = fabs(FS(f32)); }
auto CPU::instructionFABS_D(u8 fd, u8 fs) -> void { FD(f64) = fabs(FS(f64)); }
auto CPU::instructionFADD_S(u8 fd, u8 fs, u8 ft) -> void { FD(f32) = FS(f32) + FT(f32); }
auto CPU::instructionFADD_D(u8 fd, u8 fs, u8 ft) -> void { FD(f64) = FS(f64) + FT(f64); }
auto CPU::instructionFCEIL_L_S(u8 fd, u8 fs) -> void { FD(i64) = ceil(FS(f32)); }
auto CPU::instructionFCEIL_L_D(u8 fd, u8 fs) -> void { FD(i64) = ceil(FS(f64)); }
auto CPU::instructionFCEIL_W_S(u8 fd, u8 fs) -> void { FD(i32) = ceil(FS(f32)); }
auto CPU::instructionFCEIL_W_D(u8 fd, u8 fs) -> void { FD(i32) = ceil(FS(f64)); }
#define ORDERED(type, value) if(isnan(FS(type)) || isnan(FT(type))) { CF = value; return exception.floatingPoint(); }
#define UNORDERED(type, value) if(isnan(FS(type)) || isnan(FT(type))) { CF = value; return; }
auto CPU::instructionFC_EQ_S(u8 fs, u8 ft) -> void { UNORDERED(f32, 0); CF = FS(f32) == FT(f32); }
auto CPU::instructionFC_EQ_D(u8 fs, u8 ft) -> void { UNORDERED(f64, 0); CF = FS(f64) == FT(f64); }
auto CPU::instructionFC_F_S(u8 fs, u8 ft) -> void { UNORDERED(f32, 0); CF = 0; }
auto CPU::instructionFC_F_D(u8 fs, u8 ft) -> void { UNORDERED(f64, 0); CF = 0; }
auto CPU::instructionFC_LE_S(u8 fs, u8 ft) -> void { ORDERED(f32, 0); CF = FS(f32) <= FT(f32); }
auto CPU::instructionFC_LE_D(u8 fs, u8 ft) -> void { ORDERED(f64, 0); CF = FS(f64) <= FT(f64); }
auto CPU::instructionFC_LT_S(u8 fs, u8 ft) -> void { ORDERED(f32, 0); CF = FS(f32) < FT(f32); }
auto CPU::instructionFC_LT_D(u8 fs, u8 ft) -> void { ORDERED(f64, 0); CF = FS(f64) < FT(f64); }
auto CPU::instructionFC_NGE_S(u8 fs, u8 ft) -> void { ORDERED(f32, 1); CF = FS(f32) < FT(f32); }
auto CPU::instructionFC_NGE_D(u8 fs, u8 ft) -> void { ORDERED(f64, 1); CF = FS(f64) < FT(f64); }
auto CPU::instructionFC_NGL_S(u8 fs, u8 ft) -> void { ORDERED(f32, 1); CF = FS(f32) == FT(f32); }
auto CPU::instructionFC_NGL_D(u8 fs, u8 ft) -> void { ORDERED(f64, 1); CF = FS(f64) == FT(f64); }
auto CPU::instructionFC_NGLE_S(u8 fs, u8 ft) -> void { ORDERED(f32, 1); CF = 0; }
auto CPU::instructionFC_NGLE_D(u8 fs, u8 ft) -> void { ORDERED(f64, 1); CF = 0; }
auto CPU::instructionFC_NGT_S(u8 fs, u8 ft) -> void { ORDERED(f32, 1); CF = FS(f32) <= FT(f32); }
auto CPU::instructionFC_NGT_D(u8 fs, u8 ft) -> void { ORDERED(f64, 1); CF = FS(f64) <= FT(f64); }
auto CPU::instructionFC_OLE_S(u8 fs, u8 ft) -> void { UNORDERED(f32, 0); CF = FS(f32) <= FT(f32); }
auto CPU::instructionFC_OLE_D(u8 fs, u8 ft) -> void { UNORDERED(f64, 0); CF = FS(f64) <= FT(f64); }
auto CPU::instructionFC_OLT_S(u8 fs, u8 ft) -> void { UNORDERED(f32, 0); CF = FS(f32) < FT(f32); }
auto CPU::instructionFC_OLT_D(u8 fs, u8 ft) -> void { UNORDERED(f64, 0); CF = FS(f64) < FT(f64); }
auto CPU::instructionFC_SEQ_S(u8 fs, u8 ft) -> void { ORDERED(f32, 0); CF = FS(f32) == FT(f32); }
auto CPU::instructionFC_SEQ_D(u8 fs, u8 ft) -> void { ORDERED(f64, 0); CF = FS(f64) == FT(f64); }
auto CPU::instructionFC_SF_S(u8 fs, u8 ft) -> void { ORDERED(f32, 0); CF = 0; }
auto CPU::instructionFC_SF_D(u8 fs, u8 ft) -> void { ORDERED(f64, 0); CF = 0; }
auto CPU::instructionFC_UEQ_S(u8 fs, u8 ft) -> void { UNORDERED(f32, 1); CF = FS(f32) == FT(f32); }
auto CPU::instructionFC_UEQ_D(u8 fs, u8 ft) -> void { UNORDERED(f64, 1); CF = FS(f64) == FT(f64); }
auto CPU::instructionFC_ULE_S(u8 fs, u8 ft) -> void { UNORDERED(f32, 1); CF = FS(f32) <= FT(f32); }
auto CPU::instructionFC_ULE_D(u8 fs, u8 ft) -> void { UNORDERED(f64, 1); CF = FS(f64) <= FT(f64); }
auto CPU::instructionFC_ULT_S(u8 fs, u8 ft) -> void { UNORDERED(f32, 1); CF = FS(f32) < FT(f32); }
auto CPU::instructionFC_ULT_D(u8 fs, u8 ft) -> void { UNORDERED(f64, 1); CF = FS(f64) < FT(f64); }
auto CPU::instructionFC_UN_S(u8 fs, u8 ft) -> void { UNORDERED(f32, 1); CF = 0; }
auto CPU::instructionFC_UN_D(u8 fs, u8 ft) -> void { UNORDERED(f64, 1); CF = 0; }
#undef ORDERED
#undef UNORDERED
auto CPU::instructionFCVT_S_D(u8 fd, u8 fs) -> void { FD(f32) = FS(f64); }
auto CPU::instructionFCVT_S_W(u8 fd, u8 fs) -> void { FD(f32) = FS(i32); }
auto CPU::instructionFCVT_S_L(u8 fd, u8 fs) -> void { FD(f32) = FS(i64); }
auto CPU::instructionFCVT_D_S(u8 fd, u8 fs) -> void { FD(f64) = FS(f32); }
auto CPU::instructionFCVT_D_W(u8 fd, u8 fs) -> void { FD(f64) = FS(i32); }
auto CPU::instructionFCVT_D_L(u8 fd, u8 fs) -> void { FD(f64) = FS(i64); }
auto CPU::instructionFCVT_L_S(u8 fd, u8 fs) -> void { FD(i64) = FS(f32); }
auto CPU::instructionFCVT_L_D(u8 fd, u8 fs) -> void { FD(i64) = FS(f64); }
auto CPU::instructionFCVT_W_S(u8 fd, u8 fs) -> void { FD(i32) = FS(f32); }
auto CPU::instructionFCVT_W_D(u8 fd, u8 fs) -> void { FD(i32) = FS(f64); }
auto CPU::instructionFDIV_S(u8 fd, u8 fs, u8 ft) -> void {
if(FT(f32)) {
FD(f32) = FS(f32) / FT(f32);
} else if(fpu.csr.enable.divisionByZero) {
fpu.csr.flag.divisionByZero = 1;
fpu.csr.cause.divisionByZero = 1;
exception.floatingPoint();
}
}
auto CPU::instructionFADD() -> void {
if(FPU_SINGLE) {
FD(f32) = FS(f32) + FT(f32);
} else {
FD(f64) = FS(f64) + FT(f64);
auto CPU::instructionFDIV_D(u8 fd, u8 fs, u8 ft) -> void {
if(FT(f64)) {
FD(f64) = FS(f64) / FT(f64);
} else if(fpu.csr.enable.divisionByZero) {
fpu.csr.flag.divisionByZero = 1;
fpu.csr.cause.divisionByZero = 1;
exception.floatingPoint();
}
}
auto CPU::instructionFCEILL() -> void {
if(FPU_SINGLE) {
FD(i64) = ceil(FS(f32));
} else {
FD(i64) = ceil(FS(f64));
}
}
auto CPU::instructionFFLOOR_L_S(u8 fd, u8 fs) -> void { FD(i64) = floor(FS(f32)); }
auto CPU::instructionFFLOOR_L_D(u8 fd, u8 fs) -> void { FD(i64) = floor(FS(f64)); }
auto CPU::instructionFCEILW() -> void {
if(FPU_SINGLE) {
FD(i32) = ceil(FS(f32));
} else {
FD(i32) = ceil(FS(f64));
}
}
auto CPU::instructionFFLOOR_W_S(u8 fd, u8 fs) -> void { FD(i32) = floor(FS(f32)); }
auto CPU::instructionFFLOOR_W_D(u8 fd, u8 fs) -> void { FD(i32) = floor(FS(f64)); }
auto CPU::instructionFCEQ() -> void {
if(FPU_SINGLE) {
CF = FS(f32) == FT(f32);
} else {
CF = FS(f64) == FT(f64);
}
}
auto CPU::instructionFMOV_S(u8 fd, u8 fs) -> void { FD(f32) = FS(f32); }
auto CPU::instructionFMOV_D(u8 fd, u8 fs) -> void { FD(f64) = FS(f64); }
auto CPU::instructionFCF() -> void {
CF = 0;
}
auto CPU::instructionFMUL_S(u8 fd, u8 fs, u8 ft) -> void { FD(f32) = FS(f32) * FT(f32); }
auto CPU::instructionFMUL_D(u8 fd, u8 fs, u8 ft) -> void { FD(f64) = FS(f64) * FT(f64); }
auto CPU::instructionFCOLE() -> void {
if(FPU_SINGLE) {
CF = FS(f32) <= FT(f32);
} else {
CF = FS(f64) <= FT(f64);
}
}
auto CPU::instructionFNEG_S(u8 fd, u8 fs) -> void { FD(f32) = -FS(f32); }
auto CPU::instructionFNEG_D(u8 fd, u8 fs) -> void { FD(f64) = -FS(f64); }
auto CPU::instructionFCOLT() -> void {
if(FPU_SINGLE) {
CF = FS(f32) < FT(f32);
} else {
CF = FS(f64) < FT(f64);
}
}
auto CPU::instructionFROUND_L_S(u8 fd, u8 fs) -> void { FD(i64) = nearbyint(FS(f32)); }
auto CPU::instructionFROUND_L_D(u8 fd, u8 fs) -> void { FD(i64) = nearbyint(FS(f64)); }
auto CPU::instructionFCUEQ() -> void {
if(FPU_SINGLE) {
CF = FS(f32) == FT(f32);
} else {
CF = FS(f64) == FT(f64);
}
}
auto CPU::instructionFROUND_W_S(u8 fd, u8 fs) -> void { FD(i32) = nearbyint(FS(f32)); }
auto CPU::instructionFROUND_W_D(u8 fd, u8 fs) -> void { FD(i32) = nearbyint(FS(f64)); }
auto CPU::instructionFCULE() -> void {
if(FPU_SINGLE) {
CF = FS(f32) <= FT(f32);
} else {
CF = FS(f64) <= FT(f64);
}
}
auto CPU::instructionFSQRT_S(u8 fd, u8 fs) -> void { FD(f32) = sqrt(FS(f32)); }
auto CPU::instructionFSQRT_D(u8 fd, u8 fs) -> void { FD(f64) = sqrt(FS(f64)); }
auto CPU::instructionFCULT() -> void {
if(FPU_SINGLE) {
CF = FS(f32) < FT(f32);
} else {
CF = FS(f64) < FT(f64);
}
}
auto CPU::instructionFSUB_S(u8 fd, u8 fs, u8 ft) -> void { FD(f32) = FS(f32) - FT(f32); }
auto CPU::instructionFSUB_D(u8 fd, u8 fs, u8 ft) -> void { FD(f64) = FS(f64) - FT(f64); }
auto CPU::instructionFCUN() -> void {
CF = 0;
}
auto CPU::instructionFTRUNC_L_S(u8 fd, u8 fs) -> void { FD(i64) = FS(f32) < 0 ? ceil(FS(f32)) : floor(FS(f32)); }
auto CPU::instructionFTRUNC_L_D(u8 fd, u8 fs) -> void { FD(i64) = FS(f64) < 0 ? ceil(FS(f64)) : floor(FS(f64)); }
auto CPU::instructionFCVTS() -> void {
if(FPU_REAL) {
FD(f32) = FS(f64);
} else if(FPU_SINGLE) {
FD(f32) = FS(i32);
} else {
FD(f32) = FS(i64);
}
}
auto CPU::instructionFTRUNC_W_S(u8 fd, u8 fs) -> void { FD(i32) = FS(f32) < 0 ? ceil(FS(f32)) : floor(FS(f32)); }
auto CPU::instructionFTRUNC_W_D(u8 fd, u8 fs) -> void { FD(i32) = FS(f64) < 0 ? ceil(FS(f64)) : floor(FS(f64)); }
auto CPU::instructionFCVTD() -> void {
if(FPU_REAL) {
FD(f64) = FS(f32);
} else if(FPU_SINGLE) {
FD(f64) = FS(i32);
} else {
FD(f64) = FS(i64);
}
}
auto CPU::instructionFCVTL() -> void {
if(FPU_SINGLE) {
FD(i64) = FS(f32);
} else {
FD(i64) = FS(f64);
}
}
auto CPU::instructionFCVTW() -> void {
if(FPU_SINGLE) {
FD(i32) = FS(f32);
} else {
FD(i32) = FS(f64);
}
}
auto CPU::instructionFDIV() -> void {
if(FPU_SINGLE) {
if(FT(f32)) {
FD(f32) = FS(f32) / FT(f32);
} else if(fpu.csr.enable.divisionByZero) {
fpu.csr.flag.divisionByZero = 1;
fpu.csr.cause.divisionByZero = 1;
exception.floatingPoint();
}
} else {
if(FT(f64)) {
FD(f64) = FS(f64) / FT(f64);
} else if(fpu.csr.enable.divisionByZero) {
fpu.csr.flag.divisionByZero = 1;
fpu.csr.cause.divisionByZero = 1;
exception.floatingPoint();
}
}
}
auto CPU::instructionFFLOORL() -> void {
if(FPU_SINGLE) {
FD(i64) = floor(FS(f32));
} else {
FD(i64) = floor(FS(f64));
}
}
auto CPU::instructionFFLOORW() -> void {
if(FPU_SINGLE) {
FD(i32) = floor(FS(f32));
} else {
FD(i32) = floor(FS(f64));
}
}
auto CPU::instructionFMOV() -> void {
if(FPU_SINGLE) {
FD(f32) = FS(f32);
} else {
FD(f64) = FS(f64);
}
}
auto CPU::instructionFMUL() -> void {
if(FPU_SINGLE) {
FD(f32) = FS(f32) * FT(f32);
} else {
FD(f64) = FS(f64) * FT(f64);
}
}
auto CPU::instructionFNEG() -> void {
if(FPU_SINGLE) {
FD(f32) = -FS(f32);
} else {
FD(f64) = -FS(f64);
}
}
auto CPU::instructionFROUNDL() -> void {
if(FPU_SINGLE) {
FD(i64) = nearbyint(FS(f32));
} else {
FD(i64) = nearbyint(FS(f64));
}
}
auto CPU::instructionFROUNDW() -> void {
if(FPU_SINGLE) {
FD(i32) = nearbyint(FS(f32));
} else {
FD(i32) = nearbyint(FS(f64));
}
}
auto CPU::instructionFSQRT() -> void {
if(FPU_SINGLE) {
FD(f32) = sqrt(FS(f32));
} else {
FD(f64) = sqrt(FS(f64));
}
}
auto CPU::instructionFSUB() -> void {
if(FPU_SINGLE) {
FD(f32) = FS(f32) - FT(f32);
} else {
FD(f64) = FS(f64) - FT(f64);
}
}
auto CPU::instructionFTRUNCL() -> void {
if(FPU_SINGLE) {
FD(i64) = FS(f32) < 0 ? ceil(FS(f32)) : floor(FS(f32));
} else {
FD(i64) = FS(f64) < 0 ? ceil(FS(f64)) : floor(FS(f64));
}
}
auto CPU::instructionFTRUNCW() -> void {
if(FPU_SINGLE) {
FD(i32) = FS(f32) < 0 ? ceil(FS(f32)) : floor(FS(f32));
} else {
FD(i32) = FS(f64) < 0 ? ceil(FS(f64)) : floor(FS(f64));
}
}
auto CPU::instructionLDC1() -> void {
auto CPU::instructionLDC1(u8 ft, cr64& rs, i16 imm) -> void {
if(!scc.status.enable.coprocessor1) return exception.coprocessor1();
if(auto data = readDouble(RS.u32 + IMMi16)) FT(u64) = *data;
if(auto data = readDouble(rs.u32 + imm)) FT(u64) = *data;
}
auto CPU::instructionLWC1() -> void {
auto CPU::instructionLWC1(u8 ft, cr64& rs, i16 imm) -> void {
if(!scc.status.enable.coprocessor1) return exception.coprocessor1();
if(auto data = readWord(RS.u32 + IMMi16)) FT(u32) = *data;
if(auto data = readWord(rs.u32 + imm)) FT(u32) = *data;
}
auto CPU::instructionMFC1() -> void {
RT.u64 = FS(i32);
auto CPU::instructionMFC1(r64& rt, u8 fs) -> void {
rt.u64 = FS(i32);
}
auto CPU::instructionMTC1() -> void {
FS(i32) = RT.u32;
auto CPU::instructionMTC1(cr64& rt, u8 fs) -> void {
FS(i32) = rt.u32;
}
auto CPU::instructionSDC1() -> void {
auto CPU::instructionSDC1(u8 ft, cr64& rs, i16 imm) -> void {
if(!scc.status.enable.coprocessor1) return exception.coprocessor1();
writeDouble(RS.u32 + IMMi16, FT(u64));
writeDouble(rs.u32 + imm, FT(u64));
}
auto CPU::instructionSWC1() -> void {
auto CPU::instructionSWC1(u8 ft, cr64& rs, i16 imm) -> void {
if(!scc.status.enable.coprocessor1) return exception.coprocessor1();
writeWord(RS.u32 + IMMi16, FT(u32));
writeWord(rs.u32 + imm, FT(u32));
}
#undef CF
#undef FD
#undef FS
#undef FT
#undef FPU_SINGLE
#undef FPU_DOUBLE
#undef FPU_REAL
#undef FPU_INTEGER
+8
View File
@@ -1,3 +1,11 @@
auto CPU::FPU::setFloatingPointMode(bool mode) -> void {
if(mode == 0) {
//32x64-bit -> 16x64-bit
} else {
//16x64-bit -> 32x64-bit
}
}
template<> auto CPU::fgr<i32>(uint index) -> i32& {
if(scc.status.floatingPointMode) {
return fpu.r[index].i32;
+89 -49
View File
@@ -4,17 +4,11 @@
auto getControlRegisterFPU(uint5) -> u32;
auto setControlRegisterFPU(uint5, uint32) -> void;
union fpu64 {
struct { int32_t order_msb2(i32h, i32); };
struct { uint32_t order_msb2(u32h, u32); };
struct { float32_t order_msb2(f32h, f32); };
struct { int64_t i64; };
struct { uint64_t u64; };
struct { float64_t f64; };
};
struct FPU {
fpu64 r[32];
//fpu-registers.cpp
auto setFloatingPointMode(bool) -> void;
r64 r[32];
struct Coprocessor {
static constexpr u8 revision = 0x00;
@@ -51,43 +45,89 @@
} fpu;
//fpu-instructions.cpp
auto instructionBC1() -> void;
auto instructionCFC1() -> void;
auto instructionCTC1() -> void;
auto instructionDMFC1() -> void;
auto instructionDMTC1() -> void;
auto instructionFABS() -> void;
auto instructionFADD() -> void;
auto instructionFCEILL() -> void;
auto instructionFCEILW() -> void;
auto instructionFCEQ() -> void;
auto instructionFCF() -> void;
auto instructionFCOLE() -> void;
auto instructionFCOLT() -> void;
auto instructionFCUEQ() -> void;
auto instructionFCULE() -> void;
auto instructionFCULT() -> void;
auto instructionFCUN() -> void;
auto instructionFCVTS() -> void;
auto instructionFCVTD() -> void;
auto instructionFCVTL() -> void;
auto instructionFCVTW() -> void;
auto instructionFDIV() -> void;
auto instructionFFLOORL() -> void;
auto instructionFFLOORW() -> void;
auto instructionFMOV() -> void;
auto instructionFMUL() -> void;
auto instructionFNEG() -> void;
auto instructionFROUNDL() -> void;
auto instructionFROUNDW() -> void;
auto instructionFSQRT() -> void;
auto instructionFSUB() -> void;
auto instructionFTRUNCL() -> void;
auto instructionFTRUNCW() -> void;
auto instructionLDC1() -> void;
auto instructionLWC1() -> void;
auto instructionMFC1() -> void;
auto instructionMTC1() -> void;
auto instructionSDC1() -> void;
auto instructionSWC1() -> void;
auto instructionBC1(bool value, bool likely, i16 imm) -> void;
auto instructionCFC1(r64& rt, u8 rd) -> void;
auto instructionCTC1(cr64& rt, u8 rd) -> void;
auto instructionDMFC1(r64& rt, u8 fs) -> void;
auto instructionDMTC1(cr64& rt, u8 fs) -> void;
auto instructionFABS_S(u8 fd, u8 fs) -> void;
auto instructionFABS_D(u8 fd, u8 fs) -> void;
auto instructionFADD_S(u8 fd, u8 fs, u8 ft) -> void;
auto instructionFADD_D(u8 fd, u8 fs, u8 ft) -> void;
auto instructionFCEIL_L_S(u8 fd, u8 fs) -> void;
auto instructionFCEIL_L_D(u8 fd, u8 fs) -> void;
auto instructionFCEIL_W_S(u8 fd, u8 fs) -> void;
auto instructionFCEIL_W_D(u8 fd, u8 fs) -> void;
auto instructionFC_EQ_S(u8 fs, u8 ft) -> void;
auto instructionFC_EQ_D(u8 fs, u8 ft) -> void;
auto instructionFC_F_S(u8 fs, u8 ft) -> void;
auto instructionFC_F_D(u8 fs, u8 ft) -> void;
auto instructionFC_LE_S(u8 fs, u8 ft) -> void;
auto instructionFC_LE_D(u8 fs, u8 ft) -> void;
auto instructionFC_LT_S(u8 fs, u8 ft) -> void;
auto instructionFC_LT_D(u8 fs, u8 ft) -> void;
auto instructionFC_NGE_S(u8 fs, u8 ft) -> void;
auto instructionFC_NGE_D(u8 fs, u8 ft) -> void;
auto instructionFC_NGL_S(u8 fs, u8 ft) -> void;
auto instructionFC_NGL_D(u8 fs, u8 ft) -> void;
auto instructionFC_NGLE_S(u8 fs, u8 ft) -> void;
auto instructionFC_NGLE_D(u8 fs, u8 ft) -> void;
auto instructionFC_NGT_S(u8 fs, u8 ft) -> void;
auto instructionFC_NGT_D(u8 fs, u8 ft) -> void;
auto instructionFC_OLE_S(u8 fs, u8 ft) -> void;
auto instructionFC_OLE_D(u8 fs, u8 ft) -> void;
auto instructionFC_OLT_S(u8 fs, u8 ft) -> void;
auto instructionFC_OLT_D(u8 fs, u8 ft) -> void;
auto instructionFC_SEQ_S(u8 fs, u8 ft) -> void;
auto instructionFC_SEQ_D(u8 fs, u8 ft) -> void;
auto instructionFC_SF_S(u8 fs, u8 ft) -> void;
auto instructionFC_SF_D(u8 fs, u8 ft) -> void;
auto instructionFC_UEQ_S(u8 fs, u8 ft) -> void;
auto instructionFC_UEQ_D(u8 fs, u8 ft) -> void;
auto instructionFC_ULE_S(u8 fs, u8 ft) -> void;
auto instructionFC_ULE_D(u8 fs, u8 ft) -> void;
auto instructionFC_ULT_S(u8 fs, u8 ft) -> void;
auto instructionFC_ULT_D(u8 fs, u8 ft) -> void;
auto instructionFC_UN_S(u8 fs, u8 ft) -> void;
auto instructionFC_UN_D(u8 fs, u8 ft) -> void;
auto instructionFCVT_S_D(u8 fd, u8 fs) -> void;
auto instructionFCVT_S_W(u8 fd, u8 fs) -> void;
auto instructionFCVT_S_L(u8 fd, u8 fs) -> void;
auto instructionFCVT_D_S(u8 fd, u8 fs) -> void;
auto instructionFCVT_D_W(u8 fd, u8 fs) -> void;
auto instructionFCVT_D_L(u8 fd, u8 fs) -> void;
auto instructionFCVT_L_S(u8 fd, u8 fs) -> void;
auto instructionFCVT_L_D(u8 fd, u8 fs) -> void;
auto instructionFCVT_W_S(u8 fd, u8 fs) -> void;
auto instructionFCVT_W_D(u8 fd, u8 fs) -> void;
auto instructionFDIV_S(u8 fd, u8 fs, u8 ft) -> void;
auto instructionFDIV_D(u8 fd, u8 fs, u8 ft) -> void;
auto instructionFFLOOR_L_S(u8 fd, u8 fs) -> void;
auto instructionFFLOOR_L_D(u8 fd, u8 fs) -> void;
auto instructionFFLOOR_W_S(u8 fd, u8 fs) -> void;
auto instructionFFLOOR_W_D(u8 fd, u8 fs) -> void;
auto instructionFMOV_S(u8 fd, u8 fs) -> void;
auto instructionFMOV_D(u8 fd, u8 fs) -> void;
auto instructionFMUL_S(u8 fd, u8 fs, u8 ft) -> void;
auto instructionFMUL_D(u8 fd, u8 fs, u8 ft) -> void;
auto instructionFNEG_S(u8 fd, u8 fs) -> void;
auto instructionFNEG_D(u8 fd, u8 fs) -> void;
auto instructionFROUND_L_S(u8 fd, u8 fs) -> void;
auto instructionFROUND_L_D(u8 fd, u8 fs) -> void;
auto instructionFROUND_W_S(u8 fd, u8 fs) -> void;
auto instructionFROUND_W_D(u8 fd, u8 fs) -> void;
auto instructionFSQRT_S(u8 fd, u8 fs) -> void;
auto instructionFSQRT_D(u8 fd, u8 fs) -> void;
auto instructionFSUB_S(u8 fd, u8 fs, u8 ft) -> void;
auto instructionFSUB_D(u8 fd, u8 fs, u8 ft) -> void;
auto instructionFTRUNC_L_S(u8 fd, u8 fs) -> void;
auto instructionFTRUNC_L_D(u8 fd, u8 fs) -> void;
auto instructionFTRUNC_W_S(u8 fd, u8 fs) -> void;
auto instructionFTRUNC_W_D(u8 fd, u8 fs) -> void;
auto instructionLDC1(u8 ft, cr64& rs, i16 imm) -> void;
auto instructionLWC1(u8 ft, cr64& rs, i16 imm) -> void;
auto instructionMFC1(r64& rt, u8 fs) -> void;
auto instructionMTC1(cr64& rt, u8 fs) -> void;
auto instructionSDC1(u8 ft, cr64& rs, i16 imm) -> void;
auto instructionSWC1(u8 ft, cr64& rs, i16 imm) -> void;
//};
-317
View File
@@ -1,317 +0,0 @@
auto CPU::raiseException(uint code, uint coprocessor) -> void {
if(debugger.tracer.exception->enabled()) {
if(code != 0) debugger.exception(hex(code, 2L));
}
if(!scc.status.exceptionLevel) {
if(code == 10) print("* reserved instruction @ ", hex(pipeline.address), " ", hex(pipeline.instruction), "\n");
scc.epc = PC;
scc.status.exceptionLevel = 1;
scc.cause.exceptionCode = code;
scc.cause.coprocessorError = coprocessor;
if(scc.cause.branchDelay = branch.inDelaySlot()) scc.epc -= 4;
} else {
scc.cause.exceptionCode = code;
scc.cause.coprocessorError = coprocessor;
}
u64 vectorBase = !scc.status.vectorLocation ? i32(0x8000'0000) : i32(0xbfc0'0200);
u32 vectorOffset = (code == 2 || code == 3) ? 0x0000 : 0x0180;
PC = vectorBase + vectorOffset;
branch.exception();
context.setMode();
}
auto CPU::instruction() -> void {
pipeline.address = PC;
pipeline.instruction = readWord(pipeline.address)(0);
if(auto interrupts = scc.cause.interruptPending & scc.status.interruptMask) {
if(scc.status.interruptEnable && !scc.status.exceptionLevel && !scc.status.errorLevel) {
if(debugger.tracer.interrupt->enabled()) {
debugger.interrupt(hex(scc.cause.interruptPending, 2L));
}
scc.cause.interruptPending = interrupts;
return raiseException(0, interrupts);
}
}
debugger.instruction();
//instructionDEBUG();
instructionEXECUTE();
GPR[0].u64 = 0;
switch(branch.state) {
case Branch::Step: PC += 4; break;
case Branch::DelaySlot: PC = branch.pc; branch.reset(); break;
case Branch::Take: PC += 4; branch.delaySlot(); break;
case Branch::Exception: branch.reset(); break;
case Branch::Discard: PC += 8; branch.reset(); break;
}
if(--scc.random.index < scc.wired.index) {
scc.random.index = 31;
}
}
auto CPU::instructionDEBUG() -> void {
static vector<bool> mask;
if(!mask) mask.resize(0x08000000);
//if(mask[(PC & 0x1fffffff) >> 2]) return;
mask[(PC & 0x1fffffff) >> 2] = 1;
static uint counter = 0;
//if(++counter > 100) return;
print(
disassembler.hint(hex(pipeline.address, 8L)), " ",
//disassembler.hint(hex(pipeline.instruction, 8L)), " ",
disassembler.disassemble(pipeline.address, pipeline.instruction), "\n"
);
}
auto CPU::instructionEXECUTE() -> void {
switch(OP >> 26) {
case 0x00: return instructionSPECIAL();
case 0x01: return instructionREGIMM();
case 0x02: return instructionJ();
case 0x03: return instructionJAL();
case 0x04: return instructionB(RS.u64 == RT.u64); //BEQ
case 0x05: return instructionB(RS.u64 != RT.u64); //BNE
case 0x06: return instructionB(RS.i64 <= 0); //BLEZ
case 0x07: return instructionB(RS.i64 > 0); //BGTZ
case 0x08: return instructionADDI();
case 0x09: return instructionADDIU();
case 0x0a: return instructionSLTI();
case 0x0b: return instructionSLTIU();
case 0x0c: return instructionANDI();
case 0x0d: return instructionORI();
case 0x0e: return instructionXORI();
case 0x0f: return instructionLUI();
case 0x10: return instructionCOP0();
case 0x11: return instructionCOP1();
case 0x12: return exception.coprocessor2(); //COP2
case 0x13: return exception.coprocessor3(); //COP3
case 0x14: return instructionBL(RS.u64 == RT.u64); //BEQL
case 0x15: return instructionBL(RS.u64 != RT.u64); //BNEL
case 0x16: return instructionBL(RS.i64 <= 0); //BLEZL
case 0x17: return instructionBL(RS.i64 > 0); //BGTZL
case 0x18: return instructionDADDI();
case 0x19: return instructionDADDIU();
case 0x1a: return instructionLDL();
case 0x1b: return instructionLDR();
case 0x1c: break;
case 0x1d: break;
case 0x1e: break;
case 0x1f: break;
case 0x20: return instructionLB();
case 0x21: return instructionLH();
case 0x22: return instructionLWL();
case 0x23: return instructionLW();
case 0x24: return instructionLBU();
case 0x25: return instructionLHU();
case 0x26: return instructionLWR();
case 0x27: return instructionLWU();
case 0x28: return instructionSB();
case 0x29: return instructionSH();
case 0x2a: return instructionSWL();
case 0x2b: return instructionSW();
case 0x2c: return instructionSDL();
case 0x2d: return instructionSDR();
case 0x2e: return instructionSWR();
case 0x2f: return instructionCACHE();
case 0x30: return instructionLL();
case 0x31: return instructionLWC1();
case 0x32: return exception.coprocessor2(); //LWC2
case 0x33: return exception.coprocessor3(); //LWC3
case 0x34: return instructionLLD();
case 0x35: return instructionLDC1();
case 0x36: return exception.coprocessor2(); //LDC2
case 0x37: return instructionLD();
case 0x38: return instructionSC();
case 0x39: return instructionSWC1();
case 0x3a: return exception.coprocessor2(); //SWC2
case 0x3b: return exception.coprocessor3(); //SWC3
case 0x3c: return instructionSCD();
case 0x3d: return instructionSDC1();
case 0x3e: return exception.coprocessor2(); //SDC2
case 0x3f: return instructionSD();
}
exception.reservedInstruction();
}
auto CPU::instructionSPECIAL() -> void {
switch(OP & 0x3f) {
case 0x00: return instructionSLL();
case 0x01: break;
case 0x02: return instructionSRL();
case 0x03: return instructionSRA();
case 0x04: return instructionSLLV();
case 0x05: break;
case 0x06: return instructionSRLV();
case 0x07: return instructionSRAV();
case 0x08: return instructionJR();
case 0x09: return instructionJALR();
case 0x0a: break;
case 0x0b: break;
case 0x0c: return instructionSYSCALL();
case 0x0d: return instructionBREAK();
case 0x0e: break;
case 0x0f: return; //SYNC
case 0x10: return instructionMFHI();
case 0x11: return instructionMTHI();
case 0x12: return instructionMFLO();
case 0x13: return instructionMTLO();
case 0x14: return instructionDSLLV();
case 0x15: break;
case 0x16: return instructionDSRLV();
case 0x17: return instructionDSRAV();
case 0x18: return instructionMULT();
case 0x19: return instructionMULTU();
case 0x1a: return instructionDIV();
case 0x1b: return instructionDIVU();
case 0x1c: return instructionDMULT();
case 0x1d: return instructionDMULTU();
case 0x1e: return instructionDDIV();
case 0x1f: return instructionDDIVU();
case 0x20: return instructionADD();
case 0x21: return instructionADDU();
case 0x22: return instructionSUB();
case 0x23: return instructionSUBU();
case 0x24: return instructionAND();
case 0x25: return instructionOR();
case 0x26: return instructionXOR();
case 0x27: return instructionNOR();
case 0x28: break;
case 0x29: break;
case 0x2a: return instructionSLT();
case 0x2b: return instructionSLTU();
case 0x2c: return instructionDADD();
case 0x2d: return instructionDADDU();
case 0x2e: return instructionDSUB();
case 0x2f: return instructionDSUBU();
case 0x30: return instructionTGE();
case 0x31: return instructionTGEU();
case 0x32: return instructionTLT();
case 0x33: return instructionTLTU();
case 0x34: return instructionTEQ();
case 0x35: break;
case 0x36: return instructionTNE();
case 0x37: break;
case 0x38: return instructionDSLL();
case 0x39: break;
case 0x3a: return instructionDSRL();
case 0x3b: return instructionDSRA();
case 0x3c: return instructionDSLL32();
case 0x3d: break;
case 0x3e: return instructionDSRL32();
case 0x3f: return instructionDSRA32();
}
exception.reservedInstruction();
}
auto CPU::instructionREGIMM() -> void {
switch(OP >> 16 & 0x1f) {
case 0x00: return instructionB (RS.i64 < 0); //BLTZ
case 0x01: return instructionB (RS.i64 >= 0); //BGEZ
case 0x02: return instructionBL(RS.i64 < 0); //BLTZL
case 0x03: return instructionBL(RS.i64 >= 0); //BGEZL
case 0x04: break;
case 0x05: break;
case 0x06: break;
case 0x07: break;
case 0x08: return instructionTGEI();
case 0x09: return instructionTGEIU();
case 0x0a: return instructionTLTI();
case 0x0b: return instructionTLTIU();
case 0x0c: return instructionTEQI();
case 0x0d: break;
case 0x0e: return instructionTNEI();
case 0x0f: break;
case 0x10: return instructionBAL (RS.i64 < 0); //BLTZAL
case 0x11: return instructionBAL (RS.i64 >= 0); //BGEZAL
case 0x12: return instructionBALL(RS.i64 < 0); //BLTZALL
case 0x13: return instructionBALL(RS.i64 >= 0); //BGEZALL
case 0x14: break;
case 0x15: break;
case 0x16: break;
case 0x17: break;
case 0x18: break;
case 0x19: break;
case 0x1a: break;
case 0x1b: break;
case 0x1c: break;
case 0x1d: break;
case 0x1e: break;
case 0x1f: break;
}
exception.reservedInstruction();
}
auto CPU::instructionCOP0() -> void {
if(!scc.status.enable.coprocessor0) {
if(context.mode != Context::Mode::Kernel) return exception.coprocessor0();
}
switch(OP >> 21 & 0x1f) {
case 0x00: return instructionMFC0();
case 0x01: return instructionDMFC0();
case 0x02: break; //CFC0
case 0x04: return instructionMTC0();
case 0x05: return instructionDMTC0();
case 0x06: break; //CTC0
case 0x08: break; //BC0F, BC0FL, BC0T, BC0TL
}
if(!(OP >> 25 & 1)) return exception.reservedInstruction();
switch(OP & 0x3f) {
case 0x01: return instructionTLBR();
case 0x02: return instructionTLBWI();
case 0x06: return instructionTLBWR();
case 0x08: return instructionTLBP();
case 0x18: return instructionERET();
}
//undefined instructions do not throw a reserved instruction exception
}
auto CPU::instructionCOP1() -> void {
if(!scc.status.enable.coprocessor1) return exception.coprocessor1();
switch(OP >> 21 & 0x1f) {
case 0x00: return instructionMFC1();
case 0x01: return instructionDMFC1();
case 0x02: return instructionCFC1();
case 0x04: return instructionMTC1();
case 0x05: return instructionDMTC1();
case 0x06: return instructionCTC1();
case 0x08: return instructionBC1();
}
if(!(OP >> 25 & 1)) return exception.reservedInstruction();
switch(OP & 0x3f) {
case 0x00: return instructionFADD();
case 0x01: return instructionFSUB();
case 0x02: return instructionFMUL();
case 0x03: return instructionFDIV();
case 0x04: return instructionFSQRT();
case 0x05: return instructionFABS();
case 0x06: return instructionFMOV();
case 0x07: return instructionFNEG();
case 0x08: return instructionFROUNDL();
case 0x09: return instructionFTRUNCL();
case 0x0a: return instructionFCEILL();
case 0x0b: return instructionFFLOORL();
case 0x0c: return instructionFROUNDW();
case 0x0d: return instructionFTRUNCW();
case 0x0e: return instructionFCEILW();
case 0x0f: return instructionFFLOORW();
case 0x20: return instructionFCVTS();
case 0x21: return instructionFCVTD();
case 0x24: return instructionFCVTW();
case 0x25: return instructionFCVTL();
case 0x30: case 0x38: return instructionFCF();
case 0x31: case 0x39: return instructionFCUN();
case 0x32: case 0x3a: return instructionFCEQ();
case 0x33: case 0x3b: return instructionFCUEQ();
case 0x34: case 0x3c: return instructionFCOLT();
case 0x35: case 0x3d: return instructionFCULT();
case 0x36: case 0x3e: return instructionFCOLE();
case 0x37: case 0x3f: return instructionFCULE();
}
//undefined instructions do not throw a reserved instruction exception
}
+114
View File
@@ -0,0 +1,114 @@
auto CPU::Recompiler::pool(u32 address) -> Pool* {
auto& pool = pools[address >> 8 & 0x1fffff];
if(!pool) pool = (Pool*)allocator.acquire(sizeof(Pool));
return pool;
}
auto CPU::Recompiler::block(u32 address) -> Block* {
auto& block = pool(address)->blocks[address >> 2 & 0x3f];
if(!block) block = emit(address);
return block;
}
auto CPU::Recompiler::emit(u32 address) -> Block* {
if(unlikely(allocator.available() < 1_MiB)) {
print("CPU allocator flush\n");
allocator.release(bump_allocator::zero_fill);
reset();
}
auto block = (Block*)allocator.acquire(sizeof(Block));
block->code = allocator.acquire();
bind({block->code, allocator.available()});
bool branched = 0;
uint instructions = 0;
uint idle = 0;
do {
u32 instruction = bus.readWord(address);
if(instruction == 0x1000'ffff) idle += 64; //accelerate idle loops
branched = emitEXECUTE(instruction);
call(&CPU::instructionEpilogue, &self);
test(rax, rax);
jz(imm8{+1});
ret();
address += 4;
if((address & 0xfc) == 0) break; //block boundary
} while(++instructions < 64 && !branched);
ret();
block->step = 2 * instructions + idle;
allocator.reserve(size());
//print(hex(PC, 8L), " ", instructions, " ", size(), "\n");
return block;
}
#define OP instruction
#define RD &self.GPR[RDn]
#define RT &self.GPR[RTn]
#define RS &self.GPR[RSn]
#define jp(id, name) \
case id: \
return emit##name(instruction); \
#define op(id, name, ...) \
case id: \
call(&CPU::instruction##name, &self, ##__VA_ARGS__); \
return 0; \
#define br(id, name, ...) \
case id: \
call(&CPU::instruction##name, &self, ##__VA_ARGS__); \
return 1; \
auto CPU::Recompiler::emitEXECUTE(u32 instruction) -> bool {
#define DECODER_EXECUTE
#include "decoder.hpp"
return 0;
}
auto CPU::Recompiler::emitSPECIAL(u32 instruction) -> bool {
#define DECODER_SPECIAL
#include "decoder.hpp"
return 0;
}
auto CPU::Recompiler::emitREGIMM(u32 instruction) -> bool {
#define DECODER_REGIMM
#include "decoder.hpp"
return 0;
}
auto CPU::Recompiler::emitCOP0(u32 instruction) -> bool {
#define DECODER_COP0
#include "decoder.hpp"
return 0;
}
auto CPU::Recompiler::emitCOP1(u32 instruction) -> bool {
call(&CPU::Recompiler::emitCheckCOP1, this);
test(rax, rax);
jz(imm8{+1});
ret();
#define DECODER_COP1
#include "decoder.hpp"
return 0;
}
auto CPU::Recompiler::emitCheckCOP1() -> bool {
if(!self.scc.status.enable.coprocessor1) {
return self.exception.coprocessor1(), true;
}
return false;
}
#undef jp
#undef op
#undef br
#undef OP
#undef RD
#undef RT
#undef RS
+41
View File
@@ -0,0 +1,41 @@
//{
struct Recompiler : recompiler::amd64 {
CPU& self;
Recompiler(CPU& self) : self(self) {}
struct Block {
auto execute() -> void {
((void (*)())code)();
}
u32 step;
u8* code;
};
struct Pool {
Block* blocks[1 << 6];
};
auto reset() -> void {
for(u32 index : range(1 << 21)) pools[index] = nullptr;
}
auto invalidate(u32 address) -> void {
pools[address >> 8 & 0x1fffff] = nullptr;
}
auto pool(u32 address) -> Pool*;
auto block(u32 address) -> Block*;
auto emit(u32 address) -> Block*;
auto emitEXECUTE(u32 instruction) -> bool;
auto emitSPECIAL(u32 instruction) -> bool;
auto emitREGIMM(u32 instruction) -> bool;
auto emitCOP0(u32 instruction) -> bool;
auto emitCOP1(u32 instruction) -> bool;
auto emitCheckCOP1() -> bool;
bump_allocator allocator;
Pool* pools[1 << 21]; //2_MiB * sizeof(void*) == 16_MiB
} recompiler{*this};
//};
-27
View File
@@ -1,47 +1,20 @@
#if !defined(CPU_REGISTERS_HPP)
#define CPU_REGISTERS_HPP
//instruction decoding
#define OP pipeline.instruction
#define SA (OP >> 6 & 31)
#define RDn (OP >> 11 & 31)
#define RTn (OP >> 16 & 31)
#define RSn (OP >> 21 & 31)
#define IMMi16 i16(OP)
#define IMMu16 u16(OP)
#define IMMu26 (OP & 0x03ff'ffff)
//CPU
#define GPR core.r
#define LO core.lo
#define HI core.hi
#define PC core.pc
#define RD GPR[RDn]
#define RT GPR[RTn]
#define RS GPR[RSn]
#define RA GPR[Core::Register::RA]
#else
#undef CPU_REGISTERS_HPP
//instruction decoding
#undef OP
#undef SA
#undef RDn
#undef RTn
#undef RSn
#undef IMMi16
#undef IMMu16
#undef IMMu26
//CPU
#undef GPR
#undef LO
#undef HI
#undef PC
#undef RD
#undef RT
#undef RS
#undef RA
#endif
+8 -8
View File
@@ -1,9 +1,9 @@
auto CPU::instructionDMFC0() -> void {
RT.u64 = getControlRegister(RDn);
auto CPU::instructionDMFC0(r64& rt, u8 rd) -> void {
rt.u64 = getControlRegister(rd);
}
auto CPU::instructionDMTC0() -> void {
setControlRegister(RDn, RT.u64);
auto CPU::instructionDMTC0(cr64& rt, u8 rd) -> void {
setControlRegister(rd, rt.u64);
}
auto CPU::instructionERET() -> void {
@@ -19,12 +19,12 @@ auto CPU::instructionERET() -> void {
context.setMode();
}
auto CPU::instructionMFC0() -> void {
RT.u64 = i32(getControlRegister(RDn));
auto CPU::instructionMFC0(r64& rt, u8 rd) -> void {
rt.u64 = i32(getControlRegister(rd));
}
auto CPU::instructionMTC0() -> void {
setControlRegister(RDn, i32(RT.u32));
auto CPU::instructionMTC0(cr64& rt, u8 rd) -> void {
setControlRegister(rd, i32(rt.u32));
}
auto CPU::instructionTLBP() -> void {
+6 -2
View File
@@ -181,7 +181,8 @@ auto CPU::setControlRegister(uint5 index, uint64 data) -> void {
scc.compare = data.bit(0,31);
scc.cause.interruptPending.bit(Interrupt::Timer) = 0;
break;
case 12: //status
case 12: {//status
bool floatingPointMode = scc.status.floatingPointMode;
scc.status.interruptEnable = data.bit( 0);
scc.status.exceptionLevel = data.bit( 1);
scc.status.errorLevel = data.bit( 2);
@@ -204,7 +205,10 @@ auto CPU::setControlRegister(uint5 index, uint64 data) -> void {
scc.status.enable.coprocessor1 = data.bit(29);
scc.status.enable.coprocessor2 = data.bit(30);
scc.status.enable.coprocessor3 = data.bit(31);
break;
if(floatingPointMode != scc.status.floatingPointMode) {
fpu.setFloatingPointMode(scc.status.floatingPointMode);
}
} break;
case 13: //cause
scc.cause.interruptPending.bit(0) = data.bit(8);
scc.cause.interruptPending.bit(1) = data.bit(9);
+1 -1
View File
@@ -23,7 +23,7 @@ auto CPU::TLB::store(u32 address) -> maybe<u32> {
auto CPU::TLB::exception(u32 address) -> void {
self.scc.badVirtualAddress = address;
self.scc.tlb.addressSpaceID = address >> 32; //note: needs u64 address
self.scc.tlb.addressSpaceID = 0; //address >> 32; //note: needs u64 address
self.scc.tlb.virtualAddress = address >> 13;
self.scc.context.badVirtualAddress = address >> 13;
self.scc.xcontext.badVirtualAddress = address >> 13;
+4 -4
View File
@@ -174,11 +174,11 @@
} scc;
//scc-instructions.cpp
auto instructionDMFC0() -> void;
auto instructionDMTC0() -> void;
auto instructionDMFC0(r64& rt, u8 rd) -> void;
auto instructionDMTC0(cr64& rt, u8 rd) -> void;
auto instructionERET() -> void;
auto instructionMFC0() -> void;
auto instructionMTC0() -> void;
auto instructionMFC0(r64& rt, u8 rd) -> void;
auto instructionMTC0(cr64& rt, u8 rd) -> void;
auto instructionTLBP() -> void;
auto instructionTLBR() -> void;
auto instructionTLBWI() -> void;
+3 -5
View File
@@ -19,7 +19,6 @@ auto CPU::unload() -> void {
auto CPU::main() -> void {
instruction();
step(2);
}
auto CPU::step(uint clocks) -> void {
@@ -32,11 +31,10 @@ auto CPU::step(uint clocks) -> void {
while(rsp.clock < 0) rsp.main();
while(rdp.clock < 0) rdp.main();
while(clocks--) {
if(++scc.count == scc.compare) {
scc.cause.interruptPending.bit(Interrupt::Timer) = 1;
}
if(scc.count < scc.compare && scc.count + clocks >= scc.compare) {
scc.cause.interruptPending.bit(Interrupt::Timer) = 1;
}
scc.count += clocks;
}
auto CPU::power(bool reset) -> void {
+31
View File
@@ -0,0 +1,31 @@
#include <n64/n64.hpp>
namespace ares::Nintendo64 {
DD dd;
#include "io.cpp"
#include "serialization.cpp"
auto DD::load(Node::Object parent) -> void {
node = parent->append<Node::Component>("Disk Drive");
c2s.allocate(0x400);
ds.allocate(0x100);
ms.allocate(0x40);
}
auto DD::unload() -> void {
c2s.reset();
ds.reset();
ms.reset();
node.reset();
iplrom.reset();
}
auto DD::power(bool reset) -> void {
iplrom.allocate(4_MiB);
if(auto fp = platform->open(node, "64dd.ipl.rom", File::Read)) {
iplrom.load(fp);
}
}
}
+24
View File
@@ -0,0 +1,24 @@
//Disk Drive
struct DD : Memory::IO<DD> {
Node::Component node;
Memory::Readable iplrom;
Memory::Writable c2s;
Memory::Writable ds;
Memory::Writable ms;
//dd.cpp
auto load(Node::Object) -> void;
auto unload() -> void;
auto power(bool reset) -> void;
//io.cpp
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
};
extern DD dd;
+8
View File
@@ -0,0 +1,8 @@
auto DD::readWord(u32 address) -> u32 {
uint32 data;
return data;
}
auto DD::writeWord(u32 address, u32 data) -> void {
}
+2
View File
@@ -0,0 +1,2 @@
auto DD::serialize(serializer& s) -> void {
}
+54 -200
View File
@@ -1,231 +1,85 @@
inline auto Bus::readByte(u32 address) -> u8 {
static auto transform = [&](u32 data) -> u8 {
switch(address & 3) {
case 0: return data >> 24;
case 1: return data >> 16;
case 2: return data >> 8;
case 3: return data >> 0;
} unreachable;
};
#define decode(write, access, ...) \
if(address <= 0x007f'ffff) return rdram.ram.access(__VA_ARGS__); \
if(address <= 0x03ef'ffff) return unmapped; \
if(address <= 0x03ff'ffff) return rdram.access(__VA_ARGS__); \
if(address <= 0x0400'0fff) return rsp.dmem.access(__VA_ARGS__); \
if(address <= 0x0400'1fff) { \
if constexpr(write) { rsp.recompiler.invalidate(); } \
return rsp.imem.access(__VA_ARGS__); \
} \
if(address <= 0x0403'ffff) return unmapped; \
if(address <= 0x0407'ffff) return rsp.access(__VA_ARGS__); \
if(address <= 0x040f'ffff) return rsp.status.access(__VA_ARGS__); \
if(address <= 0x041f'ffff) return rdp.access(__VA_ARGS__); \
if(address <= 0x042f'ffff) return rdp.io.access(__VA_ARGS__); \
if(address <= 0x043f'ffff) return mi.access(__VA_ARGS__); \
if(address <= 0x044f'ffff) return vi.access(__VA_ARGS__); \
if(address <= 0x045f'ffff) return ai.access(__VA_ARGS__); \
if(address <= 0x046f'ffff) return pi.access(__VA_ARGS__); \
if(address <= 0x047f'ffff) return ri.access(__VA_ARGS__); \
if(address <= 0x048f'ffff) return si.access(__VA_ARGS__); \
if(address <= 0x04ff'ffff) return unmapped; \
if(address <= 0x0500'03ff) return dd.c2s.access(__VA_ARGS__); \
if(address <= 0x0500'04ff) return dd.ds.access(__VA_ARGS__); \
if(address <= 0x0500'057f) return dd.access(__VA_ARGS__); \
if(address <= 0x0500'05bf) return dd.ms.access(__VA_ARGS__); \
if(address <= 0x05ff'ffff) return unmapped; \
if(address <= 0x063f'ffff) return dd.iplrom.access(__VA_ARGS__); \
if(address <= 0x0fff'ffff) return unmapped; \
if(address <= 0x1fbf'ffff) return cartridge.rom.access(__VA_ARGS__); \
if(address <= 0x1fc0'07bf) return pi.rom.access(__VA_ARGS__); \
if(address <= 0x1fc0'07ff) return pi.ram.access(__VA_ARGS__); \
return unmapped; \
#define unmapped 0
inline auto Bus::readByte(u32 address) -> u8 {
address &= 0x1fff'ffff;
if(address <= 0x007f'ffff) return rdram.ram.readByte(address);
if(address <= 0x03ef'ffff) return 0;
if(address <= 0x03ff'ffff) return transform(rdram.readIO(address));
if(address <= 0x0400'0fff) return rsp.dmem.readByte(address);
if(address <= 0x0400'1fff) return rsp.imem.readByte(address);
if(address <= 0x0403'ffff) return 0;
if(address <= 0x0407'ffff) return transform(rsp.readSCC(address));
if(address <= 0x040f'ffff) return transform(rsp.readIO(address));
if(address <= 0x041f'ffff) return transform(rdp.readSCC(address));
if(address <= 0x042f'ffff) return transform(rdp.readIO(address));
if(address <= 0x043f'ffff) return transform(mi.readIO(address));
if(address <= 0x044f'ffff) return transform(vi.readIO(address));
if(address <= 0x045f'ffff) return transform(ai.readIO(address));
if(address <= 0x046f'ffff) return transform(pi.readIO(address));
if(address <= 0x047f'ffff) return transform(ri.readIO(address));
if(address <= 0x048f'ffff) return transform(si.readIO(address));
if(address <= 0x0fff'ffff) return 0;
if(address <= 0x1fbf'ffff) return cartridge.rom.readByte(address);
if(address <= 0x1fc0'07bf) return pi.rom.readByte(address);
if(address <= 0x1fc0'07ff) return pi.ram.readByte(address);
return 0;
decode(0, readByte, address);
}
inline auto Bus::readHalf(u32 address) -> u16 {
static auto transform = [&](u32 data) -> u16 {
switch(address & 2) {
case 0: return data >> 16;
case 2: return data >> 0;
} unreachable;
};
address &= 0x1fff'fffe;
if(address <= 0x007f'ffff) return rdram.ram.readHalf(address);
if(address <= 0x03ef'ffff) return 0;
if(address <= 0x03ff'ffff) return transform(rdram.readIO(address));
if(address <= 0x0400'0fff) return rsp.dmem.readHalf(address);
if(address <= 0x0400'1fff) return rsp.imem.readHalf(address);
if(address <= 0x0403'ffff) return 0;
if(address <= 0x0407'ffff) return transform(rsp.readSCC(address));
if(address <= 0x040f'ffff) return transform(rsp.readIO(address));
if(address <= 0x041f'ffff) return transform(rdp.readSCC(address));
if(address <= 0x042f'ffff) return transform(rdp.readIO(address));
if(address <= 0x043f'ffff) return transform(mi.readIO(address));
if(address <= 0x044f'ffff) return transform(vi.readIO(address));
if(address <= 0x045f'ffff) return transform(ai.readIO(address));
if(address <= 0x046f'ffff) return transform(pi.readIO(address));
if(address <= 0x047f'ffff) return transform(ri.readIO(address));
if(address <= 0x048f'ffff) return transform(si.readIO(address));
if(address <= 0x0fff'ffff) return 0;
if(address <= 0x1fbf'ffff) return cartridge.rom.readHalf(address);
if(address <= 0x1fc0'07bf) return pi.rom.readHalf(address);
if(address <= 0x1fc0'07ff) return pi.ram.readHalf(address);
return 0;
decode(0, readHalf, address);
}
inline auto Bus::readWord(u32 address) -> u32 {
address &= 0x1fff'fffc;
if(address <= 0x007f'ffff) return rdram.ram.readWord(address);
if(address <= 0x03ef'ffff) return 0;
if(address <= 0x03ff'ffff) return rdram.readIO(address);
if(address <= 0x0400'0fff) return rsp.dmem.readWord(address);
if(address <= 0x0400'1fff) return rsp.imem.readWord(address);
if(address <= 0x0403'ffff) return 0;
if(address <= 0x0407'ffff) return rsp.readSCC(address);
if(address <= 0x040f'ffff) return rsp.readIO(address);
if(address <= 0x041f'ffff) return rdp.readSCC(address);
if(address <= 0x042f'ffff) return rdp.readIO(address);
if(address <= 0x043f'ffff) return mi.readIO(address);
if(address <= 0x044f'ffff) return vi.readIO(address);
if(address <= 0x045f'ffff) return ai.readIO(address);
if(address <= 0x046f'ffff) return pi.readIO(address);
if(address <= 0x047f'ffff) return ri.readIO(address);
if(address <= 0x048f'ffff) return si.readIO(address);
if(address <= 0x0fff'ffff) return 0;
if(address <= 0x1fbf'ffff) return cartridge.rom.readWord(address);
if(address <= 0x1fc0'07bf) return pi.rom.readWord(address);
if(address <= 0x1fc0'07ff) return pi.ram.readWord(address);
return 0;
decode(0, readWord, address);
}
inline auto Bus::readDouble(u32 address) -> u64 {
address &= 0x1fff'fff8;
if(address <= 0x007f'ffff) return rdram.ram.readDouble(address);
if(address <= 0x03ef'ffff) return 0;
if(address <= 0x03ff'ffff) { u64 data = rdram.readIO(address); return data << 32 | rdram.readIO(address + 4); }
if(address <= 0x0400'0fff) return rsp.dmem.readDouble(address);
if(address <= 0x0400'1fff) return rsp.imem.readDouble(address);
if(address <= 0x0403'ffff) return 0;
if(address <= 0x0407'ffff) { u64 data = rsp.readSCC(address); return data << 32 | rsp.readSCC (address + 4); }
if(address <= 0x040f'ffff) { u64 data = rsp.readIO(address); return data << 32 | rsp.readIO (address + 4); }
if(address <= 0x041f'ffff) { u64 data = rdp.readSCC(address); return data << 32 | rdp.readSCC (address + 4); }
if(address <= 0x042f'ffff) { u64 data = rdp.readIO(address); return data << 32 | rdp.readIO (address + 4); }
if(address <= 0x043f'ffff) { u64 data = mi.readIO(address); return data << 32 | mi.readIO (address + 4); }
if(address <= 0x044f'ffff) { u64 data = vi.readIO(address); return data << 32 | vi.readIO (address + 4); }
if(address <= 0x045f'ffff) { u64 data = ai.readIO(address); return data << 32 | ai.readIO (address + 4); }
if(address <= 0x046f'ffff) { u64 data = pi.readIO(address); return data << 32 | pi.readIO (address + 4); }
if(address <= 0x047f'ffff) { u64 data = ri.readIO(address); return data << 32 | ri.readIO (address + 4); }
if(address <= 0x048f'ffff) { u64 data = si.readIO(address); return data << 32 | si.readIO (address + 4); }
if(address <= 0x0fff'ffff) return 0;
if(address <= 0x1fbf'ffff) return cartridge.rom.readDouble(address);
if(address <= 0x1fc0'07bf) return pi.rom.readDouble(address);
if(address <= 0x1fc0'07ff) return pi.ram.readDouble(address);
return 0;
decode(0, readDouble, address);
}
inline auto Bus::writeByte(u32 address, u8 data) -> void {
static auto transform = [&](u32 data) -> u32 {
switch(address & 3) {
case 0: return data << 24;
case 1: return data << 16;
case 2: return data << 8;
case 3: return data << 0;
} unreachable;
};
#undef unmapped
#define unmapped
inline auto Bus::writeByte(u32 address, u8 data) -> void {
address &= 0x1fff'ffff;
if(address <= 0x007f'ffff) return rdram.ram.writeByte(address, data);
if(address <= 0x03ef'ffff) return;
if(address <= 0x03ff'ffff) return rdram.writeIO(address, transform(data));
if(address <= 0x0400'0fff) return rsp.dmem.writeByte(address, data);
if(address <= 0x0400'1fff) return rsp.imem.writeByte(address, data);
if(address <= 0x0403'ffff) return;
if(address <= 0x0407'ffff) return rsp.writeSCC(address, transform(data));
if(address <= 0x040f'ffff) return rsp.writeIO(address, transform(data));
if(address <= 0x041f'ffff) return rdp.writeSCC(address, transform(data));
if(address <= 0x042f'ffff) return rdp.writeIO(address, transform(data));
if(address <= 0x043f'ffff) return mi.writeIO(address, transform(data));
if(address <= 0x044f'ffff) return vi.writeIO(address, transform(data));
if(address <= 0x045f'ffff) return ai.writeIO(address, transform(data));
if(address <= 0x046f'ffff) return pi.writeIO(address, transform(data));
if(address <= 0x047f'ffff) return ri.writeIO(address, transform(data));
if(address <= 0x048f'ffff) return si.writeIO(address, transform(data));
if(address <= 0x0fff'ffff) return;
if(address <= 0x1fbf'ffff) return;
if(address <= 0x1fc0'07bf) return;
if(address <= 0x1fc0'07ff) return pi.ram.writeByte(address, data);
return;
cpu.recompiler.invalidate(address);
decode(1, writeByte, address, data);
}
inline auto Bus::writeHalf(u32 address, u16 data) -> void {
static auto transform = [&](u32 data) -> u32 {
switch(address & 2) {
case 0: return data << 16;
case 2: return data << 0;
} unreachable;
};
address &= 0x1fff'fffe;
if(address <= 0x007f'ffff) return rdram.ram.writeHalf(address, data);
if(address <= 0x03ef'ffff) return;
if(address <= 0x03ff'ffff) return rdram.writeIO(address, transform(data));
if(address <= 0x0400'0fff) return rsp.dmem.writeHalf(address, data);
if(address <= 0x0400'1fff) return rsp.imem.writeHalf(address, data);
if(address <= 0x0403'ffff) return;
if(address <= 0x0407'ffff) return rsp.writeSCC(address, transform(data));
if(address <= 0x040f'ffff) return rsp.writeIO(address, transform(data));
if(address <= 0x041f'ffff) return rdp.writeSCC(address, transform(data));
if(address <= 0x042f'ffff) return rdp.writeIO(address, transform(data));
if(address <= 0x043f'ffff) return mi.writeIO(address, transform(data));
if(address <= 0x044f'ffff) return vi.writeIO(address, transform(data));
if(address <= 0x045f'ffff) return ai.writeIO(address, transform(data));
if(address <= 0x046f'ffff) return pi.writeIO(address, transform(data));
if(address <= 0x047f'ffff) return ri.writeIO(address, transform(data));
if(address <= 0x048f'ffff) return si.writeIO(address, transform(data));
if(address <= 0x0fff'ffff) return;
if(address <= 0x1fbf'ffff) return;
if(address <= 0x1fc0'07bf) return;
if(address <= 0x1fc0'07ff) return pi.ram.writeHalf(address, data);
return;
cpu.recompiler.invalidate(address);
decode(1, writeHalf, address, data);
}
inline auto Bus::writeWord(u32 address, u32 data) -> void {
address &= 0x1fff'fffc;
if(address <= 0x007f'ffff) return rdram.ram.writeWord(address, data);
if(address <= 0x03ef'ffff) return;
if(address <= 0x03ff'ffff) return rdram.writeIO(address, data);
if(address <= 0x0400'0fff) return rsp.dmem.writeWord(address, data);
if(address <= 0x0400'1fff) return rsp.imem.writeWord(address, data);
if(address <= 0x0403'ffff) return;
if(address <= 0x0407'ffff) return rsp.writeSCC(address, data);
if(address <= 0x040f'ffff) return rsp.writeIO(address, data);
if(address <= 0x041f'ffff) return rdp.writeSCC(address, data);
if(address <= 0x042f'ffff) return rdp.writeIO(address, data);
if(address <= 0x043f'ffff) return mi.writeIO(address, data);
if(address <= 0x044f'ffff) return vi.writeIO(address, data);
if(address <= 0x045f'ffff) return ai.writeIO(address, data);
if(address <= 0x046f'ffff) return pi.writeIO(address, data);
if(address <= 0x047f'ffff) return ri.writeIO(address, data);
if(address <= 0x048f'ffff) return si.writeIO(address, data);
if(address <= 0x0fff'ffff) return;
if(address <= 0x1fbf'ffff) return;
if(address <= 0x1fc0'07bf) return;
if(address <= 0x1fc0'07ff) return pi.ram.writeWord(address, data);
return;
cpu.recompiler.invalidate(address);
decode(1, writeWord, address, data);
}
inline auto Bus::writeDouble(u32 address, u64 data) -> void {
address &= 0x1fff'fff8;
if(address <= 0x007f'ffff) return rdram.ram.writeDouble(address, data);
if(address <= 0x03ef'ffff) return;
if(address <= 0x03ff'ffff) { rdram.writeIO(address, data >> 32); return rdram.writeIO(address + 4, data); }
if(address <= 0x0400'0fff) return rsp.dmem.writeDouble(address, data);
if(address <= 0x0400'1fff) return rsp.imem.writeDouble(address, data);
if(address <= 0x0403'ffff) return;
if(address <= 0x0407'ffff) { rsp.writeSCC (address, data >> 32); return rsp.writeSCC (address + 4, data); }
if(address <= 0x040f'ffff) { rsp.writeIO (address, data >> 32); return rsp.writeIO (address + 4, data); }
if(address <= 0x041f'ffff) { rdp.writeSCC (address, data >> 32); return rdp.writeSCC (address + 4, data); }
if(address <= 0x042f'ffff) { rdp.writeIO (address, data >> 32); return rdp.writeIO (address + 4, data); }
if(address <= 0x043f'ffff) { mi.writeIO (address, data >> 32); return mi.writeIO (address + 4, data); }
if(address <= 0x044f'ffff) { vi.writeIO (address, data >> 32); return vi.writeIO (address + 4, data); }
if(address <= 0x045f'ffff) { ai.writeIO (address, data >> 32); return ai.writeIO (address + 4, data); }
if(address <= 0x046f'ffff) { pi.writeIO (address, data >> 32); return pi.writeIO (address + 4, data); }
if(address <= 0x047f'ffff) { ri.writeIO (address, data >> 32); return ri.writeIO (address + 4, data); }
if(address <= 0x048f'ffff) { si.writeIO (address, data >> 32); return si.writeIO (address + 4, data); }
if(address <= 0x0fff'ffff) return;
if(address <= 0x1fbf'ffff) return;
if(address <= 0x1fc0'07bf) return;
if(address <= 0x1fc0'07ff) return pi.ram.writeDouble(address, data);
return;
cpu.recompiler.invalidate(address + 0);
cpu.recompiler.invalidate(address + 4);
decode(2, writeDouble, address, data);
}
#undef unmapped
#undef decode
+124 -21
View File
@@ -1,13 +1,6 @@
//the N64 is configured for big-endian mode.
//given the most common memory accesses are words,
//optimize accesses by special-casing bytes anf halves instead.
struct Memory {
auto bytes() const -> u32 { return size >> 0; }
auto halves() const -> u32 { return size >> 1; }
auto words() const -> u32 { return size >> 2; }
auto doubles() const -> u32 { return size >> 3; }
auto quads() const -> u32 { return size >> 4; }
namespace Memory {
struct Readable {
auto reset() -> void {
delete[] data;
data = nullptr;
@@ -31,14 +24,84 @@ struct Memory {
}
auto fill(u32 value = 0) -> void {
for(uint address = 0; address < size; address += 4) {
for(u32 address = 0; address < size; address += 4) {
*(u32*)&data[address & maskWord] = bswap32(value);
}
}
auto load(Shared::File fp) -> void {
for(u32 address = 0; address < min(size, fp->size()); address += 4) {
*(u32*)&data[address & maskWord] = bswap32(fp->readm(4));
}
}
//N64 CPU requires aligned memory accesses
auto readByte(u32 address) -> u8 { return *(u8*)&data[address & maskByte]; }
auto readHalf(u32 address) -> u16 { return bswap16(*(u16*)&data[address & maskHalf]); }
auto readWord(u32 address) -> u32 { return bswap32(*(u32*)&data[address & maskWord]); }
auto readDouble(u32 address) -> u64 { return bswap64(*(u64*)&data[address & maskDouble]); }
auto readQuad(u32 address) -> u128 { return bswap128(*(u128*)&data[address & maskQuad]); }
auto writeByte(u32 address, u8 value) -> void {}
auto writeHalf(u32 address, u16 value) -> void {}
auto writeWord(u32 address, u32 value) -> void {}
auto writeDouble(u32 address, u64 value) -> void {}
auto writeQuad(u32 address, u128 value) -> void {}
//N64 RSP allows unaligned memory accesses in certain cases
auto readHalfUnaligned(u32 address) -> u16 { return bswap16(*(u16*)&data[address & maskByte]); }
auto readWordUnaligned(u32 address) -> u32 { return bswap32(*(u32*)&data[address & maskByte]); }
auto readDoubleUnaligned(u32 address) -> u64 { return bswap64(*(u64*)&data[address & maskByte]); }
auto readQuadUnaligned(u32 address) -> u128 { return bswap128(*(u128*)&data[address & maskByte]); }
auto writeHalfUnaligned(u32 address, u16 value) -> void {}
auto writeWordUnaligned(u32 address, u32 value) -> void {}
auto writeDoubleUnaligned(u32 address, u64 value) -> void {}
auto writeQuadUnaligned(u32 address, u128 value) -> void {}
//private:
u8* data = nullptr;
u32 size = 0;
u32 maskByte = 0;
u32 maskHalf = 0;
u32 maskWord = 0;
u32 maskDouble = 0;
u32 maskQuad = 0;
};
struct Writable {
auto reset() -> void {
delete[] data;
data = nullptr;
size = 0;
maskByte = 0;
maskHalf = 0;
maskWord = 0;
maskDouble = 0;
maskQuad = 0;
}
auto allocate(u32 capacity) -> void {
size = capacity & ~7;
u32 mask = bit::round(size) - 1;
maskByte = mask & ~0;
maskHalf = mask & ~1;
maskWord = mask & ~3;
maskDouble = mask & ~7;
maskQuad = mask & ~15;
data = new u8[mask + 1];
}
auto fill(u32 value = 0) -> void {
for(u32 address = 0; address < size; address += 4) {
*(u32*)&data[address & maskWord] = bswap32(value);
writeWord(address, value);
}
}
auto load(Shared::File fp) -> void {
for(uint address = 0; address < min(size, fp->size()); address += 4) {
writeWord(address, fp->readm(4));
for(u32 address = 0; address < min(size, fp->size()); address += 4) {
*(u32*)&data[address & maskWord] = bswap32(fp->readm(4));
}
}
@@ -76,13 +139,57 @@ struct Memory {
u32 maskQuad = 0;
};
//00000000-7fffffff kuseg
//80000000-9fffffff kseg0
//a0000000-bfffffff kseg1
//c0000000-dfffffff ksseg
//e0000000-ffffffff kseg3
template<typename T>
struct IO {
auto readByte(u32 address) -> u8 {
auto data = ((T*)this)->readWord(address);
switch(address & 3) {
case 0: return data >> 24;
case 1: return data >> 16;
case 2: return data >> 8;
case 3: return data >> 0;
} unreachable;
}
auto readHalf(u32 address) -> u16 {
auto data = ((T*)this)->readWord(address);
switch(address & 2) {
case 0: return data >> 16;
case 2: return data >> 0;
} unreachable;
}
auto readDouble(u32 address) -> u64 {
u64 data = ((T*)this)->readWord(address);
return data << 32 | ((T*)this)->readWord(address + 4);
}
auto writeByte(u32 address, u8 data) -> void {
switch(address & 3) {
case 0: return ((T*)this)->writeWord(address, data << 24);
case 1: return ((T*)this)->writeWord(address, data << 16);
case 2: return ((T*)this)->writeWord(address, data << 8);
case 3: return ((T*)this)->writeWord(address, data << 0);
} unreachable;
}
auto writeHalf(u32 address, u16 data) -> void {
switch(address & 2) {
case 0: return ((T*)this)->writeWord(address, data << 16);
case 2: return ((T*)this)->writeWord(address, data << 0);
} unreachable;
}
auto writeDouble(u32 address, u64 data) -> void {
((T*)this)->writeWord(address + 0, data >> 32);
((T*)this)->writeWord(address + 4, data >> 0);
}
};
}
struct Bus {
//bus.hpp
auto readByte(u32 address) -> u8;
auto readHalf(u32 address) -> u16;
auto readWord(u32 address) -> u32;
@@ -91,10 +198,6 @@ struct Bus {
auto writeHalf(u32 address, u16 data) -> void;
auto writeWord(u32 address, u32 data) -> void;
auto writeDouble(u32 address, u64 data) -> void;
//bus.cpp
auto load(Node::Object) -> void;
auto unload() -> void;
};
extern Bus bus;
+3 -2
View File
@@ -5,7 +5,7 @@ static const vector<string> registerNames = {
"MI_INTR_MASK",
};
auto MI::readIO(u32 address) -> u32 {
auto MI::readWord(u32 address) -> u32 {
address = (address & 0xfffff) >> 2;
uint32 data;
@@ -47,8 +47,9 @@ auto MI::readIO(u32 address) -> u32 {
return data;
}
auto MI::writeIO(u32 address, uint32 data) -> void {
auto MI::writeWord(u32 address, u32 data_) -> void {
address = (address & 0xfffff) >> 2;
uint32 data = data_;
if(address == 0) {
//MI_INIT_MODE
+3 -3
View File
@@ -1,6 +1,6 @@
//MIPS Interface
struct MI {
struct MI : Memory::IO<MI> {
Node::Component node;
struct Debugger {
@@ -27,8 +27,8 @@ struct MI {
auto power() -> void;
//io.cpp
auto readIO(u32 address) -> u32;
auto writeIO(u32 address, uint32 data) -> void;
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
+16 -14
View File
@@ -2,8 +2,10 @@
//started: 2020-04-28
#include <ares/ares.hpp>
#include <nall/hashset.hpp>
#include <nall/recompiler/amd64/amd64.hpp>
#include <nmmintrin.h>
using s128 = __m128i;
using v128 = __m128i;
namespace ares::Nintendo64 {
struct Accuracy {
@@ -11,9 +13,21 @@ namespace ares::Nintendo64 {
static constexpr bool Reference = 0;
struct CPU {
//0 = dynamic recompiler; 1 = interpreter
static constexpr bool Interpreter = 0 | Reference;
//exceptions when the CPU accesses unaligned memory addresses
static constexpr bool AddressErrors = 0 | Reference;
};
struct RSP {
//0 = dynamic recompiler; 1 = interpreter
static constexpr bool Interpreter = 0 | Reference;
//VU instructions
static constexpr bool SISD = 0 | Reference;
static constexpr bool SIMD = SISD == 0;
};
};
struct Region {
@@ -33,23 +47,11 @@ namespace ares::Nintendo64 {
i64 clock;
};
template<uint lo, uint hi, typename T>
struct bitref {
static constexpr T mask = ~0ull >> 64 - (hi - lo + 1) << lo;
bitref(T& data) : data(data) {}
operator T() const { return (data & mask) >> lo; }
auto& operator=(T value) { return data = data & ~mask | value << lo & mask, *this; }
auto& operator=(const bitref& value) { return operator=((T)value); }
T& data;
};
template<uint lo, typename T> auto bit(T& value) { return bitref<lo, lo, T>(value); }
template<uint lo, uint hi, typename T> auto bit(T& value) { return bitref<lo, hi, T>(value); }
#include <n64/memory/memory.hpp>
#include <n64/system/system.hpp>
#include <n64/cartridge/cartridge.hpp>
#include <n64/controller/controller.hpp>
#include <n64/dd/dd.hpp>
#include <n64/mi/mi.hpp>
#include <n64/vi/vi.hpp>
#include <n64/ai/ai.hpp>
+5 -4
View File
@@ -14,7 +14,7 @@ static const vector<string> registerNames = {
"PI_BSD_DOM2_RLS",
};
auto PI::readIO(u32 address) -> u32 {
auto PI::readWord(u32 address) -> u32 {
address = (address & 0xfffff) >> 2;
uint32 data;
@@ -92,8 +92,9 @@ auto PI::readIO(u32 address) -> u32 {
return data;
}
auto PI::writeIO(u32 address, uint32 data) -> void {
auto PI::writeWord(u32 address, u32 data_) -> void {
address = (address & 0xfffff) >> 2;
uint32 data = data_;
//only PI_STATUS can be written while PI is busy
if(address != 4 && (io.dmaBusy || io.ioBusy)) {
@@ -115,7 +116,7 @@ auto PI::writeIO(u32 address, uint32 data) -> void {
//PI_READ_LENGTH
io.readLength = (uint24(data) | 7) + 1;
for(u32 address = 0; address < io.readLength; address += 2) {
u16 data = rdram.ram.readHalf(io.dramAddress + address);
u16 data = bus.readHalf(io.dramAddress + address);
bus.writeHalf(io.pbusAddress + address, data);
}
io.interrupt = 1;
@@ -127,7 +128,7 @@ auto PI::writeIO(u32 address, uint32 data) -> void {
io.writeLength = (uint24(data) | 7) + 1;
for(u32 address = 0; address < io.writeLength; address += 2) {
u16 data = bus.readHalf(io.pbusAddress + address);
rdram.ram.writeHalf(io.dramAddress + address, data);
bus.writeHalf(io.dramAddress + address, data);
}
io.interrupt = 1;
mi.raise(MI::IRQ::PI);
+1 -3
View File
@@ -32,9 +32,7 @@ auto PI::power() -> void {
string iplrom = cartridge.region() == "NTSC" ? "pif.ntsc.rom" : "pif.pal.rom";
iplrom = "pif.rom";
if(auto fp = platform->open(node, iplrom, File::Read, File::Required)) {
for(u32 offset = 0; offset < 0x7c0; offset++) {
rom.writeByte(offset, fp->read());
}
rom.load(fp);
}
//write CIC seeds into PIF RAM so that cartridge checksum function passes
+5 -5
View File
@@ -1,9 +1,9 @@
//Peripheral Interface
struct PI {
struct PI : Memory::IO<PI> {
Node::Component node;
Memory rom;
Memory ram;
Memory::Readable rom;
Memory::Writable ram;
struct Debugger {
//debugger.cpp
@@ -25,8 +25,8 @@ struct PI {
auto power() -> void;
//io.cpp
auto readIO(u32 address) -> u32;
auto writeIO(u32 address, uint32 data) -> void;
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
-127
View File
@@ -1,127 +0,0 @@
static const vector<string> registerNamesSCC = {
"DPC_START",
"DPC_END",
"DPC_CURRENT",
"DPC_STATUS",
"DPC_CLOCK",
"DPC_BUSY",
"DPC_PIPE_BUSY",
"DPC_TMEM_BUSY",
};
auto RDP::readSCC(u32 address) -> u32 {
address = (address & 0xfffff) >> 2;
uint32 data;
if(address == 0) {
//DPC_START
data.bit(0,23) = command.start;
}
if(address == 1) {
//DPC_END
data.bit(0,23) = command.end;
}
if(address == 2) {
//DPC_CURRENT
data.bit(0,23) = command.current;
}
if(address == 3) {
//DPC_STATUS
data.bit( 0) = command.source;
data.bit( 1) = command.freeze;
data.bit( 2) = command.flush;
data.bit( 3) = 0; //start gclk?
data.bit( 4) = command.tmemBusy > 0;
data.bit( 5) = command.pipeBusy > 0;
data.bit( 6) = command.bufferBusy > 0;
data.bit( 7) = command.ready;
data.bit( 8) = 0; //DMA busy
data.bit( 9) = 0; //end valid
data.bit(10) = 0; //start valid
}
if(address == 4) {
//DPC_CLOCK
data.bit(0,23) = command.clock;
}
if(address == 5) {
//DPC_BUSY
data.bit(0,23) = command.bufferBusy;
}
if(address == 6) {
//DPC_PIPE_BUSY
data.bit(0,23) = command.pipeBusy;
}
if(data == 7) {
//DPC_TMEM_BUSY
data.bit(0,23) = command.tmemBusy;
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNamesSCC(address, "DPC_UNKNOWN"), " => ", hex(data, 8L)});
}
return data;
}
auto RDP::writeSCC(u32 address, uint32 data) -> void {
address = (address & 0xfffff) >> 2;
if(address == 0) {
//DPC_START
command.start = data.bit(0,23) & ~7;
command.current = command.start;
}
if(address == 1) {
//DPC_END
command.end = data.bit(0,23) & ~7;
command.freeze = 0;
render();
command.current = command.end;
command.ready = 1;
}
if(address == 2) {
//DPC_CURRENT (read-only)
}
if(address == 3) {
//DPC_STATUS
if(data.bit(0)) command.source = 0;
if(data.bit(1)) command.source = 1;
if(data.bit(2)) command.freeze = 0;
//if(data.bit(3)) command.freeze = 1;
if(data.bit(4)) command.flush = 0;
if(data.bit(5)) command.flush = 1;
if(data.bit(6)) command.tmemBusy = 0;
if(data.bit(7)) command.pipeBusy = 0;
if(data.bit(8)) command.bufferBusy = 0;
if(data.bit(9)) command.clock = 0;
}
if(address == 4) {
//DPC_CLOCK (read-only)
}
if(address == 5) {
//DPC_BUSY (read-only)
}
if(address == 6) {
//DPC_PIPE_BUSY (read-only)
}
if(address == 7) {
//DPC_TMEM_BUSY (read-only)
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNamesSCC(address, "DPC_UNKNOWN"), " <= ", hex(data, 8L)});
}
}
+152 -20
View File
@@ -1,69 +1,201 @@
static const vector<string> registerNames = {
static const vector<string> registerNamesSCC = {
"DPC_START",
"DPC_END",
"DPC_CURRENT",
"DPC_STATUS",
"DPC_CLOCK",
"DPC_BUSY",
"DPC_PIPE_BUSY",
"DPC_TMEM_BUSY",
};
auto RDP::readWord(u32 address) -> u32 {
address = (address & 0xfffff) >> 2;
uint32 data;
if(address == 0) {
//DPC_START
data.bit(0,23) = command.start;
}
if(address == 1) {
//DPC_END
data.bit(0,23) = command.end;
}
if(address == 2) {
//DPC_CURRENT
data.bit(0,23) = command.current;
}
if(address == 3) {
//DPC_STATUS
data.bit( 0) = command.source;
data.bit( 1) = command.freeze;
data.bit( 2) = command.flush;
data.bit( 3) = 0; //start gclk?
data.bit( 4) = command.tmemBusy > 0;
data.bit( 5) = command.pipeBusy > 0;
data.bit( 6) = command.bufferBusy > 0;
data.bit( 7) = command.ready;
data.bit( 8) = 0; //DMA busy
data.bit( 9) = 0; //end valid
data.bit(10) = 0; //start valid
}
if(address == 4) {
//DPC_CLOCK
data.bit(0,23) = command.clock;
}
if(address == 5) {
//DPC_BUSY
data.bit(0,23) = command.bufferBusy;
}
if(address == 6) {
//DPC_PIPE_BUSY
data.bit(0,23) = command.pipeBusy;
}
if(data == 7) {
//DPC_TMEM_BUSY
data.bit(0,23) = command.tmemBusy;
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNamesSCC(address, "DPC_UNKNOWN"), " => ", hex(data, 8L)});
}
return data;
}
auto RDP::writeWord(u32 address, u32 data_) -> void {
address = (address & 0xfffff) >> 2;
uint32 data = data_;
if(address == 0) {
//DPC_START
command.start = data.bit(0,23) & ~7;
command.current = command.start;
}
if(address == 1) {
//DPC_END
command.end = data.bit(0,23) & ~7;
if(command.end > command.current) {
command.freeze = 0;
render();
command.current = command.end;
command.ready = 1;
}
}
if(address == 2) {
//DPC_CURRENT (read-only)
}
if(address == 3) {
//DPC_STATUS
if(data.bit(0)) command.source = 0;
if(data.bit(1)) command.source = 1;
if(data.bit(2)) command.freeze = 0;
//if(data.bit(3)) command.freeze = 1;
if(data.bit(4)) command.flush = 0;
if(data.bit(5)) command.flush = 1;
if(data.bit(6)) command.tmemBusy = 0;
if(data.bit(7)) command.pipeBusy = 0;
if(data.bit(8)) command.bufferBusy = 0;
if(data.bit(9)) command.clock = 0;
}
if(address == 4) {
//DPC_CLOCK (read-only)
}
if(address == 5) {
//DPC_BUSY (read-only)
}
if(address == 6) {
//DPC_PIPE_BUSY (read-only)
}
if(address == 7) {
//DPC_TMEM_BUSY (read-only)
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNamesSCC(address, "DPC_UNKNOWN"), " <= ", hex(data, 8L)});
}
}
static const vector<string> registerNamesIO = {
"DPS_TBIST",
"DPS_TEST_MODE",
"DPS_BUFTEST_ADDR",
"DPS_BUFTEST_DATA",
};
auto RDP::readIO(u32 address) -> u32 {
auto RDP::IO::readWord(u32 address) -> u32 {
address = (address & 0xfffff) >> 2;
uint32 data;
if(address == 0) {
//DPS_TBIST
data.bit(0) = io.bist.check;
data.bit(1) = io.bist.go;
data.bit(2) = io.bist.done;
data.bit(3,10) = io.bist.fail;
data.bit(0) = bist.check;
data.bit(1) = bist.go;
data.bit(2) = bist.done;
data.bit(3,10) = bist.fail;
}
if(address == 1) {
//DPS_TEST_MODE
data.bit(0) = io.test.enable;
data.bit(0) = test.enable;
}
if(address == 2) {
//DPS_BUFTEST_ADDR
data.bit(0,6) = io.test.address;
data.bit(0,6) = test.address;
}
if(address == 3) {
//DPS_BUFTEST_DATA
data.bit(0,31) = io.test.data;
data.bit(0,31) = test.data;
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNames(address, "DPS_UNKNOWN"), " => ", hex(data, 8L)});
if(self.debugger.tracer.io->enabled()) {
self.debugger.io({registerNamesIO(address, "DPS_UNKNOWN"), " => ", hex(data, 8L)});
}
return data;
}
auto RDP::writeIO(u32 address, uint32 data) -> void {
auto RDP::IO::writeWord(u32 address, u32 data_) -> void {
address = (address & 0xfffff) >> 2;
uint32 data = data_;
if(address == 0) {
//DPS_TBIST
io.bist.check = data.bit(0);
io.bist.go = data.bit(1);
if(data.bit(2)) io.bist.done = 0;
bist.check = data.bit(0);
bist.go = data.bit(1);
if(data.bit(2)) bist.done = 0;
}
if(address == 1) {
//DPS_TEST_MODE
io.test.enable = data.bit(0);
test.enable = data.bit(0);
}
if(address == 2) {
//DPS_BUFTEST_ADDR
io.test.address = data.bit(0,6);
test.address = data.bit(0,6);
}
if(address == 3) {
//DPS_BUFTEST_DATA
io.test.data = data.bit(0,31);
test.data = data.bit(0,31);
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNames(address, "DPS_UNKNOWN"), " <= ", hex(data, 8L)});
if(self.debugger.tracer.io->enabled()) {
self.debugger.io({registerNamesIO(address, "DPS_UNKNOWN"), " <= ", hex(data, 8L)});
}
}
+2 -2
View File
@@ -5,7 +5,6 @@ namespace ares::Nintendo64 {
RDP rdp;
#include "render.cpp"
#include "io.cpp"
#include "io-scc.cpp"
#include "debugger.cpp"
#include "serialization.cpp"
@@ -31,7 +30,8 @@ auto RDP::power() -> void {
Thread::reset();
command = {};
set = {};
io = {};
io.bist = {};
io.test = {};
}
}
+267 -21
View File
@@ -1,6 +1,6 @@
//Reality Display Processor
struct RDP : Thread {
struct RDP : Thread, Memory::IO<RDP> {
Node::Component node;
struct Debugger {
@@ -27,30 +27,45 @@ struct RDP : Thread {
auto render() -> void;
auto noOperation() -> void;
auto invalidOperation() -> void;
auto unshadedTriangle() -> void;
auto unshadedZbufferTriangle() -> void;
auto textureTriangle() -> void;
auto textureZbufferTriangle() -> void;
auto shadedTriangle() -> void;
auto shadedZbufferTriangle() -> void;
auto shadedTextureTriangle() -> void;
auto shadedTextureZbufferTriangle() -> void;
auto syncLoad() -> void;
auto syncPipe() -> void;
auto syncTile() -> void;
auto syncFull() -> void;
auto textureRectangle(
uint12 xl, uint12 yl, uint3 tile, uint12 xh, uint12 yh,
uint16 s, uint16 t, uint16 dsdx, uint16 dsdy
) -> void;
auto textureRectangleFlip(
uint12 xl, uint12 yl, uint3 tile, uint12 xh, uint12 yh,
uint16 s, uint16 t, uint16 dsdx, uint16 dsdy
) -> void;
auto fillRectangle(uint12 xl, uint12 yl, uint12 xh, uint12 yh) -> void;
auto setFillColor(uint32 color) -> void;
auto setTextureImage(uint3 format, uint2 size, uint10 width, uint26 dramAddress) -> void;
auto setColorImage(uint3 format, uint2 size, uint10 width, uint26 dramAddress) -> void;
auto setKeyGB() -> void;
auto setKeyR() -> void;
auto setConvert() -> void;
auto setScissor() -> void;
auto setPrimitiveDepth() -> void;
auto setOtherModes() -> void;
auto textureRectangle() -> void;
auto textureRectangleFlip() -> void;
auto loadTLUT() -> void;
auto setTileSize() -> void;
auto loadBlock() -> void;
auto loadTile() -> void;
auto setTile() -> void;
auto fillRectangle() -> void;
auto setFillColor() -> void;
auto setFogColor() -> void;
auto setBlendColor() -> void;
auto setPrimitiveColor() -> void;
auto setEnvironmentColor() -> void;
auto setCombineMode() -> void;
auto setTextureImage() -> void;
auto setMaskImage() -> void;
auto setColorImage() -> void;
//io.cpp
auto readIO(u32 address) -> u32;
auto writeIO(u32 address, uint32 data) -> void;
//io-scc.cpp
auto readSCC(u32 address) -> u32;
auto writeSCC(u32 address, uint32 data) -> void;
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
@@ -69,6 +84,194 @@ struct RDP : Thread {
uint1 ready = 1;
} command;
struct Point {
uint16 i; //integer
uint16 f; //fraction
};
struct Edge {
uint1 lmajor;
uint3 level;
uint3 tile;
struct Y {
uint14 hi;
uint14 md;
uint14 lo;
} y;
struct X {
struct {
Point c; //coordinate
Point s; //inverse slope
} hi, md, lo;
} x;
} edge;
struct Shade {
struct Channel {
Point c; //color
Point x; //change per X coordinate
Point y; //change per Y coordinate
Point e; //change along edge
} r, g, b, a;
} shade;
struct Texture {
struct {
Point c; //coordinate
Point x; //change per X coordinate
Point y; //change per Y coordinate
Point e; //change along edge
} s, t, w;
} texture;
struct Zbuffer {
Point d; //inverse depth
Point x; //change per X coordinate
Point y; //change per Y coordinate
Point e; //change along edge
} zbuffer;
struct TextureRectangle {
uint3 tile;
struct {
uint12 hi;
uint12 lo;
} x, y;
Point s;
Point t;
} rectangle;
struct OtherModes {
uint1 atomicPrimitive;
uint1 reserved1;
uint2 cycleType;
uint1 perspective;
uint1 detailTexture;
uint1 sharpenTexture;
uint1 lodTexture;
uint1 tlut;
uint1 tlutType;
uint1 sampleType;
uint1 midTexel;
uint1 bilerp[2];
uint1 convertOne;
uint1 colorKey;
uint2 colorDitherMode;
uint2 alphaDitherMode;
uint4 reserved2;
uint2 blend1a[2];
uint2 blend1b[2];
uint2 blend2a[2];
uint2 blend2b[2];
uint1 reserved3;
uint1 forceBlend;
uint1 alphaCoverage;
uint1 coverageXalpha;
uint2 zMode;
uint2 coverageMode;
uint1 colorOnCoverage;
uint1 imageRead;
uint1 zUpdate;
uint1 zCompare;
uint1 antialias;
uint1 zSource;
uint1 ditherAlpha;
uint1 alphaCompare;
} other;
struct FogColor {
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha;
} fog;
struct Blend {
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha;
} blend;
struct PrimitiveColor {
uint5 minimum;
uint8 fraction;
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha;
} primitive;
struct EnvironmentColor {
uint8 red;
uint8 green;
uint8 blue;
uint8 alpha;
} environment;
struct CombineMode {
struct MUL {
uint5 color[2];
uint3 alpha[2];
} mul;
struct ADD {
uint3 color[2];
uint3 alpha[2];
} add;
struct SUB {
uint4 color[2];
uint3 alpha[2];
} sba, sbb;
} combine;
struct TLUT {
uint3 index;
struct {
uint12 lo;
uint12 hi;
} s, t;
} tlut;
struct Load {
struct Block {
uint3 index;
struct {
uint12 lo;
uint12 hi;
} s, t;
} block;
struct Tile {
uint3 index;
struct {
uint12 lo;
uint12 hi;
} s, t;
} tile;
} load_;
struct TileSize {
uint3 index;
struct {
uint12 lo;
uint12 hi;
} s, t;
} tileSize;
struct Tile {
uint3 format;
uint2 size;
uint9 line;
uint9 address;
uint3 index;
uint4 palette;
struct {
uint1 clamp;
uint1 mirror;
uint4 mask;
uint4 shift;
} s, t;
} tile;
struct Set {
struct Fill {
uint32 color = 0;
@@ -79,6 +282,9 @@ struct RDP : Thread {
uint10 width = 0;
uint26 dramAddress = 0;
} texture;
struct Mask {
uint26 dramAddress = 0;
} mask;
struct Color {
uint3 format = 0;
uint2 size = 0;
@@ -87,7 +293,47 @@ struct RDP : Thread {
} color;
} set;
struct IO {
struct PrimitiveDepth {
uint16 z;
uint16 deltaZ;
} primitiveDepth;
struct Scissor {
uint1 field;
uint1 odd;
struct {
uint12 lo;
uint12 hi;
} x, y;
} scissor;
struct Convert {
uint9 k[6];
} convert;
struct Key {
struct {
uint12 width;
uint8 center;
uint8 scale;
} r, g, b;
} key;
struct FillRectangle {
struct {
uint12 lo;
uint12 hi;
} x, y;
} fillRectangle_;
struct IO : Memory::IO<IO> {
RDP& self;
IO(RDP& self) : self(self) {}
//io.cpp
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
struct BIST {
uint1 check = 0;
uint1 go = 0;
@@ -99,7 +345,7 @@ struct RDP : Thread {
uint7 address = 0;
uint32 data = 0;
} test;
} io;
} io{*this};
};
extern RDP rdp;
+433 -123
View File
@@ -46,12 +46,141 @@ static const vector<string> commandNames = {
auto RDP::render() -> void {
auto& memory = !command.source ? rdram.ram : rsp.dmem;
auto fetch = [&]() -> u64 {
u64 op = memory.readDoubleUnaligned(command.current);
command.current += 8;
return op;
};
auto fetchEdge = [&](u64 op) {
edge.lmajor = uint1(op >> 55);
edge.level = uint3(op >> 51);
edge.tile = uint3(op >> 48);
edge.y.lo = uint14(op >> 32);
edge.y.md = uint14(op >> 16);
edge.y.hi = uint14(op >> 0);
op = fetch();
edge.x.lo.c.i = uint16(op >> 48);
edge.x.lo.c.f = uint16(op >> 32);
edge.x.lo.s.i = uint16(op >> 16);
edge.x.lo.s.f = uint16(op >> 0);
op = fetch();
edge.x.hi.c.i = uint16(op >> 48);
edge.x.hi.c.f = uint16(op >> 32);
edge.x.hi.s.i = uint16(op >> 16);
edge.x.hi.s.f = uint16(op >> 0);
op = fetch();
edge.x.md.c.i = uint16(op >> 48);
edge.x.md.c.f = uint16(op >> 32);
edge.x.md.s.i = uint16(op >> 16);
edge.x.md.s.f = uint16(op >> 0);
};
auto fetchShade = [&](u64 op) {
op = fetch();
shade.r.c.i = uint16(op >> 48);
shade.g.c.i = uint16(op >> 32);
shade.b.c.i = uint16(op >> 16);
shade.a.c.i = uint16(op >> 0);
op = fetch();
shade.r.x.i = uint16(op >> 48);
shade.g.x.i = uint16(op >> 32);
shade.b.x.i = uint16(op >> 16);
shade.a.x.i = uint16(op >> 0);
op = fetch();
shade.r.c.f = uint16(op >> 48);
shade.g.c.f = uint16(op >> 32);
shade.b.c.f = uint16(op >> 16);
shade.a.c.f = uint16(op >> 0);
op = fetch();
shade.r.x.f = uint16(op >> 48);
shade.g.x.f = uint16(op >> 32);
shade.b.x.f = uint16(op >> 16);
shade.a.x.f = uint16(op >> 0);
op = fetch();
shade.r.e.i = uint16(op >> 48);
shade.g.e.i = uint16(op >> 32);
shade.b.e.i = uint16(op >> 16);
shade.a.e.i = uint16(op >> 0);
op = fetch();
shade.r.y.i = uint16(op >> 48);
shade.g.y.i = uint16(op >> 32);
shade.b.y.i = uint16(op >> 16);
shade.a.y.i = uint16(op >> 0);
op = fetch();
shade.r.e.f = uint16(op >> 48);
shade.g.e.f = uint16(op >> 32);
shade.b.e.f = uint16(op >> 16);
shade.a.e.f = uint16(op >> 0);
op = fetch();
shade.r.y.f = uint16(op >> 48);
shade.g.y.f = uint16(op >> 32);
shade.b.y.f = uint16(op >> 16);
shade.a.y.f = uint16(op >> 0);
};
auto fetchTexture = [&](u64 op) {
op = fetch();
texture.s.c.i = uint16(op >> 48);
texture.t.c.i = uint16(op >> 32);
texture.w.c.i = uint16(op >> 16);
op = fetch();
texture.s.x.i = uint16(op >> 48);
texture.t.x.i = uint16(op >> 32);
texture.w.x.i = uint16(op >> 16);
op = fetch();
texture.s.c.f = uint16(op >> 48);
texture.t.c.f = uint16(op >> 32);
texture.w.c.f = uint16(op >> 16);
op = fetch();
texture.s.x.f = uint16(op >> 48);
texture.t.x.f = uint16(op >> 32);
texture.w.x.f = uint16(op >> 16);
op = fetch();
texture.s.e.i = uint16(op >> 48);
texture.t.e.i = uint16(op >> 32);
texture.w.e.i = uint16(op >> 16);
op = fetch();
texture.s.y.i = uint16(op >> 48);
texture.t.y.i = uint16(op >> 32);
texture.w.y.i = uint16(op >> 16);
op = fetch();
texture.s.e.f = uint16(op >> 48);
texture.t.e.f = uint16(op >> 32);
texture.w.e.f = uint16(op >> 16);
op = fetch();
texture.s.y.f = uint16(op >> 48);
texture.t.y.f = uint16(op >> 32);
texture.w.y.f = uint16(op >> 16);
};
auto fetchZBuffer = [&](u64 op) {
op = fetch();
zbuffer.d.i = uint16(op >> 48);
zbuffer.d.f = uint16(op >> 32);
zbuffer.x.i = uint16(op >> 16);
zbuffer.x.f = uint16(op >> 0);
op = fetch();
zbuffer.e.i = uint16(op >> 48);
zbuffer.e.f = uint16(op >> 32);
zbuffer.y.i = uint16(op >> 16);
zbuffer.y.f = uint16(op >> 0);
};
auto fetchRectangle = [&](u64 op) {
rectangle.x.lo = uint12(op >> 44);
rectangle.y.lo = uint12(op >> 32);
rectangle.tile = uint3(op >> 24);
rectangle.x.hi = uint12(op >> 12);
rectangle.y.hi = uint12(op >> 0);
op = fetch();
rectangle.s.i = uint16(op >> 48);
rectangle.t.i = uint16(op >> 32);
rectangle.s.f = uint16(op >> 16);
rectangle.t.f = uint16(op >> 0);
};
while(command.current < command.end) {
u64 op = fetch();
@@ -76,55 +205,55 @@ auto RDP::render() -> void {
} break;
case 0x08: {
command.current += 8 * 3; //edge
//unshadedTriangle();
fetchEdge(op);
unshadedTriangle();
} break;
case 0x09: {
command.current += 8 * 3; //edge
command.current += 8 * 2; //zbuffer
//unshadedZbufferTriangle();
fetchEdge(op);
fetchZBuffer(op);
unshadedZbufferTriangle();
} break;
case 0x0a: {
command.current += 8 * 3; //edge
command.current += 8 * 8; //texture
//textureTriangle();
fetchEdge(op);
fetchTexture(op);
textureTriangle();
} break;
case 0x0b: {
command.current += 8 * 3; //edge
command.current += 8 * 8; //texture
command.current += 8 * 2; //zbuffer
//textureZbufferTriangle();
fetchEdge(op);
fetchTexture(op);
fetchZBuffer(op);
textureZbufferTriangle();
} break;
case 0x0c: {
command.current += 8 * 3; //edge
command.current += 8 * 8; //shade
//shadedTriangle();
fetchEdge(op);
fetchShade(op);
shadedTriangle();
} break;
case 0x0d: {
command.current += 8 * 3; //edge
command.current += 8 * 8; //shade
command.current += 8 * 2; //zbuffer
//shadedZbufferTriangle();
fetchEdge(op);
fetchShade(op);
fetchZBuffer(op);
shadedZbufferTriangle();
} break;
case 0x0e: {
command.current += 8 * 3; //edge
command.current += 8 * 8; //shade
command.current += 8 * 8; //texture
//shadedTextureTriangle();
fetchEdge(op);
fetchShade(op);
fetchTexture(op);
shadedTextureTriangle();
} break;
case 0x0f: {
command.current += 8 * 3; //edge
command.current += 8 * 8; //shade
command.current += 8 * 8; //texture
command.current += 8 * 2; //zbuffer
//shadedTextureZbufferTriangle();
fetchEdge(op);
fetchShade(op);
fetchTexture(op);
fetchZBuffer(op);
shadedTextureZbufferTriangle();
} break;
case 0x10:
@@ -151,31 +280,13 @@ auto RDP::render() -> void {
} break;
case 0x24: {
auto xl = uint12(op >> 44);
auto yl = uint12(op >> 32);
auto tile = uint3(op >> 24);
auto xh = uint12(op >> 12);
auto yh = uint12(op >> 0);
op = fetch();
auto s = uint16(op >> 48);
auto t = uint16(op >> 32);
auto dsdx = uint16(op >> 16);
auto dsdy = uint16(op >> 0);
textureRectangle(xl, yl, tile, xh, yh, s, t, dsdx, dsdy);
fetchRectangle(op);
textureRectangle();
} break;
case 0x25: {
auto xl = uint12(op >> 44);
auto yl = uint12(op >> 32);
auto tile = uint3(op >> 24);
auto xh = uint12(op >> 12);
auto yh = uint12(op >> 0);
op = fetch();
auto s = uint16(op >> 48);
auto t = uint16(op >> 32);
auto dsdx = uint16(op >> 16);
auto dsdy = uint16(op >> 0);
textureRectangleFlip(xl, yl, tile, xh, yh, s, t, dsdx, dsdy);
fetchRectangle(op);
textureRectangleFlip();
} break;
case 0x26: {
@@ -195,31 +306,99 @@ auto RDP::render() -> void {
} break;
case 0x2a: {
//setKeyGB();
key.g.width = uint12(op >> 44);
key.b.width = uint12(op >> 32);
key.g.center = uint8(op >> 24);
key.g.scale = uint8(op >> 16);
key.b.center = uint8(op >> 8);
key.b.scale = uint8(op >> 0);
setKeyGB();
} break;
case 0x2b: {
//setKeyR();
key.r.width = uint12(op >> 16);
key.r.center = uint8(op >> 8);
key.r.scale = uint8(op >> 0);
setKeyR();
} break;
case 0x2c: {
//setConvert();
convert.k[0] = uint9(op >> 45);
convert.k[1] = uint9(op >> 36);
convert.k[2] = uint9(op >> 27);
convert.k[3] = uint9(op >> 18);
convert.k[4] = uint9(op >> 9);
convert.k[5] = uint8(op >> 0);
setConvert();
} break;
case 0x2d: {
//setScissor();
scissor.x.hi = uint12(op >> 44);
scissor.y.hi = uint12(op >> 32);
scissor.field = uint1(op >> 25);
scissor.odd = uint1(op >> 24);
scissor.x.lo = uint12(op >> 12);
scissor.y.lo = uint12(op >> 0);
setScissor();
} break;
case 0x2e: {
//setPrimitiveDepth();
primitiveDepth.z = uint16(op >> 16);
primitiveDepth.deltaZ = uint16(op >> 0);
setPrimitiveDepth();
} break;
case 0x2f: {
//setOtherModes();
other.atomicPrimitive = uint1(op >> 55);
other.reserved1 = uint1(op >> 54);
other.cycleType = uint2(op >> 52);
other.perspective = uint1(op >> 51);
other.detailTexture = uint1(op >> 50);
other.sharpenTexture = uint1(op >> 49);
other.lodTexture = uint1(op >> 48);
other.tlut = uint1(op >> 47);
other.tlutType = uint1(op >> 46);
other.sampleType = uint1(op >> 45);
other.midTexel = uint1(op >> 44);
other.bilerp[0] = uint1(op >> 43);
other.bilerp[1] = uint1(op >> 42);
other.convertOne = uint1(op >> 41);
other.colorKey = uint1(op >> 40);
other.colorDitherMode = uint2(op >> 38);
other.alphaDitherMode = uint2(op >> 36);
other.reserved2 = uint4(op >> 32);
other.blend1a[0] = uint2(op >> 30);
other.blend1a[1] = uint2(op >> 28);
other.blend1b[0] = uint2(op >> 26);
other.blend1b[1] = uint2(op >> 24);
other.blend2a[0] = uint2(op >> 22);
other.blend2a[1] = uint2(op >> 20);
other.blend2b[0] = uint2(op >> 18);
other.blend2b[1] = uint2(op >> 16);
other.reserved3 = uint1(op >> 15);
other.forceBlend = uint1(op >> 14);
other.alphaCoverage = uint1(op >> 13);
other.coverageXalpha = uint1(op >> 12);
other.zMode = uint2(op >> 10);
other.coverageMode = uint2(op >> 8);
other.colorOnCoverage = uint1(op >> 7);
other.imageRead = uint1(op >> 6);
other.zUpdate = uint1(op >> 5);
other.zCompare = uint1(op >> 4);
other.antialias = uint1(op >> 3);
other.zSource = uint1(op >> 2);
other.ditherAlpha = uint1(op >> 1);
other.alphaCompare = uint1(op >> 0);
setOtherModes();
} break;
case 0x30: {
//loadTextureLUT();
tlut.s.lo = uint12(op >> 44);
tlut.t.lo = uint12(op >> 32);
tlut.index = uint3(op >> 24);
tlut.s.hi = uint12(op >> 12);
tlut.t.hi = uint12(op >> 0);
loadTLUT();
} break;
case 0x31: {
@@ -227,72 +406,136 @@ auto RDP::render() -> void {
} break;
case 0x32: {
//setTileSize();
tileSize.s.lo = uint12(op >> 44);
tileSize.t.lo = uint12(op >> 32);
tileSize.index = uint3(op >> 24);
tileSize.s.hi = uint12(op >> 12);
tileSize.t.hi = uint12(op >> 0);
setTileSize();
} break;
case 0x33: {
//loadBlock();
load_.block.s.lo = uint12(op >> 44);
load_.block.t.lo = uint12(op >> 32);
load_.block.index = uint3(op >> 24);
load_.block.s.hi = uint12(op >> 12);
load_.block.t.hi = uint12(op >> 0);
loadBlock();
} break;
case 0x34: {
//loadTile();
load_.tile.s.lo = uint12(op >> 44);
load_.tile.t.lo = uint12(op >> 32);
load_.tile.index = uint3(op >> 24);
load_.tile.s.hi = uint12(op >> 12);
load_.tile.t.hi = uint12(op >> 0);
loadTile();
} break;
case 0x35: {
//setTile();
tile.format = uint3(op >> 53);
tile.size = uint2(op >> 51);
tile.line = uint9(op >> 41);
tile.address = uint9(op >> 32);
tile.index = uint3(op >> 24);
tile.palette = uint4(op >> 20);
tile.t.clamp = uint1(op >> 19);
tile.t.mirror = uint1(op >> 18);
tile.t.mask = uint4(op >> 14);
tile.t.shift = uint4(op >> 10);
tile.s.clamp = uint1(op >> 9);
tile.s.mirror = uint1(op >> 8);
tile.s.mask = uint4(op >> 4);
tile.s.shift = uint4(op >> 0);
setTile();
} break;
case 0x36: {
auto xl = uint12(op >> 44);
auto yl = uint12(op >> 32);
auto xh = uint12(op >> 12);
auto yh = uint12(op >> 0);
fillRectangle(xl, yl, xh, yh);
fillRectangle_.x.lo = uint12(op >> 44);
fillRectangle_.y.lo = uint12(op >> 32);
fillRectangle_.x.hi = uint12(op >> 12);
fillRectangle_.y.hi = uint12(op >> 0);
fillRectangle();
} break;
case 0x37: {
auto color = uint32(op >> 0);
setFillColor(color);
set.fill.color = uint32(op >> 0);
setFillColor();
} break;
case 0x38: {
//setFogColor();
fog.red = uint8(op >> 24);
fog.green = uint8(op >> 16);
fog.blue = uint8(op >> 8);
fog.alpha = uint8(op >> 0);
setFogColor();
} break;
case 0x39: {
//setBlendColor();
blend.red = uint8(op >> 24);
blend.green = uint8(op >> 16);
blend.blue = uint8(op >> 8);
blend.alpha = uint8(op >> 0);
setBlendColor();
} break;
case 0x3a: {
//setPrimitiveColor();
primitive.minimum = uint4(op >> 40);
primitive.fraction = uint8(op >> 32);
primitive.red = uint8(op >> 24);
primitive.green = uint8(op >> 16);
primitive.blue = uint8(op >> 8);
primitive.alpha = uint8(op >> 0);
setPrimitiveColor();
} break;
case 0x3b: {
//setEnvironmentColor();
environment.red = uint8(op >> 24);
environment.green = uint8(op >> 16);
environment.blue = uint8(op >> 8);
environment.alpha = uint8(op >> 0);
setEnvironmentColor();
} break;
case 0x3c: {
//setCombineMode();
combine.sba.color[0] = uint4(op >> 52);
combine.mul.color[0] = uint5(op >> 47);
combine.sba.alpha[0] = uint3(op >> 44);
combine.mul.alpha[0] = uint3(op >> 41);
combine.sba.color[1] = uint4(op >> 37);
combine.mul.color[1] = uint5(op >> 32);
combine.sbb.color[0] = uint4(op >> 28);
combine.sbb.color[1] = uint4(op >> 24);
combine.sba.alpha[1] = uint3(op >> 21);
combine.mul.alpha[1] = uint3(op >> 18);
combine.add.color[0] = uint3(op >> 15);
combine.sbb.alpha[0] = uint3(op >> 12);
combine.add.alpha[0] = uint3(op >> 9);
combine.add.color[1] = uint3(op >> 6);
combine.sbb.alpha[1] = uint3(op >> 3);
combine.add.alpha[1] = uint3(op >> 0);
setCombineMode();
} break;
case 0x3d: {
auto format = uint3(op >> 53);
auto size = uint2(op >> 51);
auto width = uint10(op >> 32);
auto dramAddress = uint26(op >> 0);
setTextureImage(format, size, width, dramAddress);
set.texture.format = uint3(op >> 53);
set.texture.size = uint2(op >> 51);
set.texture.width = uint10(op >> 32);
set.texture.dramAddress = uint26(op >> 0);
setTextureImage();
} break;
case 0x3e: {
//setMaskImage();
set.mask.dramAddress = uint26(op >> 0);
setMaskImage();
} break;
case 0x3f: {
auto format = uint3(op >> 53);
auto size = uint2(op >> 51);
auto width = uint10(op >> 32);
auto dramAddress = uint26(op >> 0);
setColorImage(format, size, width, dramAddress);
set.color.format = uint3(op >> 53);
set.color.size = uint2(op >> 51);
set.color.width = uint10(op >> 32);
set.color.dramAddress = uint26(op >> 0);
setColorImage();
} break;
}
@@ -307,18 +550,44 @@ auto RDP::noOperation() -> void {
auto RDP::invalidOperation() -> void {
}
//0x08
auto RDP::unshadedTriangle() -> void {
}
//0x09
auto RDP::unshadedZbufferTriangle() -> void {
}
//0x0a
auto RDP::textureTriangle() -> void {
}
//0x0b
auto RDP::textureZbufferTriangle() -> void {
}
//0x0c
auto RDP::shadedTriangle() -> void {
}
//0x0d
auto RDP::shadedZbufferTriangle() -> void {
}
//0x0e
auto RDP::shadedTextureTriangle() -> void {
}
//0x0f
auto RDP::shadedTextureZbufferTriangle() -> void {
}
//0x24
auto RDP::textureRectangle(
uint12 xl, uint12 yl, uint3 tile, uint12 xh, uint12 yh,
uint16 s, uint16 t, uint16 dsdx, uint16 dsdy
) -> void {
auto RDP::textureRectangle() -> void {
}
//0x25
auto RDP::textureRectangleFlip(
uint12 xl, uint12 yl, uint3 tile, uint12 xh, uint12 yh,
uint16 s, uint16 t, uint16 dsdx, uint16 dsdy
) -> void {
auto RDP::textureRectangleFlip() -> void {
}
//0x26
@@ -338,45 +607,86 @@ auto RDP::syncFull() -> void {
mi.raise(MI::IRQ::DP);
}
//0x2a
auto RDP::setKeyGB() -> void {
}
//0x2b
auto RDP::setKeyR() -> void {
}
//0x2c
auto RDP::setConvert() -> void {
}
//0x2d
auto RDP::setScissor() -> void {
}
//0x2e
auto RDP::setPrimitiveDepth() -> void {
}
//0x2f
auto RDP::setOtherModes() -> void {
}
//0x30
auto RDP::loadTLUT() -> void {
}
//0x32
auto RDP::setTileSize() -> void {
}
//0x33
auto RDP::loadBlock() -> void {
}
//0x34
auto RDP::loadTile() -> void {
}
//0x35
auto RDP::setTile() -> void {
}
//0x36
auto RDP::fillRectangle(uint12 xl, uint12 yl, uint12 xh, uint12 yh) -> void {
u32 depth = vi.io.colorDepth == 2 ? 2 : 4;
u32 step = vi.io.colorDepth == 2 ? 2 : 1;
u32 shift = 2;
xl >>= shift;
yl >>= shift;
xh >>= shift;
yh >>= shift;
u32 base = set.color.dramAddress;
for(u32 y = yh; y <= yl; y++) {
u32 line = base + y * vi.io.width * depth;
u32 address = line + xh * depth;
for(u32 x = xh; x <= xl; x += step) {
//rdram.ram.writeWord(address, set.fill.color);
address += 4;
}
}
auto RDP::fillRectangle() -> void {
}
//0x37
auto RDP::setFillColor(uint32 color) -> void {
set.fill.color = color;
auto RDP::setFillColor() -> void {
}
//0x38
auto RDP::setFogColor() -> void {
}
//0x39
auto RDP::setBlendColor() -> void {
}
//0x3a
auto RDP::setPrimitiveColor() -> void {
}
//0x3b
auto RDP::setEnvironmentColor() -> void {
}
//0x3c
auto RDP::setCombineMode() -> void {
}
//0x3d
auto RDP::setTextureImage(uint3 format, uint2 size, uint10 width, uint26 dramAddress) -> void {
set.texture.format = format;
set.texture.size = size;
set.texture.width = width;
set.texture.dramAddress = dramAddress;
auto RDP::setTextureImage() -> void {
}
//0x3e
auto RDP::setMaskImage() -> void {
}
//0x3f
auto RDP::setColorImage(uint3 format, uint2 size, uint10 width, uint26 dramAddress) -> void {
set.color.format = format;
set.color.size = size;
set.color.width = width;
set.color.dramAddress = dramAddress;
auto RDP::setColorImage() -> void {
}
+2 -2
View File
@@ -11,7 +11,7 @@ static const vector<string> registerNames = {
"RDRAM_DEVICE_MANUF",
};
auto RDRAM::readIO(u32 address) -> u32 {
auto RDRAM::readWord(u32 address) -> u32 {
address = (address & 0xfffff) >> 2;
u32 data = 0;
@@ -61,7 +61,7 @@ auto RDRAM::readIO(u32 address) -> u32 {
return data;
}
auto RDRAM::writeIO(u32 address, u32 data) -> void {
auto RDRAM::writeWord(u32 address, u32 data) -> void {
address = (address & 0xfffff) >> 2;
if(address == 0) {
+2 -1
View File
@@ -18,8 +18,9 @@ auto RDRAM::load(Node::Object parent) -> void {
}
auto RDRAM::unload() -> void {
ram.reset();
debugger = {};
ram.reset();
node.reset();
}
auto RDRAM::power() -> void {
+4 -4
View File
@@ -1,8 +1,8 @@
//RAMBUS RAM
struct RDRAM {
struct RDRAM : Memory::IO<RDRAM> {
Node::Component node;
Memory ram;
Memory::Writable ram;
struct Debugger {
//debugger.cpp
@@ -24,8 +24,8 @@ struct RDRAM {
auto power() -> void;
//io.cpp
auto readIO(u32 address) -> u32;
auto writeIO(u32 address, u32 data) -> void;
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
+3 -2
View File
@@ -9,7 +9,7 @@ static const vector<string> registerNames = {
"RI_WERROR",
};
auto RI::readIO(u32 address) -> u32 {
auto RI::readWord(u32 address) -> u32 {
address = (address & 0xfffff) >> 2;
uint32 data = 0;
@@ -51,8 +51,9 @@ auto RI::readIO(u32 address) -> u32 {
return data;
}
auto RI::writeIO(u32 address, u32 data) -> void {
auto RI::writeWord(u32 address, u32 data_) -> void {
address = (address & 0xfffff) >> 2;
uint32 data = data_;
if(address == 0) {
//RI_MODE
+3 -3
View File
@@ -1,6 +1,6 @@
//RDRAM Interface
struct RI {
struct RI : Memory::IO<RI> {
Node::Component node;
struct Debugger {
@@ -19,8 +19,8 @@ struct RI {
auto power() -> void;
//io.cpp
auto readIO(u32 address) -> u32;
auto writeIO(u32 address, u32 data) -> void;
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
+52 -1
View File
@@ -1,11 +1,57 @@
#include "registers.hpp"
#include "instruction.cpp"
#include "vu-registers.cpp"
#include "decoder.cpp"
#include "cpu-instructions.cpp"
#include "scc-instructions.cpp"
#include "vu-instructions.cpp"
#include "recompiler.cpp"
#include "disassembler.cpp"
#include "serialization.cpp"
auto RSP::instruction() -> void {
if constexpr(Accuracy::RSP::Interpreter == 0) {
auto block = recompiler.block(PC);
block->execute();
step(block->step);
}
if constexpr(Accuracy::RSP::Interpreter == 1) {
pipeline.address = PC;
pipeline.instruction = imem.readWord(pipeline.address);
debugger.instruction();
//instructionDebug();
decoderEXECUTE();
instructionEpilogue();
step(3);
}
}
auto RSP::instructionEpilogue() -> bool {
GPR[0].u32 = 0;
switch(branch.state) {
case Branch::Step: PC += 4; return 0;
case Branch::Take: PC += 4; branch.delaySlot(); return 0;
case Branch::DelaySlot: PC = branch.pc; branch.reset(); return 1;
case Branch::Halt: PC += 4; return 1;
}
unreachable;
}
auto RSP::instructionDebug() -> void {
pipeline.address = PC;
pipeline.instruction = imem.readWord(pipeline.address);
static uint counter = 0;
//if(++counter > 100) return;
print(
disassembler.hint(hex(pipeline.address, 3L)), " ",
//disassembler.hint(hex(pipeline.instruction, 8L)), " ",
disassembler.disassemble(pipeline.address, pipeline.instruction), "\n"
);
}
auto RSP::powerCore() -> void {
for(uint n : range(32)) GPR[n].u32 = 0;
PC = 0;
@@ -37,4 +83,9 @@ auto RSP::powerCore() -> void {
while(a * (b + 1) * (b + 1) < (u64(1) << 44)) b++;
inverseSquareRoots[index] = u16(b >> 1);
}
if constexpr(Accuracy::RSP::Interpreter == 0) {
recompiler.allocator.resize(512_MiB, bump_allocator::executable | bump_allocator::zero_fill);
recompiler.reset();
}
}
+14 -8
View File
@@ -1,15 +1,20 @@
//{
//core.cpp
auto instruction() -> void;
auto instructionEpilogue() -> bool;
auto instructionDebug() -> void;
auto powerCore() -> void;
//instruction.cpp
auto instruction() -> void;
auto instructionDEBUG() -> void;
auto instructionEXECUTE() -> void;
auto instructionSPECIAL() -> void;
auto instructionREGIMM() -> void;
auto instructionCOP0() -> void;
auto instructionCOP2() -> void;
//decoder.cpp
auto decoderEXECUTE() -> void;
auto decoderSPECIAL() -> void;
auto decoderREGIMM() -> void;
auto decoderCOP0() -> void;
auto decoderCOP2() -> void;
auto decoderLWC2() -> void;
auto decoderSWC2() -> void;
auto instructionINVALID() -> void;
//serialization.cpp
auto serializeCore(serializer&) -> void;
@@ -18,5 +23,6 @@
#include "cpu.hpp"
#include "scc.hpp"
#include "vu.hpp"
#include "recompiler.hpp"
#include "disassembler.hpp"
//};
+98 -72
View File
@@ -1,152 +1,178 @@
auto RSP::instructionADDIU() -> void {
RT.u32 = i32(RS.u32 + IMMi16);
auto RSP::instructionADDIU(r32& rt, cr32& rs, i16 imm) -> void {
rt.u32 = i32(rs.u32 + imm);
}
auto RSP::instructionADDU() -> void {
RD.u32 = i32(RS.u32 + RT.u32);
auto RSP::instructionADDU(r32& rd, cr32& rs, cr32& rt) -> void {
rd.u32 = i32(rs.u32 + rt.u32);
}
auto RSP::instructionAND() -> void {
RD.u32 = RS.u32 & RT.u32;
auto RSP::instructionAND(r32& rd, cr32& rs, cr32& rt) -> void {
rd.u32 = rs.u32 & rt.u32;
}
auto RSP::instructionANDI() -> void {
RT.u32 = RS.u32 & IMMu16;
auto RSP::instructionANDI(r32& rt, cr32& rs, u16 imm) -> void {
rt.u32 = rs.u32 & imm;
}
auto RSP::instructionB(bool take) -> void {
if(take) branch.take(PC + 4 + (IMMi16 << 2));
auto RSP::instructionBEQ(cr32& rs, cr32& rt, i16 imm) -> void {
if(rs.u32 == rt.u32) branch.take(PC + 4 + (imm << 2));
}
auto RSP::instructionBAL(bool take) -> void {
auto RSP::instructionBGEZ(cr32& rs, i16 imm) -> void {
if(rs.i32 >= 0) branch.take(PC + 4 + (imm << 2));
}
auto RSP::instructionBGEZAL(cr32& rs, i16 imm) -> void {
RA.u32 = i32(PC + 8);
if(take) branch.take(PC + 4 + (IMMi16 << 2));
if(rs.i32 >= 0) branch.take(PC + 4 + (imm << 2));
}
auto RSP::instructionBGTZ(cr32& rs, i16 imm) -> void {
if(rs.i32 > 0) branch.take(PC + 4 + (imm << 2));
}
auto RSP::instructionBLEZ(cr32& rs, i16 imm) -> void {
if(rs.i32 <= 0) branch.take(PC + 4 + (imm << 2));
}
auto RSP::instructionBLTZ(cr32& rs, i16 imm) -> void {
if(rs.i32 < 0) branch.take(PC + 4 + (imm << 2));
}
auto RSP::instructionBLTZAL(cr32& rs, i16 imm) -> void {
RA.u32 = i32(PC + 8);
if(rs.i32 < 0) branch.take(PC + 4 + (imm << 2));
}
auto RSP::instructionBNE(cr32& rs, cr32& rt, i16 imm) -> void {
if(rs.u32 != rt.u32) branch.take(PC + 4 + (imm << 2));
}
auto RSP::instructionBREAK() -> void {
status.halted = 1;
status.broken = 1;
if(status.interruptOnBreak) mi.raise(MI::IRQ::SP);
branch.halt();
}
auto RSP::instructionCACHE() -> void {
auto RSP::instructionCACHE(u8 cache, u8 operation) -> void {
//todo
}
auto RSP::instructionJ() -> void {
branch.take((PC + 4 & 0xf000'0000) | (IMMu26 << 2));
auto RSP::instructionJ(u32 imm) -> void {
branch.take((PC + 4 & 0xf000'0000) | (imm << 2));
}
auto RSP::instructionJAL() -> void {
branch.take((PC + 4 & 0xf000'0000) | (IMMu26 << 2));
auto RSP::instructionJAL(u32 imm) -> void {
RA.u32 = i32(PC + 8);
branch.take((PC + 4 & 0xf000'0000) | (imm << 2));
}
auto RSP::instructionJALR() -> void {
branch.take(RS.u32);
RD.u32 = i32(PC + 8);
auto RSP::instructionJALR(r32& rd, cr32& rs) -> void {
rd.u32 = i32(PC + 8);
branch.take(rs.u32);
}
auto RSP::instructionJR() -> void {
branch.take(RS.u32);
auto RSP::instructionJR(cr32& rs) -> void {
branch.take(rs.u32);
}
auto RSP::instructionLB() -> void {
RT.u32 = i8(dmem.readByte(RS.u32 + IMMi16));
auto RSP::instructionLB(r32& rt, cr32& rs, i16 imm) -> void {
rt.u32 = i8(dmem.readByte(rs.u32 + imm));
}
auto RSP::instructionLBU() -> void {
RT.u32 = u8(dmem.readByte(RS.u32 + IMMi16));
auto RSP::instructionLBU(r32& rt, cr32& rs, i16 imm) -> void {
rt.u32 = u8(dmem.readByte(rs.u32 + imm));
}
auto RSP::instructionLH() -> void {
RT.u32 = i16(dmem.readHalfUnaligned(RS.u32 + IMMi16));
auto RSP::instructionLH(r32& rt, cr32& rs, i16 imm) -> void {
rt.u32 = i16(dmem.readHalfUnaligned(rs.u32 + imm));
}
auto RSP::instructionLHU() -> void {
RT.u32 = u16(dmem.readHalfUnaligned(RS.u32 + IMMi16));
auto RSP::instructionLHU(r32& rt, cr32& rs, i16 imm) -> void {
rt.u32 = u16(dmem.readHalfUnaligned(rs.u32 + imm));
}
auto RSP::instructionLUI() -> void {
RT.u32 = i32(IMMu16 << 16);
auto RSP::instructionLUI(r32& rt, u16 imm) -> void {
rt.u32 = i32(imm << 16);
}
auto RSP::instructionLW() -> void {
RT.u32 = i32(dmem.readWordUnaligned(RS.u32 + IMMi16));
auto RSP::instructionLW(r32& rt, cr32& rs, i16 imm) -> void {
rt.u32 = i32(dmem.readWordUnaligned(rs.u32 + imm));
}
auto RSP::instructionNOR() -> void {
RD.u32 = ~(RS.u32 | RT.u32);
auto RSP::instructionNOR(r32& rd, cr32& rs, cr32& rt) -> void {
rd.u32 = ~(rs.u32 | rt.u32);
}
auto RSP::instructionOR() -> void {
RD.u32 = RS.u32 | RT.u32;
auto RSP::instructionOR(r32& rd, cr32& rs, cr32& rt) -> void {
rd.u32 = rs.u32 | rt.u32;
}
auto RSP::instructionORI() -> void {
RT.u32 = RS.u32 | IMMu16;
auto RSP::instructionORI(r32& rt, cr32& rs, u16 imm) -> void {
rt.u32 = rs.u32 | imm;
}
auto RSP::instructionSB() -> void {
dmem.writeByte(RS.u32 + IMMi16, RT.u32);
auto RSP::instructionSB(cr32& rt, cr32& rs, i16 imm) -> void {
dmem.writeByte(rs.u32 + imm, rt.u32);
}
auto RSP::instructionSH() -> void {
dmem.writeHalfUnaligned(RS.u32 + IMMi16, RT.u32);
auto RSP::instructionSH(cr32& rt, cr32& rs, i16 imm) -> void {
dmem.writeHalfUnaligned(rs.u32 + imm, rt.u32);
}
auto RSP::instructionSLL() -> void {
RD.u32 = i32(RT.u32 << SA);
auto RSP::instructionSLL(r32& rd, cr32& rt, u8 sa) -> void {
rd.u32 = i32(rt.u32 << sa);
}
auto RSP::instructionSLLV() -> void {
RD.u32 = i32(RT.u32 << (RS.u32 & 31));
auto RSP::instructionSLLV(r32& rd, cr32& rt, cr32& rs) -> void {
rd.u32 = i32(rt.u32 << (rs.u32 & 31));
}
auto RSP::instructionSLT() -> void {
RD.u32 = RS.i32 < RT.i32;
auto RSP::instructionSLT(r32& rd, cr32& rs, cr32& rt) -> void {
rd.u32 = rs.i32 < rt.i32;
}
auto RSP::instructionSLTI() -> void {
RT.u32 = RS.i32 < i32(IMMi16);
auto RSP::instructionSLTI(r32& rt, cr32& rs, i16 imm) -> void {
rt.u32 = rs.i32 < imm;
}
auto RSP::instructionSLTIU() -> void {
RT.u32 = RS.u32 < u32(IMMu16);
auto RSP::instructionSLTIU(r32& rt, cr32& rs, i16 imm) -> void {
rt.u32 = rs.u32 < imm;
}
auto RSP::instructionSLTU() -> void {
RD.u32 = RS.u32 < RT.u32;
auto RSP::instructionSLTU(r32& rd, cr32& rs, cr32& rt) -> void {
rd.u32 = rs.u32 < rt.u32;
}
auto RSP::instructionSRA() -> void {
RD.u32 = RT.i32 >> SA;
auto RSP::instructionSRA(r32& rd, cr32& rt, u8 sa) -> void {
rd.u32 = rt.i32 >> sa;
}
auto RSP::instructionSRAV() -> void {
RD.u32 = RT.i32 >> (RS.u32 & 31);
auto RSP::instructionSRAV(r32& rd, cr32& rt, cr32& rs) -> void {
rd.u32 = rt.i32 >> (rs.u32 & 31);
}
auto RSP::instructionSRL() -> void {
RD.u32 = i32(RT.u32 >> SA);
auto RSP::instructionSRL(r32& rd, cr32& rt, u8 sa) -> void {
rd.u32 = i32(rt.u32 >> sa);
}
auto RSP::instructionSRLV() -> void {
RD.u32 = i32(RT.u32 >> (RS.u32 & 31));
auto RSP::instructionSRLV(r32& rd, cr32& rt, cr32& rs) -> void {
rd.u32 = i32(rt.u32 >> (rs.u32 & 31));
}
auto RSP::instructionSUBU() -> void {
RD.u32 = i32(RS.u32 - RT.u32);
auto RSP::instructionSUBU(r32& rd, cr32& rs, cr32& rt) -> void {
rd.u32 = i32(rs.u32 - rt.u32);
}
auto RSP::instructionSW() -> void {
dmem.writeWordUnaligned(RS.u32 + IMMi16, RT.u32);
auto RSP::instructionSW(cr32& rt, cr32& rs, i16 imm) -> void {
dmem.writeWordUnaligned(rs.u32 + imm, rt.u32);
}
auto RSP::instructionXOR() -> void {
RD.u32 = RS.u32 ^ RT.u32;
auto RSP::instructionXOR(r32& rd, cr32& rs, cr32& rt) -> void {
rd.u32 = rs.u32 ^ rt.u32;
}
auto RSP::instructionXORI() -> void {
RT.u32 = RS.u32 ^ IMMu16;
auto RSP::instructionXORI(r32& rt, cr32& rs, u16 imm) -> void {
rt.u32 = rs.u32 ^ imm;
}
+45 -37
View File
@@ -3,6 +3,7 @@
struct { int32_t i32; };
struct { uint32_t u32; };
};
using cr32 = const r32;
struct Core {
enum Register : uint {
@@ -17,53 +18,60 @@
} core;
struct Branch {
enum : u32 { Step, Take, DelaySlot };
enum : u32 { Step, Take, DelaySlot, Halt };
auto inDelaySlot() const -> bool { return state == DelaySlot; }
auto reset() -> void { state = Step; }
auto take(u32 address) -> void { state = Take; pc = address; }
auto delaySlot() -> void { state = DelaySlot; }
auto halt() -> void { state = Halt; }
u64 pc;
u32 state;
} branch;
//cpu-instructions.cpp
auto instructionADDIU() -> void;
auto instructionADDU() -> void;
auto instructionAND() -> void;
auto instructionANDI() -> void;
auto instructionB(bool) -> void;
auto instructionBAL(bool) -> void;
auto instructionADDIU(r32& rt, cr32& rs, i16 imm) -> void;
auto instructionADDU(r32& rd, cr32& rs, cr32& rt) -> void;
auto instructionAND(r32& rd, cr32& rs, cr32& rt) -> void;
auto instructionANDI(r32& rt, cr32& rs, u16 imm) -> void;
auto instructionBEQ(cr32& rs, cr32& rt, i16 imm) -> void;
auto instructionBGEZ(cr32& rs, i16 imm) -> void;
auto instructionBGEZAL(cr32& rs, i16 imm) -> void;
auto instructionBGTZ(cr32& rs, i16 imm) -> void;
auto instructionBLEZ(cr32& rs, i16 imm) -> void;
auto instructionBLTZ(cr32& rs, i16 imm) -> void;
auto instructionBLTZAL(cr32& rs, i16 imm) -> void;
auto instructionBNE(cr32& rs, cr32& rt, i16 imm) -> void;
auto instructionBREAK() -> void;
auto instructionCACHE() -> void;
auto instructionJ() -> void;
auto instructionJAL() -> void;
auto instructionJALR() -> void;
auto instructionJR() -> void;
auto instructionLB() -> void;
auto instructionLBU() -> void;
auto instructionLH() -> void;
auto instructionLHU() -> void;
auto instructionLUI() -> void;
auto instructionLW() -> void;
auto instructionNOR() -> void;
auto instructionOR() -> void;
auto instructionORI() -> void;
auto instructionSB() -> void;
auto instructionSH() -> void;
auto instructionSLL() -> void;
auto instructionSLLV() -> void;
auto instructionSLT() -> void;
auto instructionSLTI() -> void;
auto instructionSLTIU() -> void;
auto instructionSLTU() -> void;
auto instructionSRA() -> void;
auto instructionSRAV() -> void;
auto instructionSRL() -> void;
auto instructionSRLV() -> void;
auto instructionSUBU() -> void;
auto instructionSW() -> void;
auto instructionXOR() -> void;
auto instructionXORI() -> void;
auto instructionCACHE(u8 cache, u8 operation) -> void;
auto instructionJ(u32 imm) -> void;
auto instructionJAL(u32 imm) -> void;
auto instructionJALR(r32& rd, cr32& rs) -> void;
auto instructionJR(cr32& rs) -> void;
auto instructionLB(r32& rt, cr32& rs, i16 imm) -> void;
auto instructionLBU(r32& rt, cr32& rs, i16 imm) -> void;
auto instructionLH(r32& rt, cr32& rs, i16 imm) -> void;
auto instructionLHU(r32& rt, cr32& rs, i16 imm) -> void;
auto instructionLUI(r32& rt, u16 imm) -> void;
auto instructionLW(r32& rt, cr32& rs, i16 imm) -> void;
auto instructionNOR(r32& rd, cr32& rs, cr32& rt) -> void;
auto instructionOR(r32& rd, cr32& rs, cr32& rt) -> void;
auto instructionORI(r32& rt, cr32& rs, u16 imm) -> void;
auto instructionSB(cr32& rt, cr32& rs, i16 imm) -> void;
auto instructionSH(cr32& rt, cr32& rs, i16 imm) -> void;
auto instructionSLL(r32& rd, cr32& rt, u8 sa) -> void;
auto instructionSLLV(r32& rd, cr32& rt, cr32& rs) -> void;
auto instructionSLT(r32& rd, cr32& rs, cr32& rt) -> void;
auto instructionSLTI(r32& rt, cr32& rs, i16 imm) -> void;
auto instructionSLTIU(r32& rt, cr32& rs, i16 imm) -> void;
auto instructionSLTU(r32& rd, cr32& rs, cr32& rt) -> void;
auto instructionSRA(r32& rd, cr32& rt, u8 sa) -> void;
auto instructionSRAV(r32& rd, cr32& rt, cr32& rs) -> void;
auto instructionSRL(r32& rd, cr32& rt, u8 sa) -> void;
auto instructionSRLV(r32& rd, cr32& rt, cr32& rs) -> void;
auto instructionSUBU(r32& rd, cr32& rs, cr32& rt) -> void;
auto instructionSW(cr32& rt, cr32& rs, i16 imm) -> void;
auto instructionXOR(r32& rd, cr32& rs, cr32& rt) -> void;
auto instructionXORI(r32& rt, cr32& rs, u16 imm) -> void;
//};
+61
View File
@@ -0,0 +1,61 @@
#define OP pipeline.instruction
#define RD GPR[RDn]
#define RT GPR[RTn]
#define RS GPR[RSn]
#define VD VPR[VDn]
#define VS VPR[VSn]
#define VT VPR[VTn]
#define jp(id, name, ...) case id: return decoder##name(__VA_ARGS__)
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__)
#define br(id, name, ...) case id: return instruction##name(__VA_ARGS__)
auto RSP::decoderEXECUTE() -> void {
#define DECODER_EXECUTE
#include "decoder.hpp"
}
auto RSP::decoderSPECIAL() -> void {
#define DECODER_SPECIAL
#include "decoder.hpp"
}
auto RSP::decoderREGIMM() -> void {
#define DECODER_REGIMM
#include "decoder.hpp"
}
auto RSP::decoderCOP0() -> void {
#define DECODER_COP0
#include "decoder.hpp"
}
auto RSP::decoderCOP2() -> void {
#define DECODER_COP2
#include "decoder.hpp"
}
auto RSP::decoderLWC2() -> void {
#define DECODER_LWC2
#include "decoder.hpp"
}
auto RSP::decoderSWC2() -> void {
#define DECODER_SWC2
#include "decoder.hpp"
}
auto RSP::instructionINVALID() -> void {
}
#undef jp
#undef op
#undef br
#undef OP
#undef RD
#undef RT
#undef RS
#undef VD
#undef VS
#undef VT
+376
View File
@@ -0,0 +1,376 @@
//shares instruction decoding between interpreter and dynamic recompiler
#define SA (OP >> 6 & 31)
#define RDn (OP >> 11 & 31)
#define RTn (OP >> 16 & 31)
#define RSn (OP >> 21 & 31)
#define VDn (OP >> 6 & 31)
#define VSn (OP >> 11 & 31)
#define VTn (OP >> 16 & 31)
#define IMMi16 i16(OP)
#define IMMu16 u16(OP)
#define IMMu26 (OP & 0x03ff'ffff)
#ifdef DECODER_EXECUTE
{
switch(OP >> 26) {
jp(0x00, SPECIAL);
jp(0x01, REGIMM);
br(0x02, J, IMMu26);
br(0x03, JAL, IMMu26);
br(0x04, BEQ, RS, RT, IMMi16);
br(0x05, BNE, RS, RT, IMMi16);
br(0x06, BLEZ, RS, IMMi16);
br(0x07, BGTZ, RS, IMMi16);
op(0x08, ADDIU, RT, RS, IMMi16); //ADDI
op(0x09, ADDIU, RT, RS, IMMi16);
op(0x0a, SLTI, RT, RS, IMMi16);
op(0x0b, SLTIU, RT, RS, IMMi16);
op(0x0c, ANDI, RT, RS, IMMu16);
op(0x0d, ORI, RT, RS, IMMu16);
op(0x0e, XORI, RT, RS, IMMu16);
op(0x0f, LUI, RT, IMMu16);
jp(0x10, COP0);
op(0x11, INVALID); //COP1
jp(0x12, COP2);
op(0x13, INVALID); //COP3
op(0x14, INVALID); //BEQL
op(0x15, INVALID); //BNEL
op(0x16, INVALID); //BLEZL
op(0x17, INVALID); //BGTZL
op(0x18, INVALID); //DADDI
op(0x19, INVALID); //DADDIU
op(0x1a, INVALID); //LDL
op(0x1b, INVALID); //LDR
op(0x1c, INVALID);
op(0x1d, INVALID);
op(0x1e, INVALID);
op(0x1f, INVALID);
op(0x20, LB, RT, RS, IMMi16);
op(0x21, LH, RT, RS, IMMi16);
op(0x22, INVALID); //LWL
op(0x23, LW, RT, RS, IMMi16);
op(0x24, LBU, RT, RS, IMMi16);
op(0x25, LHU, RT, RS, IMMi16);
op(0x26, INVALID); //LWR
op(0x27, INVALID); //LWU
op(0x28, SB, RT, RS, IMMi16);
op(0x29, SH, RT, RS, IMMi16);
op(0x2a, INVALID); //SWL
op(0x2b, SW, RT, RS, IMMi16);
op(0x2c, INVALID); //SDL
op(0x2d, INVALID); //SDR
op(0x2e, INVALID); //SWR
op(0x2f, CACHE, OP >> 16 & 3, OP >> 18 & 3);
op(0x30, INVALID); //LL
op(0x31, INVALID); //LWC1
jp(0x32, LWC2);
op(0x33, INVALID); //LWC3
op(0x34, INVALID); //LLD
op(0x35, INVALID); //LDC1
op(0x36, INVALID); //LDC2
op(0x37, INVALID); //LD
op(0x38, INVALID); //SC
op(0x39, INVALID); //SWC1
jp(0x3a, SWC2);
op(0x3b, INVALID); //SWC3
op(0x3c, INVALID); //SCD
op(0x3d, INVALID); //SDC1
op(0x3e, INVALID); //SDC2
op(0x3f, INVALID); //SD
}
}
#undef DECODER_EXECUTE
#endif
#ifdef DECODER_SPECIAL
{
switch(OP & 0x3f) {
op(0x00, SLL, RD, RT, SA);
op(0x01, INVALID);
op(0x02, SRL, RD, RT, SA);
op(0x03, SRA, RD, RT, SA);
op(0x04, SLLV, RD, RT, RS);
op(0x05, INVALID);
op(0x06, SRLV, RD, RT, RS);
op(0x07, SRAV, RD, RT, RS);
br(0x08, JR, RS);
br(0x09, JALR, RD, RS);
op(0x0a, INVALID);
op(0x0b, INVALID);
op(0x0c, INVALID); //SYSCALL
br(0x0d, BREAK);
op(0x0e, INVALID);
op(0x0f, INVALID); //SYNC
op(0x10, INVALID); //MFHI
op(0x11, INVALID); //MTHI
op(0x12, INVALID); //MFLO
op(0x13, INVALID); //MTLO
op(0x14, INVALID); //DSLLV
op(0x15, INVALID);
op(0x16, INVALID); //DSRLV
op(0x17, INVALID); //DSRAV
op(0x18, INVALID); //MULT
op(0x19, INVALID); //MULTU
op(0x1a, INVALID); //DIV
op(0x1b, INVALID); //DIVU
op(0x1c, INVALID); //DMULT
op(0x1d, INVALID); //DMULTU
op(0x1e, INVALID); //DDIV
op(0x1f, INVALID); //DDIVU
op(0x20, ADDU, RD, RS, RT); //ADD
op(0x21, ADDU, RD, RS, RT);
op(0x22, SUBU, RD, RS, RT); //SUB
op(0x23, SUBU, RD, RS, RT);
op(0x24, AND, RD, RS, RT);
op(0x25, OR, RD, RS, RT);
op(0x26, XOR, RD, RS, RT);
op(0x27, NOR, RD, RS, RT);
op(0x28, INVALID);
op(0x29, INVALID);
op(0x2a, SLT, RD, RS, RT);
op(0x2b, SLTU, RD, RS, RT);
op(0x2c, INVALID); //DADD
op(0x2d, INVALID); //DADDU
op(0x2e, INVALID); //DSUB
op(0x2f, INVALID); //DSUBU
op(0x30, INVALID); //TGE
op(0x31, INVALID); //TGEU
op(0x32, INVALID); //TLT
op(0x33, INVALID); //TLTU
op(0x34, INVALID); //TEQ
op(0x35, INVALID);
op(0x36, INVALID); //TNE
op(0x37, INVALID);
op(0x38, INVALID); //DSLL
op(0x39, INVALID);
op(0x3a, INVALID); //DSRL
op(0x3b, INVALID); //DSRA
op(0x3c, INVALID); //DSLL32
op(0x3d, INVALID);
op(0x3e, INVALID); //DSRL32
op(0x3f, INVALID); //DSRA32
}
}
#undef DECODER_SPECIAL
#endif
#ifdef DECODER_REGIMM
{
switch(OP >> 16 & 0x1f) {
br(0x00, BLTZ, RS, IMMi16);
br(0x01, BGEZ, RS, IMMi16);
op(0x02, INVALID); //BLTZL
op(0x03, INVALID); //BGEZL
op(0x04, INVALID);
op(0x05, INVALID);
op(0x06, INVALID);
op(0x07, INVALID);
op(0x08, INVALID); //TGEI
op(0x09, INVALID); //TGEIU
op(0x0a, INVALID); //TLTI
op(0x0b, INVALID); //TLTIU
op(0x0c, INVALID); //TEQI
op(0x0d, INVALID);
op(0x0e, INVALID); //TNEI
op(0x0f, INVALID);
br(0x10, BLTZAL, RS, IMMi16);
br(0x11, BGEZAL, RS, IMMi16);
op(0x12, INVALID); //BLTZALL
op(0x13, INVALID); //BGEZALL
op(0x14, INVALID);
op(0x15, INVALID);
op(0x16, INVALID);
op(0x17, INVALID);
op(0x18, INVALID);
op(0x19, INVALID);
op(0x1a, INVALID);
op(0x1b, INVALID);
op(0x1c, INVALID);
op(0x1d, INVALID);
op(0x1e, INVALID);
op(0x1f, INVALID);
}
}
#undef DECODER_REGIMM
#endif
#ifdef DECODER_COP0
{
switch(OP >> 21 & 0x1f) {
op(0x00, MFC0, RT, RDn);
op(0x01, INVALID); //DMFC0
op(0x02, INVALID); //CFC0
op(0x03, INVALID);
op(0x04, MTC0, RT, RDn);
op(0x05, INVALID); //DMTC0
op(0x06, INVALID); //CTC0
op(0x07, INVALID);
op(0x08, INVALID); //BC0
op(0x09, INVALID);
op(0x0a, INVALID);
op(0x0b, INVALID);
op(0x0c, INVALID);
op(0x0d, INVALID);
op(0x0e, INVALID);
op(0x0f, INVALID);
}
}
#undef DECODER_COP0
#endif
#ifdef DECODER_COP2
{
#define E (OP >> 7 & 15)
switch(OP >> 21 & 0x1f) {
op(0x00, MFC2, RT, VS, E);
op(0x01, INVALID); //DMFC2
op(0x02, CFC2, RT, RDn);
op(0x03, INVALID);
op(0x04, MTC2, RT, VS, E);
op(0x05, INVALID); //DMTC2
op(0x06, CTC2, RT, RDn);
op(0x07, INVALID);
op(0x08, INVALID); //BC2
op(0x09, INVALID);
op(0x0a, INVALID);
op(0x0b, INVALID);
op(0x0c, INVALID);
op(0x0d, INVALID);
op(0x0e, INVALID);
op(0x0f, INVALID);
}
#undef E
#define E (OP >> 21 & 15)
#define DE (OP >> 11 & 7)
switch(OP & 0x3f) {
op(0x00, VMULF<0>, VD, VS, VT, E);
op(0x01, VMULF<1>, VD, VS, VT, E);
op(0x02, VRND<1>, VD, VSn, VT, E);
op(0x03, VMULQ, VD, VS, VT, E);
op(0x04, VMUDL, VD, VS, VT, E);
op(0x05, VMUDM, VD, VS, VT, E);
op(0x06, VMUDN, VD, VS, VT, E);
op(0x07, VMUDH, VD, VS, VT, E);
op(0x08, VMACF<0>, VD, VS, VT, E);
op(0x09, VMACF<1>, VD, VS, VT, E);
op(0x0a, VRND<0>, VD, VSn, VT, E);
op(0x0b, VMACQ, VD);
op(0x0c, VMADL, VD, VS, VT, E);
op(0x0d, VMADM, VD, VS, VT, E);
op(0x0e, VMADN, VD, VS, VT, E);
op(0x0f, VMADH, VD, VS, VT, E);
op(0x10, VADD, VD, VS, VT, E);
op(0x11, VSUB, VD, VS, VT, E);
op(0x12, INVALID);
op(0x13, VABS, VD, VS, VT, E);
op(0x14, VADDC, VD, VS, VT, E);
op(0x15, VSUBC, VD, VS, VT, E);
op(0x16, INVALID);
op(0x17, INVALID);
op(0x18, INVALID);
op(0x19, INVALID);
op(0x1a, INVALID);
op(0x1b, INVALID);
op(0x1c, INVALID);
op(0x1d, VSAR, VD, VS, E);
op(0x1e, INVALID);
op(0x1f, INVALID);
op(0x20, VLT, VD, VS, VT, E);
op(0x21, VEQ, VD, VS, VT, E);
op(0x22, VNE, VD, VS, VT, E);
op(0x23, VGE, VD, VS, VT, E);
op(0x24, VCL, VD, VS, VT, E);
op(0x25, VCH, VD, VS, VT, E);
op(0x26, VCR, VD, VS, VT, E);
op(0x27, VMRG, VD, VS, VT, E);
op(0x28, VAND, VD, VS, VT, E);
op(0x29, VNAND, VD, VS, VT, E);
op(0x2a, VOR, VD, VS, VT, E);
op(0x2b, VNOR, VD, VS, VT, E);
op(0x2c, VXOR, VD, VS, VT, E);
op(0x2d, VNXOR, VD, VS, VT, E);
op(0x2e, INVALID);
op(0x2f, INVALID);
op(0x30, VRCP<0>, VD, DE, VT, E);
op(0x31, VRCP<1>, VD, DE, VT, E);
op(0x32, VRCPH, VD, DE, VT, E);
op(0x33, VMOV, VD, DE, VT, E);
op(0x34, VRSQ<0>, VD, DE, VT, E);
op(0x35, VRSQ<1>, VD, DE, VT, E);
op(0x36, VRSQH, VD, DE, VT, E);
op(0x37, VNOP);
op(0x38, INVALID);
op(0x39, INVALID);
op(0x3a, INVALID);
op(0x3b, INVALID);
op(0x3c, INVALID);
op(0x3d, INVALID);
op(0x3e, INVALID);
op(0x3f, INVALID);
}
#undef E
#undef DE
}
#undef DECODER_COP2
#endif
#ifdef DECODER_LWC2
{
#define E (OP >> 7 & 15)
#define IMMi7 int7(OP)
switch(OP >> 11 & 0x1f) {
op(0x00, LBV, VT, E, RS, IMMi7);
op(0x01, LSV, VT, E, RS, IMMi7);
op(0x02, LLV, VT, E, RS, IMMi7);
op(0x03, LDV, VT, E, RS, IMMi7);
op(0x04, LQV, VT, E, RS, IMMi7);
op(0x05, LRV, VT, E, RS, IMMi7);
op(0x06, LPV, VT, E, RS, IMMi7);
op(0x07, LUV, VT, E, RS, IMMi7);
op(0x08, LHV, VT, E, RS, IMMi7);
op(0x09, LFV, VT, E, RS, IMMi7);
//op(0x0a, LWV, VT, E, RS, IMMi7); //not present on N64 RSP
op(0x0b, LTV, VTn, E, RS, IMMi7);
}
#undef E
#undef IMMi7
}
#undef DECODER_LWC2
#endif
#ifdef DECODER_SWC2
{
#define E (OP >> 7 & 15)
#define IMMi7 int7(OP)
switch(OP >> 11 & 0x1f) {
op(0x00, SBV, VT, E, RS, IMMi7);
op(0x01, SSV, VT, E, RS, IMMi7);
op(0x02, SLV, VT, E, RS, IMMi7);
op(0x03, SDV, VT, E, RS, IMMi7);
op(0x04, SQV, VT, E, RS, IMMi7);
op(0x05, SRV, VT, E, RS, IMMi7);
op(0x06, SPV, VT, E, RS, IMMi7);
op(0x07, SUV, VT, E, RS, IMMi7);
op(0x08, SHV, VT, E, RS, IMMi7);
op(0x09, SFV, VT, E, RS, IMMi7);
op(0x0a, SWV, VT, E, RS, IMMi7);
op(0x0b, STV, VTn, E, RS, IMMi7);
}
#undef E
#undef IMMi7
}
#undef DECODER_SWC2
#endif
#undef SA
#undef RDn
#undef RTn
#undef RSn
#undef VDn
#undef VSn
#undef VTn
#undef IMMi16
#undef IMMu16
#undef IMMu26
+16 -4
View File
@@ -365,10 +365,22 @@ auto RSP::Disassembler::VU() -> vector<string> {
return {name, vdName(), vsValue(), vtValue()};
};
auto DSE = [&](string_view name) -> vector<string> {
static const string registerNames[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"acch", "accm", "accl", "r11", "r12", "r13", "r14", "r15",
};
return {name, vdName(), vsValue(), registerNames[instruction >> 21 & 15]};
};
auto DT = [&](string_view name) -> vector<string> {
return {name, vmName(), vtValue()};
};
auto D = [&](string_view name) -> vector<string> {
return {name, vdName()};
};
switch(instruction & 0x3f) {
case 0x00: return DST("vmulf");
case 0x01: return DST("vmulu");
@@ -381,7 +393,7 @@ auto RSP::Disassembler::VU() -> vector<string> {
case 0x08: return DST("vmacf");
case 0x09: return DST("vmacu");
case 0x0a: return DST("vrndn");
case 0x0b: return DST("vmacq");
case 0x0b: return D("vmacq");
case 0x0c: return DST("vmadl");
case 0x0d: return DST("vmadm");
case 0x0e: return DST("vmadn");
@@ -399,7 +411,7 @@ auto RSP::Disassembler::VU() -> vector<string> {
case 0x1a: break;
case 0x1b: break;
case 0x1c: break;
case 0x1d: return DST("vsar");
case 0x1d: return DSE("vsar");
case 0x1e: break;
case 0x1f: break;
case 0x20: return DST("vlt");
@@ -479,9 +491,9 @@ auto RSP::Disassembler::sccRegisterName(uint index) const -> string {
auto RSP::Disassembler::sccRegisterValue(uint index) const -> string {
u32 value = 0;
if(index <= 6) value = rsp.readSCC((index & 7) << 2);
if(index <= 6) value = rsp.readWord((index & 7) << 2);
if(index == 7) value = self.status.semaphore; //rsp.readSCC(7) has side-effects
if(index >= 8) value = rdp.readSCC((index & 7) << 2);
if(index >= 8) value = rdp.readWord((index & 7) << 2);
if(showValues) return {sccRegisterName(index), hint("{$", hex(value, 8L), "}")};
return sccRegisterName(index);
}
-291
View File
@@ -1,291 +0,0 @@
auto RSP::instruction() -> void {
pipeline.address = PC;
pipeline.instruction = imem.readWord(pipeline.address);
debugger.instruction();
//instructionDEBUG();
instructionEXECUTE();
GPR[0].u32 = 0;
switch(branch.state) {
case Branch::Step: PC += 4; break;
case Branch::DelaySlot: PC = branch.pc; branch.reset(); break;
case Branch::Take: PC += 4; branch.delaySlot(); break;
}
}
auto RSP::instructionDEBUG() -> void {
static uint counter = 0;
//if(++counter > 100) return;
print(
disassembler.hint(hex(pipeline.address, 3L)), " ",
//disassembler.hint(hex(pipeline.instruction, 8L)), " ",
disassembler.disassemble(pipeline.address, pipeline.instruction), "\n"
);
}
auto RSP::instructionEXECUTE() -> void {
switch(OP >> 26) {
case 0x00: return instructionSPECIAL();
case 0x01: return instructionREGIMM();
case 0x02: return instructionJ();
case 0x03: return instructionJAL();
case 0x04: return instructionB(RS.u32 == RT.u32); //BEQ
case 0x05: return instructionB(RS.u32 != RT.u32); //BNE
case 0x06: return instructionB(RS.i32 <= 0); //BLEZ
case 0x07: return instructionB(RS.i32 > 0); //BGTZ
case 0x08: return instructionADDIU(); //ADDI
case 0x09: return instructionADDIU();
case 0x0a: return instructionSLTI();
case 0x0b: return instructionSLTIU();
case 0x0c: return instructionANDI();
case 0x0d: return instructionORI();
case 0x0e: return instructionXORI();
case 0x0f: return instructionLUI();
case 0x10: return instructionCOP0();
case 0x11: break; //COP1
case 0x12: return instructionCOP2();
case 0x13: break; //COP3
case 0x14: break; //BEQL
case 0x15: break; //BNEL
case 0x16: break; //BLEZL
case 0x17: break; //BGTZL
case 0x18: break; //DADDI
case 0x19: break; //DADDIU
case 0x1a: break; //LDL
case 0x1b: break; //LDR
case 0x1c: break;
case 0x1d: break;
case 0x1e: break;
case 0x1f: break;
case 0x20: return instructionLB();
case 0x21: return instructionLH();
case 0x22: break; //LWL
case 0x23: return instructionLW();
case 0x24: return instructionLBU();
case 0x25: return instructionLHU();
case 0x26: break; //LWR
case 0x27: break; //LWU
case 0x28: return instructionSB();
case 0x29: return instructionSH();
case 0x2a: break; //SWL
case 0x2b: return instructionSW();
case 0x2c: break; //SDL
case 0x2d: break; //SDR
case 0x2e: break; //SWR
case 0x2f: return instructionCACHE();
case 0x30: break; //LL
case 0x31: break; //LWC1
case 0x32: return instructionLWC2();
case 0x33: break; //LWC3
case 0x34: break; //LLD
case 0x35: break; //LDC1
case 0x36: break; //LDC2
case 0x37: break; //LD
case 0x38: break; //SC
case 0x39: break; //SWC1
case 0x3a: return instructionSWC2();
case 0x3b: break; //SWC3
case 0x3c: break; //SCD
case 0x3d: break; //SDC1
case 0x3e: break; //SDC2
case 0x3f: break; //SD
}
}
auto RSP::instructionSPECIAL() -> void {
switch(OP & 0x3f) {
case 0x00: return instructionSLL();
case 0x01: break;
case 0x02: return instructionSRL();
case 0x03: return instructionSRA();
case 0x04: return instructionSLLV();
case 0x05: break;
case 0x06: return instructionSRLV();
case 0x07: return instructionSRAV();
case 0x08: return instructionJR();
case 0x09: return instructionJALR();
case 0x0a: break;
case 0x0b: break;
case 0x0c: break; //SYSCALL
case 0x0d: return instructionBREAK();
case 0x0e: break;
case 0x0f: break; //SYNC
case 0x10: break; //MFHI
case 0x11: break; //MTHI
case 0x12: break; //MFLO
case 0x13: break; //MTLO
case 0x14: break; //DSLLV
case 0x15: break;
case 0x16: break; //DSRLV
case 0x17: break; //DSRAV
case 0x18: break; //MULT
case 0x19: break; //MULTU
case 0x1a: break; //DIV
case 0x1b: break; //DIVU
case 0x1c: break; //DMULT
case 0x1d: break; //DMULTU
case 0x1e: break; //DDIV
case 0x1f: break; //DDIVU
case 0x20: return instructionADDU(); //ADD
case 0x21: return instructionADDU();
case 0x22: return instructionSUBU(); //SUB
case 0x23: return instructionSUBU();
case 0x24: return instructionAND();
case 0x25: return instructionOR();
case 0x26: return instructionXOR();
case 0x27: return instructionNOR();
case 0x28: break;
case 0x29: break;
case 0x2a: return instructionSLT();
case 0x2b: return instructionSLTU();
case 0x2c: break; //DADD
case 0x2d: break; //DADDU
case 0x2e: break; //DSUB
case 0x2f: break; //DSUBU
case 0x30: break; //TGE
case 0x31: break; //TGEU
case 0x32: break; //TLT
case 0x33: break; //TLTU
case 0x34: break; //TEQ
case 0x35: break;
case 0x36: break; //TNE
case 0x37: break;
case 0x38: break; //DSLL
case 0x39: break;
case 0x3a: break; //DSRL
case 0x3b: break; //DSRA
case 0x3c: break; //DSLL32
case 0x3d: break;
case 0x3e: break; //DSRL32
case 0x3f: break; //DSRA32
}
}
auto RSP::instructionREGIMM() -> void {
switch(OP >> 16 & 0x1f) {
case 0x00: return instructionB(RS.i32 < 0); //BLTZ
case 0x01: return instructionB(RS.i32 >= 0); //BGEZ
case 0x02: break; //BLTZL
case 0x03: break; //BGEZL
case 0x04: break;
case 0x05: break;
case 0x06: break;
case 0x07: break;
case 0x08: break; //TGEI
case 0x09: break; //TGEIU
case 0x0a: break; //TLTI
case 0x0b: break; //TLTIU
case 0x0c: break; //TEQI
case 0x0d: break;
case 0x0e: break; //TNEI
case 0x0f: break;
case 0x10: return instructionBAL(RS.i32 < 0); //BLTZAL
case 0x11: return instructionBAL(RS.i32 >= 0); //BGEZAL
case 0x12: break; //BLTZALL
case 0x13: break; //BGEZALL
case 0x14: break;
case 0x15: break;
case 0x16: break;
case 0x17: break;
case 0x18: break;
case 0x19: break;
case 0x1a: break;
case 0x1b: break;
case 0x1c: break;
case 0x1d: break;
case 0x1e: break;
case 0x1f: break;
}
}
auto RSP::instructionCOP0() -> void {
switch(OP >> 21 & 31) {
case 0x00: return instructionMFC0();
case 0x01: break; //DMFC0
case 0x02: break; //CFC0
case 0x04: return instructionMTC0();
case 0x05: break; //DMTC0
case 0x06: break; //CTC0
case 0x08: break; //BC0
}
}
auto RSP::instructionCOP2() -> void {
switch(OP >> 21 & 31) {
case 0x00: return instructionMFC2();
case 0x01: break; //DMFC2
case 0x02: return instructionCFC2();
case 0x04: return instructionMTC2();
case 0x05: break; //DMTC2
case 0x06: return instructionCTC2();
case 0x08: break; //BC2
}
if(!(OP >> 25 & 1)) return;
switch(OP & 0x3f) {
case 0x00: return instructionVMULF(0);
case 0x01: return instructionVMULF(1);
case 0x02: return instructionVRND(1);
case 0x03: return instructionVMULQ();
case 0x04: return instructionVMUDL();
case 0x05: return instructionVMUDM();
case 0x06: return instructionVMUDN();
case 0x07: return instructionVMUDH();
case 0x08: return instructionVMACF(0);
case 0x09: return instructionVMACF(1);
case 0x0a: return instructionVRND(0);
case 0x0b: return instructionVMACQ();
case 0x0c: return instructionVMADL();
case 0x0d: return instructionVMADM();
case 0x0e: return instructionVMADN();
case 0x0f: return instructionVMADH();
case 0x10: return instructionVADD();
case 0x11: return instructionVSUB();
case 0x12: break;
case 0x13: return instructionVABS();
case 0x14: return instructionVADDC();
case 0x15: return instructionVSUBC();
case 0x16: break;
case 0x17: break;
case 0x18: break;
case 0x19: break;
case 0x1a: break;
case 0x1b: break;
case 0x1c: break;
case 0x1d: return instructionVSAR();
case 0x1e: break;
case 0x1f: break;
case 0x20: return instructionVLT();
case 0x21: return instructionVEQ();
case 0x22: return instructionVNE();
case 0x23: return instructionVGE();
case 0x24: return instructionVCL();
case 0x25: return instructionVCH();
case 0x26: return instructionVCR();
case 0x27: return instructionVMRG();
case 0x28: return instructionVAND();
case 0x29: return instructionVNAND();
case 0x2a: return instructionVOR();
case 0x2b: return instructionVNOR();
case 0x2c: return instructionVXOR();
case 0x2d: return instructionVNXOR();
case 0x2e: break;
case 0x2f: break;
case 0x30: return instructionVRCP(0);
case 0x31: return instructionVRCP(1);
case 0x32: return instructionVRCPH();
case 0x33: return instructionVMOV();
case 0x34: return instructionVRSQ(0);
case 0x35: return instructionVRSQ(1);
case 0x36: return instructionVRSQH();
case 0x37: return instructionVNOP();
case 0x38: break;
case 0x39: break;
case 0x3a: break;
case 0x3b: break;
case 0x3c: break;
case 0x3d: break;
case 0x3e: break;
case 0x3f: break;
}
}
+135
View File
@@ -0,0 +1,135 @@
auto RSP::Recompiler::pool() -> Pool* {
if(context) return context;
context = (Pool*)allocator.acquire();
u32 hashcode = 0;
for(u32 offset : range(4096)) {
hashcode = (hashcode << 5) + hashcode + self.imem.readByte(offset);
}
context->hashcode = hashcode;
if(auto result = pools.find(*context)) {
context->hashcode = 0; //leave the memory zeroed out
return context = &result();
}
allocator.reserve(sizeof(Pool));
if(auto result = pools.insert(*context)) {
return context = &result();
}
throw; //should never occur
}
auto RSP::Recompiler::block(u32 address) -> Block* {
auto& block = pool()->blocks[address >> 2 & 0x3ff];
if(!block) block = emit(address);
return block;
}
auto RSP::Recompiler::emit(u32 address) -> Block* {
if(unlikely(allocator.available() < 1_MiB)) {
print("RSP allocator flush\n");
allocator.release(bump_allocator::zero_fill);
reset();
}
auto block = (Block*)allocator.acquire(sizeof(Block));
block->code = allocator.acquire();
bind({block->code, allocator.available()});
bool branched = 0;
uint instructions = 0;
do {
u32 instruction = self.imem.readWord(address);
branched = emitEXECUTE(instruction);
call(&RSP::instructionEpilogue, &self);
test(rax, rax);
jz(imm8{+1});
ret();
address += 4;
if((address & 0xffc) == 0) break; //IMEM boundary
} while(++instructions < 64 && !branched);
ret();
block->step = 3 * instructions;
allocator.reserve(size());
//print(hex(PC, 8L), " ", instructions, " ", size(), "\n");
return block;
}
#define OP instruction
#define RD &self.GPR[RDn]
#define RT &self.GPR[RTn]
#define RS &self.GPR[RSn]
#define VD &self.VPR[VDn]
#define VS &self.VPR[VSn]
#define VT &self.VPR[VTn]
#define jp(id, name) \
case id: \
return emit##name(instruction); \
#define op(id, name, ...) \
case id: \
call(&RSP::instruction##name, &self, ##__VA_ARGS__); \
return 0; \
#define br(id, name, ...) \
case id: \
call(&RSP::instruction##name, &self, ##__VA_ARGS__); \
return 1; \
auto RSP::Recompiler::emitEXECUTE(u32 instruction) -> bool {
#define DECODER_EXECUTE
#include "decoder.hpp"
return 0;
}
auto RSP::Recompiler::emitSPECIAL(u32 instruction) -> bool {
#define DECODER_SPECIAL
#include "decoder.hpp"
return 0;
}
auto RSP::Recompiler::emitREGIMM(u32 instruction) -> bool {
#define DECODER_REGIMM
#include "decoder.hpp"
return 0;
}
auto RSP::Recompiler::emitCOP0(u32 instruction) -> bool {
#define DECODER_COP0
#include "decoder.hpp"
return 0;
}
auto RSP::Recompiler::emitCOP2(u32 instruction) -> bool {
#define DECODER_COP2
#include "decoder.hpp"
return 0;
}
auto RSP::Recompiler::emitLWC2(u32 instruction) -> bool {
#define DECODER_LWC2
#include "decoder.hpp"
return 0;
}
auto RSP::Recompiler::emitSWC2(u32 instruction) -> bool {
#define DECODER_SWC2
#include "decoder.hpp"
return 0;
}
#undef jp
#undef op
#undef br
#undef OP
#undef RD
#undef RT
#undef RS
#undef VD
#undef VS
#undef VT
+50
View File
@@ -0,0 +1,50 @@
//{
struct Recompiler : recompiler::amd64 {
RSP& self;
Recompiler(RSP& self) : self(self) {}
struct Block {
auto execute() -> void {
((void (*)())code)();
}
u32 step;
u8* code;
};
struct Pool {
auto operator==(const Pool& source) const -> bool { return hashcode == source.hashcode; }
auto operator< (const Pool& source) const -> bool { return hashcode < source.hashcode; }
auto hash() const -> u32 { return hashcode; }
u32 hashcode;
Block* blocks[1024];
};
auto reset() -> void {
context = nullptr;
pools.reset();
}
auto invalidate() -> void {
context = nullptr;
}
auto pool() -> Pool*;
auto block(u32 address) -> Block*;
auto emit(u32 address) -> Block*;
auto emitEXECUTE(u32 instruction) -> bool;
auto emitSPECIAL(u32 instruction) -> bool;
auto emitREGIMM(u32 instruction) -> bool;
auto emitCOP0(u32 instruction) -> bool;
auto emitCOP2(u32 instruction) -> bool;
auto emitLWC2(u32 instruction) -> bool;
auto emitSWC2(u32 instruction) -> bool;
bump_allocator allocator;
Pool* context = nullptr;
set<Pool> pools;
//hashset<Pool> pools;
} recompiler{*this};
//};
-48
View File
@@ -1,37 +1,13 @@
#if !defined(RSP_REGISTERS_HPP)
#define RSP_REGISTERS_HPP
//instruction decoding
#define OP pipeline.instruction
#define SA (OP >> 6 & 31)
#define RDn (OP >> 11 & 31)
#define RTn (OP >> 16 & 31)
#define RSn (OP >> 21 & 31)
#define IMMi16 i16(OP)
#define IMMu16 u16(OP)
#define IMMu26 (OP & 0x03ff'ffff)
//CPU
#define GPR core.r
#define PC core.pc
#define RD GPR[RDn]
#define RT GPR[RTn]
#define RS GPR[RSn]
#define RA GPR[Core::Register::RA]
//VU
#define VDn (OP >> 6 & 31)
#define VSn (OP >> 11 & 31)
#define VTn (OP >> 16 & 31)
#define DEn (OP >> 11 & 31)
#define En (OP >> 21 & 15)
#define VPR vu.r
#define VD VPR[VDn]
#define VS VPR[VSn]
#define VT VPR[VTn]
#define VTe this->vte()
#define ACCH vu.acch
#define ACCM vu.accm
@@ -48,37 +24,13 @@
#else
#undef RSP_REGISTERS_HPP
//instruction decoding
#undef OP
#undef SA
#undef RDn
#undef RTn
#undef RSn
#undef IMMi16
#undef IMMu16
#undef IMMu26
//CPU
#undef GPR
#undef PC
#undef RD
#undef RT
#undef RS
#undef RA
//VU
#undef VDn
#undef VSn
#undef VTn
#undef DEn
#undef En
#undef VPR
#undef VD
#undef VS
#undef VT
#undef VTe
#undef ACCH
#undef ACCM
+6 -6
View File
@@ -1,9 +1,9 @@
auto RSP::instructionMFC0() -> void {
if((RDn & 8) == 0) RT.u32 = rsp.readSCC((RDn & 7) << 2);
if((RDn & 8) != 0) RT.u32 = rdp.readSCC((RDn & 7) << 2);
auto RSP::instructionMFC0(r32& rt, u8 rd) -> void {
if((rd & 8) == 0) rt.u32 = Nintendo64::rsp.readWord((rd & 7) << 2);
if((rd & 8) != 0) rt.u32 = Nintendo64::rdp.readWord((rd & 7) << 2);
}
auto RSP::instructionMTC0() -> void {
if((RDn & 8) == 0) rsp.writeSCC((RDn & 7) << 2, RT.u32);
if((RDn & 8) != 0) rdp.writeSCC((RDn & 7) << 2, RT.u32);
auto RSP::instructionMTC0(cr32& rt, u8 rd) -> void {
if((rd & 8) == 0) Nintendo64::rsp.writeWord((rd & 7) << 2, rt.u32);
if((rd & 8) != 0) Nintendo64::rdp.writeWord((rd & 7) << 2, rt.u32);
}
+2 -2
View File
@@ -4,6 +4,6 @@
auto setControlRegister(uint, uint32) -> void;
//scc-instructions.cpp
auto instructionMFC0() -> void;
auto instructionMTC0() -> void;
auto instructionMFC0(r32& rt, u8 rd) -> void;
auto instructionMTC0(cr32& rt, u8 rd) -> void;
//};
File diff suppressed because it is too large. Load diff
+72
View File
@@ -0,0 +1,72 @@
auto RSP::r128::operator()(uint index) const -> r128 {
if constexpr(Accuracy::RSP::SISD) {
r128 v{*this};
switch(index) {
case 0: break;
case 1: break;
case 2: v.u16(1) = v.u16(0); v.u16(3) = v.u16(2); v.u16(5) = v.u16(4); v.u16(7) = v.u16(6); break;
case 3: v.u16(0) = v.u16(1); v.u16(2) = v.u16(3); v.u16(4) = v.u16(5); v.u16(6) = v.u16(7); break;
case 4: v.u16(1) = v.u16(2) = v.u16(3) = v.u16(0); v.u16(5) = v.u16(6) = v.u16(7) = v.u16(4); break;
case 5: v.u16(0) = v.u16(2) = v.u16(3) = v.u16(1); v.u16(4) = v.u16(6) = v.u16(7) = v.u16(5); break;
case 6: v.u16(0) = v.u16(1) = v.u16(3) = v.u16(2); v.u16(4) = v.u16(5) = v.u16(7) = v.u16(6); break;
case 7: v.u16(0) = v.u16(1) = v.u16(2) = v.u16(3); v.u16(4) = v.u16(5) = v.u16(6) = v.u16(7); break;
case 8: for(uint n : range(8)) v.u16(n) = v.u16(0); break;
case 9: for(uint n : range(8)) v.u16(n) = v.u16(1); break;
case 10: for(uint n : range(8)) v.u16(n) = v.u16(2); break;
case 11: for(uint n : range(8)) v.u16(n) = v.u16(3); break;
case 12: for(uint n : range(8)) v.u16(n) = v.u16(4); break;
case 13: for(uint n : range(8)) v.u16(n) = v.u16(5); break;
case 14: for(uint n : range(8)) v.u16(n) = v.u16(6); break;
case 15: for(uint n : range(8)) v.u16(n) = v.u16(7); break;
}
return v;
}
if constexpr(Accuracy::RSP::SIMD) {
static const __m128i shuffle[16] = {
//vector
_mm_set_epi8(15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), //01234567
_mm_set_epi8(15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0), //01234567
//scalar quarter
_mm_set_epi8(15,14,15,14,11,10,11,10, 7, 6, 7, 6, 3, 2, 3, 2), //00224466
_mm_set_epi8(13,12,13,12, 9, 8, 9, 8, 5, 4, 5, 4, 1, 0, 1, 0), //11335577
//scalar half
_mm_set_epi8(15,14,15,14,15,14,15,14, 7, 6, 7, 6, 7, 6, 7, 6), //00004444
_mm_set_epi8(13,12,13,12,13,12,13,12, 5, 4, 5, 4, 5, 4, 5, 4), //11115555
_mm_set_epi8(11,10,11,10,11,10,11,10, 3, 2, 3, 2, 3, 2, 3, 2), //22226666
_mm_set_epi8( 9, 8, 9, 8, 9, 8, 9, 8, 1, 0, 1, 0, 1, 0, 1, 0), //33337777
//scalar whole
_mm_set_epi8(15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14), //00000000
_mm_set_epi8(13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12), //11111111
_mm_set_epi8(11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10), //22222222
_mm_set_epi8( 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8), //33333333
_mm_set_epi8( 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6), //44444444
_mm_set_epi8( 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4), //55555555
_mm_set_epi8( 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2), //66666666
_mm_set_epi8( 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0), //77777777
};
//todo: benchmark to see if testing for cases 0&1 to return value directly is faster
return {uint128_t(_mm_shuffle_epi8(v128, shuffle[index]))};
}
}
auto RSP::accumulatorGet(uint index) const -> u64 {
return (u64)ACCH.u16(index) << 32 | (u64)ACCM.u16(index) << 16 | (u64)ACCL.u16(index) << 0;
}
auto RSP::accumulatorSet(uint index, u64 value) -> void {
ACCH.u16(index) = value >> 32;
ACCM.u16(index) = value >> 16;
ACCL.u16(index) = value >> 0;
}
auto RSP::accumulatorSaturate(uint index, bool slice, u16 negative, u16 positive) const -> u16 {
if(ACCH.i16(index) < 0) {
if(ACCH.u16(index) != 0xffff) return negative;
if(ACCM.i16(index) >= 0) return negative;
} else {
if(ACCH.u16(index) != 0x0000) return positive;
if(ACCM.i16(index) < 0) return positive;
}
return !slice ? ACCL.u16(index) : ACCM.u16(index);
}
+111 -84
View File
@@ -1,101 +1,128 @@
//{
union v128 {
union r128 {
struct { uint128_t u128; };
struct { __m128i s128; };
operator __m128i() const { return s128; }
auto operator=(__m128i value) { s128 = value; }
auto byte(uint index) -> u8& { return ((u8*)&u128)[15 - index]; }
auto element(uint index) -> u16& { return ((u16*)&u128)[7 - index]; }
};
struct { __m128i v128; };
//vu-instructions.cpp
auto vte() -> v128;
operator __m128i() const { return v128; }
auto operator=(__m128i value) { v128 = value; }
auto byte(uint index) -> uint8_t& { return ((uint8_t*)&u128)[15 - index]; }
auto byte(uint index) const -> uint8_t { return ((uint8_t*)&u128)[15 - index]; }
auto element(uint index) -> uint16_t& { return ((uint16_t*)&u128)[7 - index]; }
auto element(uint index) const -> uint16_t { return ((uint16_t*)&u128)[7 - index]; }
auto u8(uint index) -> uint8_t& { return ((uint8_t*)&u128)[15 - index]; }
auto u8(uint index) const -> uint8_t { return ((uint8_t*)&u128)[15 - index]; }
auto i16(uint index) -> int16_t& { return ((int16_t*)&u128)[7 - index]; }
auto i16(uint index) const -> int16_t { return ((int16_t*)&u128)[7 - index]; }
auto u16(uint index) -> uint16_t& { return ((uint16_t*)&u128)[7 - index]; }
auto u16(uint index) const -> uint16_t { return ((uint16_t*)&u128)[7 - index]; }
//VCx registers
auto get(uint index) const -> bool { return u16(index) != 0; }
auto set(uint index, bool value) -> bool { return u16(index) = 0 - value, value; }
//vu-registers.cpp
auto operator()(uint index) const -> r128;
};
using cr128 = const r128;
struct COP2 {
v128 r[32];
v128 acch, accm, accl;
v128 vcoh, vcol; //16-bit little endian
v128 vcch, vccl; //16-bit little endian
v128 vce; // 8-bit little endian
r128 r[32];
r128 acch, accm, accl;
r128 vcoh, vcol; //16-bit little endian
r128 vcch, vccl; //16-bit little endian
r128 vce; // 8-bit little endian
i16 divin;
i16 divout;
bool divdp;
} vu;
//vu-registers.cpp
auto accumulatorGet(uint index) const -> u64;
auto accumulatorSet(uint index, u64 value) -> void;
auto accumulatorSaturate(uint index, bool slice, u16 negative, u16 positive) const -> u16;
u16 reciprocals[512];
u16 inverseSquareRoots[512];
static constexpr v128 zero{0};
static constexpr v128 invert{u128(0) - 1};
static constexpr r128 zero{0};
static constexpr r128 invert{u128(0) - 1};
//vu-instructions.cpp
auto instructionCFC2() -> void;
auto instructionCTC2() -> void;
auto instructionLBV() -> void;
auto instructionLDV() -> void;
auto instructionLFV() -> void;
auto instructionLHV() -> void;
auto instructionLLV() -> void;
auto instructionLPV() -> void;
auto instructionLQV() -> void;
auto instructionLRV() -> void;
auto instructionLSV() -> void;
auto instructionLTV() -> void;
auto instructionLUV() -> void;
auto instructionLWC2() -> void;
auto instructionLWV() -> void;
auto instructionMFC2() -> void;
auto instructionMTC2() -> void;
auto instructionSBV() -> void;
auto instructionSDV() -> void;
auto instructionSFV() -> void;
auto instructionSHV() -> void;
auto instructionSLV() -> void;
auto instructionSPV() -> void;
auto instructionSQV() -> void;
auto instructionSRV() -> void;
auto instructionSSV() -> void;
auto instructionSTV() -> void;
auto instructionSUV() -> void;
auto instructionSWC2() -> void;
auto instructionSWV() -> void;
auto instructionVABS() -> void;
auto instructionVADD() -> void;
auto instructionVADDC() -> void;
auto instructionVAND() -> void;
auto instructionVCL() -> void;
auto instructionVCH() -> void;
auto instructionVCR() -> void;
auto instructionVEQ() -> void;
auto instructionVGE() -> void;
auto instructionVLT() -> void;
auto instructionVMACF(bool) -> void;
auto instructionVMACQ() -> void;
auto instructionVMADH() -> void;
auto instructionVMADL() -> void;
auto instructionVMADM() -> void;
auto instructionVMADN() -> void;
auto instructionVMOV() -> void;
auto instructionVMRG() -> void;
auto instructionVMUDH() -> void;
auto instructionVMUDL() -> void;
auto instructionVMUDM() -> void;
auto instructionVMUDN() -> void;
auto instructionVMULF(bool) -> void;
auto instructionVMULQ() -> void;
auto instructionVNAND() -> void;
auto instructionVNE() -> void;
auto instructionCFC2(r32& rt, u8 rd) -> void;
auto instructionCTC2(cr32& rt, u8 rd) -> void;
auto instructionLBV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLDV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLFV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLHV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLLV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLPV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLQV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLRV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLSV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLTV(u8 vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLUV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionLWV(r128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionMFC2(r32& rt, cr128& vs, u8 e) -> void;
auto instructionMTC2(cr32& rt, r128& vs, u8 e) -> void;
auto instructionSBV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSDV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSFV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSHV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSLV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSPV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSQV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSRV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSSV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSTV(u8 vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSUV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionSWV(cr128& vt, u8 e, cr32& rs, i8 imm) -> void;
auto instructionVABS(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVADD(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVADDC(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVAND(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVCH(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVCL(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVCR(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVEQ(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVGE(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVLT(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
template<bool U>
auto instructionVMACF(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVMACQ(r128& vd) -> void;
auto instructionVMADH(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVMADL(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVMADM(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVMADN(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVMOV(r128& vd, u8 de, cr128& vt, u8 e) -> void;
auto instructionVMRG(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVMUDH(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVMUDL(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVMUDM(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVMUDN(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
template<bool U>
auto instructionVMULF(r128& rd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVMULQ(r128& rd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVNAND(r128& rd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVNE(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVNOP() -> void;
auto instructionVNOR() -> void;
auto instructionVNXOR() -> void;
auto instructionVOR() -> void;
auto instructionVRCP(bool) -> void;
auto instructionVRCPH() -> void;
auto instructionVRND(bool) -> void;
auto instructionVRSQ(bool) -> void;
auto instructionVRSQH() -> void;
auto instructionVSAR() -> void;
auto instructionVSUB() -> void;
auto instructionVSUBC() -> void;
auto instructionVXOR() -> void;
auto instructionVNOR(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVNXOR(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVOR(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
template<bool L>
auto instructionVRCP(r128& vd, u8 de, cr128& vt, u8 e) -> void;
auto instructionVRCPH(r128& vd, u8 de, cr128& vt, u8 e) -> void;
template<bool D>
auto instructionVRND(r128& vd, u8 vs, cr128& vt, u8 e) -> void;
template<bool L>
auto instructionVRSQ(r128& vd, u8 de, cr128& vt, u8 e) -> void;
auto instructionVRSQH(r128& vd, u8 de, cr128& vt, u8 e) -> void;
auto instructionVSAR(r128& vd, cr128& vs, u8 e) -> void;
auto instructionVSUB(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVSUBC(r128& vd, cr128& vs, cr128& vt, u8 e) -> void;
auto instructionVXOR(r128& rd, cr128& vs, cr128& vt, u8 e) -> void;
//};
+4
View File
@@ -1,3 +1,5 @@
#define rsp Nintendo64::rsp
auto RSP::Debugger::load(Node::Object parent) -> void {
tracer.instruction = parent->append<Node::Instruction>("Instruction", "RSP");
tracer.instruction->setAddressBits(12);
@@ -40,3 +42,5 @@ auto RSP::Debugger::io(string_view message) -> void {
tracer.io->notify(message);
}
}
#undef rsp
-177
View File
@@ -1,177 +0,0 @@
static const vector<string> registerNamesSCC = {
"SP_PBUS_ADDRESS",
"SP_DRAM_ADDRESS",
"SP_READ_LENGTH",
"SP_WRITE_LENGTH",
"SP_STATUS",
"SP_DMA_FULL",
"SP_DMA_BUSY",
"SP_SEMAPHORE",
};
auto RSP::readSCC(u32 address) -> u32 {
address = (address & 0x3ffff) >> 2;
uint32 data;
if(address == 0) {
//SP_PBUS_ADDRESS
data.bit( 0,11) = dma.memAddress;
data.bit(12) = dma.memSource;
}
if(address == 1) {
//SP_DRAM_ADDRESS
data.bit(0,23) = dma.dramAddress;
}
if(address == 2) {
//SP_READ_LENGTH
data.bit( 0,11) = dma.read.length;
data.bit(12,19) = dma.read.count;
data.bit(20,31) = dma.read.skip;
}
if(address == 3) {
//SP_WRITE_LENGTH
data.bit( 0,11) = dma.write.length;
data.bit(12,19) = dma.write.count;
data.bit(20,31) = dma.write.skip;
}
if(address == 4) {
//SP_STATUS
data.bit( 0) = status.halted;
data.bit( 1) = status.broken;
data.bit( 2) = dma.busy;
data.bit( 3) = dma.full;
data.bit( 4) = status.full;
data.bit( 5) = status.singleStep;
data.bit( 6) = status.interruptOnBreak;
data.bit( 7) = status.signal[0];
data.bit( 8) = status.signal[1];
data.bit( 9) = status.signal[2];
data.bit(10) = status.signal[3];
data.bit(11) = status.signal[4];
data.bit(12) = status.signal[5];
data.bit(13) = status.signal[6];
data.bit(14) = status.signal[7];
}
if(address == 5) {
//SP_DMA_FULL
data.bit(0) = dma.full;
}
if(address == 6) {
//SP_DMA_BUSY
data.bit(0) = dma.busy;
}
if(address == 7) {
//SP_SEMAPHORE
data.bit(0) = status.semaphore;
status.semaphore = 1;
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNamesSCC(address, "SP_UNKNOWN"), " => ", hex(data, 8L)});
}
return data;
}
auto RSP::writeSCC(u32 address, uint32 data) -> void {
address = (address & 0x3ffff) >> 2;
if(address == 0) {
//SP_PBUS_ADDRESS
dma.memAddress = data.bit( 0,11) & ~3;
dma.memSource = data.bit(12);
}
if(address == 1) {
//SP_DRAM_ADDRESS
dma.dramAddress = data.bit(0,23) & ~7;
}
if(address == 2) {
//SP_READ_LENGTH
dma.read.length = data.bit( 0,11);
dma.read.count = data.bit(12,19);
dma.read.skip = data.bit(20,31);
auto& memory = dma.memSource == 0 ? dmem : imem;
auto length = (dma.read.length | 7) + 1;
for(u32 count : range(dma.read.count + 1)) {
for(u32 offset = 0; offset < length; offset += 4) {
u32 data = rdram.ram.readWord(dma.dramAddress + offset);
memory.writeWord(dma.memAddress + offset, data);
}
dma.dramAddress += length + dma.read.skip;
dma.memAddress += length;
}
}
if(address == 3) {
//SP_WRITE_LENGTH
dma.write.length = data.bit( 0,11);
dma.write.count = data.bit(12,19);
dma.write.skip = data.bit(20,31);
auto& memory = dma.memSource == 0 ? dmem : imem;
auto length = (dma.write.length | 7) + 1;
for(u32 count : range(dma.write.count + 1)) {
for(u32 offset = 0; offset < length; offset += 4) {
u32 data = memory.readWord(dma.memAddress + offset);
rdram.ram.writeWord(dma.dramAddress + offset, data);
}
dma.dramAddress += length + dma.write.skip;
dma.memAddress += length;
}
}
if(address == 4) {
//SP_STATUS
if(data.bit( 0)) status.halted = 0;
if(data.bit( 1)) status.halted = 1;
if(data.bit( 2)) status.broken = 0;
if(data.bit( 3)) mi.lower(MI::IRQ::SP);
if(data.bit( 4)) mi.raise(MI::IRQ::SP);
if(data.bit( 5)) status.singleStep = 0;
if(data.bit( 6)) status.singleStep = 1;
if(data.bit( 7)) status.interruptOnBreak = 0;
if(data.bit( 8)) status.interruptOnBreak = 1;
if(data.bit( 9)) status.signal[0] = 0;
if(data.bit(10)) status.signal[0] = 1;
if(data.bit(11)) status.signal[1] = 0;
if(data.bit(12)) status.signal[1] = 1;
if(data.bit(13)) status.signal[2] = 0;
if(data.bit(14)) status.signal[2] = 1;
if(data.bit(15)) status.signal[3] = 0;
if(data.bit(16)) status.signal[3] = 1;
if(data.bit(17)) status.signal[4] = 0;
if(data.bit(18)) status.signal[4] = 1;
if(data.bit(19)) status.signal[5] = 0;
if(data.bit(20)) status.signal[5] = 1;
if(data.bit(21)) status.signal[6] = 0;
if(data.bit(22)) status.signal[6] = 1;
if(data.bit(23)) status.signal[7] = 0;
if(data.bit(24)) status.signal[7] = 1;
}
if(address == 5) {
//SP_DMA_FULL (read-only)
}
if(address == 6) {
//SP_DMA_BUSY (read-only)
}
if(address == 7) {
//SP_SEMAPHORE
if(!data.bit(0)) status.semaphore = 0;
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNamesSCC(address, "SP_UNKNOWN"), " <= ", hex(data, 8L)});
}
}
+191 -11
View File
@@ -1,36 +1,216 @@
static const vector<string> registerNames = {
static const vector<string> registerNamesSCC = {
"SP_PBUS_ADDRESS",
"SP_DRAM_ADDRESS",
"SP_READ_LENGTH",
"SP_WRITE_LENGTH",
"SP_STATUS",
"SP_DMA_FULL",
"SP_DMA_BUSY",
"SP_SEMAPHORE",
};
auto RSP::readWord(u32 address) -> u32 {
address = (address & 0x3ffff) >> 2;
uint32 data;
if(address == 0) {
//SP_PBUS_ADDRESS
data.bit( 0,11) = dma.memAddress;
data.bit(12) = dma.memSource;
}
if(address == 1) {
//SP_DRAM_ADDRESS
data.bit(0,23) = dma.dramAddress;
}
if(address == 2) {
//SP_READ_LENGTH
data.bit( 0,11) = dma.read.length;
data.bit(12,19) = dma.read.count;
data.bit(20,31) = dma.read.skip;
}
if(address == 3) {
//SP_WRITE_LENGTH
data.bit( 0,11) = dma.write.length;
data.bit(12,19) = dma.write.count;
data.bit(20,31) = dma.write.skip;
}
if(address == 4) {
//SP_STATUS
data.bit( 0) = status.halted;
data.bit( 1) = status.broken;
data.bit( 2) = dma.busy;
data.bit( 3) = dma.full;
data.bit( 4) = status.full;
data.bit( 5) = status.singleStep;
data.bit( 6) = status.interruptOnBreak;
data.bit( 7) = status.signal[0];
data.bit( 8) = status.signal[1];
data.bit( 9) = status.signal[2];
data.bit(10) = status.signal[3];
data.bit(11) = status.signal[4];
data.bit(12) = status.signal[5];
data.bit(13) = status.signal[6];
data.bit(14) = status.signal[7];
}
if(address == 5) {
//SP_DMA_FULL
data.bit(0) = dma.full;
}
if(address == 6) {
//SP_DMA_BUSY
data.bit(0) = dma.busy;
}
if(address == 7) {
//SP_SEMAPHORE
data.bit(0) = status.semaphore;
status.semaphore = 1;
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNamesSCC(address, "SP_UNKNOWN"), " => ", hex(data, 8L)});
}
return data;
}
auto RSP::writeWord(u32 address, u32 data_) -> void {
address = (address & 0x3ffff) >> 2;
uint32 data = data_;
if(address == 0) {
//SP_PBUS_ADDRESS
dma.memAddress = data.bit( 0,11) & ~3;
dma.memSource = data.bit(12);
}
if(address == 1) {
//SP_DRAM_ADDRESS
dma.dramAddress = data.bit(0,23) & ~7;
}
if(address == 2) {
//SP_READ_LENGTH
dma.read.length = data.bit( 0,11);
dma.read.count = data.bit(12,19);
dma.read.skip = data.bit(20,31);
auto target = dma.memSource == 0 ? 0x0400'0000 : 0x0400'1000;
auto length = (dma.read.length | 7) + 1;
for(u32 count : range(dma.read.count + 1)) {
for(u32 offset = 0; offset < length; offset += 4) {
u32 data = bus.readWord(dma.dramAddress + offset);
bus.writeWord(dma.memAddress + target + offset, data);
}
dma.dramAddress += length + dma.read.skip;
dma.memAddress += length;
}
}
if(address == 3) {
//SP_WRITE_LENGTH
dma.write.length = data.bit( 0,11);
dma.write.count = data.bit(12,19);
dma.write.skip = data.bit(20,31);
auto source = dma.memSource == 0 ? 0x0400'0000 : 0x0400'1000;
auto length = (dma.write.length | 7) + 1;
for(u32 count : range(dma.write.count + 1)) {
for(u32 offset = 0; offset < length; offset += 4) {
u32 data = bus.readWord(dma.memAddress + source + offset);
bus.writeWord(dma.dramAddress + offset, data);
}
dma.dramAddress += length + dma.write.skip;
dma.memAddress += length;
}
}
if(address == 4) {
//SP_STATUS
if(data.bit( 0)) status.halted = 0;
if(data.bit( 1)) status.halted = 1;
if(data.bit( 2)) status.broken = 0;
if(data.bit( 3)) mi.lower(MI::IRQ::SP);
if(data.bit( 4)) mi.raise(MI::IRQ::SP);
if(data.bit( 5)) status.singleStep = 0;
if(data.bit( 6)) status.singleStep = 1;
if(data.bit( 7)) status.interruptOnBreak = 0;
if(data.bit( 8)) status.interruptOnBreak = 1;
if(data.bit( 9)) status.signal[0] = 0;
if(data.bit(10)) status.signal[0] = 1;
if(data.bit(11)) status.signal[1] = 0;
if(data.bit(12)) status.signal[1] = 1;
if(data.bit(13)) status.signal[2] = 0;
if(data.bit(14)) status.signal[2] = 1;
if(data.bit(15)) status.signal[3] = 0;
if(data.bit(16)) status.signal[3] = 1;
if(data.bit(17)) status.signal[4] = 0;
if(data.bit(18)) status.signal[4] = 1;
if(data.bit(19)) status.signal[5] = 0;
if(data.bit(20)) status.signal[5] = 1;
if(data.bit(21)) status.signal[6] = 0;
if(data.bit(22)) status.signal[6] = 1;
if(data.bit(23)) status.signal[7] = 0;
if(data.bit(24)) status.signal[7] = 1;
}
if(address == 5) {
//SP_DMA_FULL (read-only)
}
if(address == 6) {
//SP_DMA_BUSY (read-only)
}
if(address == 7) {
//SP_SEMAPHORE
if(!data.bit(0)) status.semaphore = 0;
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNamesSCC(address, "SP_UNKNOWN"), " <= ", hex(data, 8L)});
}
}
static const vector<string> registerNamesIO = {
"SP_PC_REG",
"SP_IBIST",
};
auto RSP::readIO(u32 address) -> u32 {
auto RSP::Status::readWord(u32 address) -> u32 {
address = (address & 0x7ffff) >> 2;
uint32 data;
if(address == 0) {
//SP_PC_REG
data.bit(0,11) = core.pc;
data.bit(0,11) = self.core.pc;
}
if(address == 1) {
//SP_IBIST
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNames(address, "SP_UNKNOWN"), " => ", hex(data, 8L)});
if(self.debugger.tracer.io->enabled()) {
self.debugger.io({registerNamesIO(address, "SP_UNKNOWN"), " => ", hex(data, 8L)});
}
return data;
}
auto RSP::writeIO(u32 address, uint32 data) -> void {
auto RSP::Status::writeWord(u32 address, u32 data_) -> void {
address = (address & 0x7ffff) >> 2;
uint32 data = data_;
if(address == 0) {
//SP_PC_REG
if(branch.state == Branch::Take) {
branch.pc = data.bit(0,11) & ~3;
if(self.branch.state == Branch::Take) {
self.branch.pc = data.bit(0,11) & ~3;
} else {
core.pc = data.bit(0,11) & ~3;
self.core.pc = data.bit(0,11) & ~3;
}
}
@@ -38,7 +218,7 @@ auto RSP::writeIO(u32 address, uint32 data) -> void {
//SP_IBIST
}
if(debugger.tracer.io->enabled()) {
debugger.io({registerNames(address, "SP_UNKNOWN"), " <= ", hex(data, 8L)});
if(self.debugger.tracer.io->enabled()) {
self.debugger.io({registerNamesIO(address, "SP_UNKNOWN"), " <= ", hex(data, 8L)});
}
}
+7 -3
View File
@@ -5,7 +5,6 @@ namespace ares::Nintendo64 {
RSP rsp;
#include "core/core.cpp"
#include "io.cpp"
#include "io-scc.cpp"
#include "debugger.cpp"
#include "serialization.cpp"
@@ -26,7 +25,6 @@ auto RSP::unload() -> void {
auto RSP::main() -> void {
if(status.halted) return step(96);
instruction();
step(3);
}
auto RSP::step(uint clocks) -> void {
@@ -37,7 +35,13 @@ auto RSP::power() -> void {
Thread::reset();
powerCore();
dma = {};
status = {};
status.semaphore = 0;
status.halted = 1;
status.broken = 0;
status.full = 0;
status.singleStep = 0;
status.interruptOnBreak = 0;
for(auto& signal : status.signal) signal = 0;
}
}
+21 -18
View File
@@ -1,9 +1,9 @@
//Reality Signal Processor
struct RSP : Thread {
struct RSP : Thread, Memory::IO<RSP> {
Node::Component node;
Memory dmem;
Memory imem;
Memory::Writable dmem;
Memory::Writable imem;
struct Debugger {
//debugger.cpp
@@ -32,12 +32,8 @@ struct RSP : Thread {
auto power() -> void;
//io.cpp
auto readIO(u32 address) -> u32;
auto writeIO(u32 address, uint32 data) -> void;
//io-scc.cpp
auto readSCC(u32 address) -> u32;
auto writeSCC(u32 address, uint32 data) -> void;
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
@@ -56,15 +52,22 @@ struct RSP : Thread {
} read, write;
} dma;
struct Status {
uint1 semaphore = 0;
uint1 halted = 1;
uint1 broken = 0;
uint1 full = 0;
uint1 singleStep = 0;
uint1 interruptOnBreak = 0;
uint1 signal[8] = {};
} status;
struct Status : Memory::IO<Status> {
RSP& self;
Status(RSP& self) : self(self) {}
//io.cpp
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
uint1 semaphore = 0;
uint1 halted = 1;
uint1 broken = 0;
uint1 full = 0;
uint1 singleStep = 0;
uint1 interruptOnBreak = 0;
uint1 signal[8] = {};
} status{*this};
#include "core/core.hpp"
};
+3 -2
View File
@@ -8,7 +8,7 @@ static const vector<string> registerNames = {
"SI_STATUS",
};
auto SI::readIO(u32 address) -> u32 {
auto SI::readWord(u32 address) -> u32 {
address = (address & 0xfffff) >> 2;
uint32 data;
@@ -56,8 +56,9 @@ auto SI::readIO(u32 address) -> u32 {
return data;
}
auto SI::writeIO(u32 address, uint32 data) -> void {
auto SI::writeWord(u32 address, u32 data_) -> void {
address = (address & 0xfffff) >> 2;
uint32 data = data_;
if(address == 0) {
//SI_DRAM_ADDRESS
+3 -3
View File
@@ -1,6 +1,6 @@
//Serial Interface
struct SI {
struct SI : Memory::IO<SI> {
Node::Component node;
struct Debugger {
@@ -20,8 +20,8 @@ struct SI {
auto power() -> void;
//io.cpp
auto readIO(u32 address) -> u32;
auto writeIO(u32 address, uint32 data) -> void;
auto readWord(u32 address) -> u32;
auto writeWord(u32 address, u32 data) -> void;
//serialization.cpp
auto serialize(serializer&) -> void;
+1
View File
@@ -60,6 +60,7 @@ auto System::serializeAll(serializer& s, bool synchronize) -> void {
controllerPort2.serialize(s);
controllerPort3.serialize(s);
controllerPort4.serialize(s);
dd.serialize(s);
}
auto System::serializeInit(bool synchronize) -> uint {
+3
View File
@@ -43,6 +43,7 @@ auto System::load(Node::Object& root) -> void {
controllerPort2.load(node);
controllerPort3.load(node);
controllerPort4.load(node);
dd.load(node);
}
auto System::unload() -> void {
@@ -63,6 +64,7 @@ auto System::unload() -> void {
controllerPort2.unload();
controllerPort3.unload();
controllerPort4.unload();
dd.unload();
node.reset();
}
@@ -89,6 +91,7 @@ auto System::power(bool reset) -> void {
}
cartridge.power();
dd.power(reset);
mi.power();
vi.power();
ai.power();
Loaded 100 of 275 files, more files were not shown because too many files have changed in this diff. Show more