diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..a8b7ed028
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,9 @@
+# Other data.
+/data
+
+# Build files.
+/build
+
+# Swap files.
+*.swp
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 000000000..d5e9ff82b
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,35 @@
+#
+# CEN64: Cycle-Accurate Nintendo 64 Simulator.
+# Copyright (C) 2014, Tyler J. Stachecki.
+#
+# This file is subject to the terms and conditions defined in
+# 'LICENSE', which is part of this source code package.
+#
+
+cmake_minimum_required(VERSION 2.6)
+project(cen64)
+
+if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU")
+ set(CMAKE_C_FLAGS "-Wall -Wextra -std=c99 -D_POSIX_SOURCE")
+
+ set(CMAKE_C_FLAGS_DEBUG "-ggdb3 -g3 -O0")
+ set(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG")
+ set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Og")
+endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU")
+
+include_directories(${PROJECT_SOURCE_DIR})
+include_directories(${PROJECT_SOURCE_DIR}/bus)
+include_directories(${PROJECT_SOURCE_DIR}/pif)
+include_directories(${PROJECT_SOURCE_DIR}/vr4300)
+
+# Glob all the files together.
+file(GLOB BUS_SOURCES ${PROJECT_SOURCE_DIR}/bus/*.c)
+file(GLOB CEN64_SOURCES ${PROJECT_SOURCE_DIR}/*.c)
+file(GLOB PIF_SOURCES ${PROJECT_SOURCE_DIR}/pif/*.c)
+file(GLOB VR4300_SOURCES ${PROJECT_SOURCE_DIR}/vr4300/*.c)
+
+# Create the executable.
+add_executable(cen64 ${CEN64_SOURCES} ${BUS_SOURCES} ${PIF_SOURCES}
+ ${VR4300_SOURCES})
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..ec0ac4f88
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2014, Tyler J. Stachecki
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Tyler J. Stachecki nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL TYLER J. STACHECKI BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..a3c5548ab
--- /dev/null
+++ b/README.md
@@ -0,0 +1,31 @@
+
+
+
+
+# About
+
+This is my pet project. It's something I pick up whenever I get bored. To me,
+what Nintendo and SGI did with this console is nothing short of amazing. The
+ingenuity and design of the hardware was well-ahead of it's time, and it is
+an absolute blast to reverse-engineer and study. I started this project in
+order to learn more about what _really_ went on at the hardware level back in
+the (good old) days.
+
+That being said, I've also grown tired of people complaining that "cycle
+accurate simulation on N-gen consoles is impossible." Not to be a bigot, but
+no, it's not. Is it hard to write a simulator that is capable of running fast
+enough to emulate a 93.75MHz processor on modern machines? Absolutely. Is it
+impossible? No, certainly not. It just takes time. Programming is an art,
+and like anything else, it takes time if done well.
+
+Getting back on track: this simulator attempts to be everything that every
+other emulator hoped to be, but never quite attained due to... emulation. My
+hopes are that properly simulating things at the cycle and pixel-accurate level
+will preserve the original fidelity of the work that so many companies put
+out.
+
+Thank you to every single one of you developers for filling my childhood
+with excellent memories. I'd also like to thank the community on all their
+hard work and effort spent reverse-engineering this little gem. Without
+further ado...
+
diff --git a/VERSION b/VERSION
new file mode 100644
index 000000000..be5863417
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.3
diff --git a/assets/logo-small.png b/assets/logo-small.png
new file mode 100644
index 000000000..307f27693
Binary files /dev/null and b/assets/logo-small.png differ
diff --git a/assets/logo.png b/assets/logo.png
new file mode 100644
index 000000000..1b1189de5
Binary files /dev/null and b/assets/logo.png differ
diff --git a/bus/controller.c b/bus/controller.c
new file mode 100644
index 000000000..bbdb43626
--- /dev/null
+++ b/bus/controller.c
@@ -0,0 +1,36 @@
+//
+// bus/controller.c: System bus controller.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "bus/controller.h"
+#include "pif/controller.h"
+
+// Initializes the bus component.
+int bus_init(struct bus_controller *bus) {
+ bus->num_requests = 0;
+ bus->rq_head = 0;
+ bus->rq_tail = 0;
+
+ return 0;
+}
+
+// Issues a read request to the bus.
+unsigned bus_read_word(struct bus_controller *bus,
+ uint32_t address, uint32_t *word) {
+
+ if (address >= 0x1FC00000 && address < 0x1FC07C00)
+ return read_pifrom(bus->pif, word, address & 0xFFC);
+
+ printf("bus_read_word: Failed to access: 0x%.8X\n", address);
+ abort();
+
+ return 0;
+}
+
diff --git a/bus/controller.h b/bus/controller.h
new file mode 100644
index 000000000..d8d55dbc0
--- /dev/null
+++ b/bus/controller.h
@@ -0,0 +1,31 @@
+//
+// bus/controller.h: System bus controller.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __bus_controller_h__
+#define __bus_controller_h__
+#define BUS_REQUEST_QUEUE_SIZE 8
+
+struct bus_request;
+struct vr4300;
+
+struct bus_controller {
+ struct bus_request *rq[BUS_REQUEST_QUEUE_SIZE];
+ unsigned num_requests, rq_head, rq_tail;
+
+ struct pif_controller *pif;
+ struct vr4300 *vr4300;
+};
+
+int bus_init(struct bus_controller *bus);
+unsigned bus_read_word(struct bus_controller *bus,
+ uint32_t address, uint32_t *word);
+
+#endif
+
diff --git a/cen64.c b/cen64.c
new file mode 100644
index 000000000..0b88e3234
--- /dev/null
+++ b/cen64.c
@@ -0,0 +1,32 @@
+//
+// cen64.c: CEN64 entry point.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "device.h"
+
+int main(int argc, const char *argv[]) {
+ struct cen64_device *device;
+
+ if (argc < 2) {
+ printf("%s \n", argv[0]);
+ return 0;
+ }
+
+ if ((device = device_create(argv[1])) == NULL) {
+ printf("Failed to create a device.\n");
+ return 1;
+ }
+
+ device_run(device);
+
+ device_destroy(device);
+ return 0;
+}
+
diff --git a/common.h b/common.h
new file mode 100644
index 000000000..1b3a0aed9
--- /dev/null
+++ b/common.h
@@ -0,0 +1,86 @@
+//
+// common.h: Common definitions and such.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __common_h__
+#define __common_h__
+
+#ifdef _MSC_VER
+#define inline _inline
+#endif
+
+#ifndef __cplusplus
+#include
+#include
+#include
+#include
+#include
+#include
+#else
+#include
+#include
+#include
+#include
+#include
+#include
+#endif
+
+#ifndef _MSC_VER
+#ifndef __cplusplus
+#include
+#else
+#include
+#endif
+
+#else
+typedef char bool;
+#define false 0
+#define true 1
+#endif
+
+#ifndef NDEBUG
+#ifndef __cplusplus
+#include
+#else
+#include
+#endif
+#endif
+
+#define CACHE_LINE_SIZE 64
+
+// Define cen64_align().
+#ifdef _MSC_VER
+#define cen64_align(decl, value) __declspec(align(value)) decl
+
+#elif (defined __GNUC__)
+#define cen64_align(decl, value) decl __attribute__ ((aligned(value)))
+
+#else
+#define cen64_align(decl, value) decl value
+#endif
+
+// Define likely()/unlikely().
+#ifdef __GNUC__
+#define likely(expr) __builtin_expect(!!(expr), !0)
+#define unlikely(expr) __builtin_expect(!!(expr), 0)
+
+#else
+#define likely(expr) expr
+#define unlikely(expr) expr
+#endif
+
+// Define unused().
+#ifdef __GNUC__
+#define unused(decl) __attribute__((unused)) decl
+#else
+#define unused(decl) decl
+#endif
+
+#endif
+
diff --git a/device.c b/device.c
new file mode 100644
index 000000000..2a8cfa2a0
--- /dev/null
+++ b/device.c
@@ -0,0 +1,97 @@
+//
+// device.c: CEN64 device container.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "device.h"
+#include "pif/controller.h"
+
+// Loads the PIFROM from a file into memory.
+static int load_pifrom(const char *file, uint8_t *rom) {
+ int status = 0;
+ size_t i, last;
+ FILE *f;
+
+ if ((f = fopen(file, "rb")) == NULL) {
+ printf("load_pifrom: Failed to open: %s\n", file);
+ return -1;
+ }
+
+ for (i = 0; i < PIFROM_SIZE; i += last) {
+ last = fread(rom + i, 1, PIFROM_SIZE - i, f);
+
+ if (feof(f)) {
+ printf("load_pifrom: ROM file is smaller than expected.\n");
+ status = -1;
+ break;
+ }
+
+ else if (ferror(f)) {
+ printf("load_pifrom: An error occured while reading the ROM.\n");
+ status = -2;
+ break;
+ }
+ }
+
+ fclose(f);
+ return status;
+}
+
+// Creates and initializes a device.
+struct cen64_device *device_create(const char *pifrom) {
+ struct cen64_device *device;
+
+ // Allocate memory.
+ if ((device = (struct cen64_device*) malloc(sizeof(*device))) == NULL)
+ return NULL;
+
+ // Initialize the PIF.
+ if (load_pifrom(pifrom, device->pifrom) < 0 ||
+ init_pif(&device->pif, &device->bus, device->pifrom)) {
+ printf("create_device: Failed to initialize the PIF.\n");
+
+ free(device);
+ return NULL;
+ }
+
+ // Initialize the bus.
+ if (bus_init(&device->bus)) {
+ printf("create_device: Failed to initialize the bus.\n");
+
+ free(device);
+ return NULL;
+ }
+
+ device->bus.pif = &device->pif;
+ device->bus.vr4300 = &device->vr4300;
+
+ // Initialize the VR4300.
+ if (vr4300_init(&device->vr4300, &device->bus)) {
+ printf("create_device: Failed to initialize the VR4300.\n");
+
+ free(device);
+ return NULL;
+ }
+
+ return device;
+}
+
+// Deallocates and cleans up a device.
+void device_destroy(struct cen64_device *device) {
+ free(device);
+}
+
+// Kicks off threads and starts the device.
+void device_run(struct cen64_device *device) {
+ unsigned i;
+
+ for (i = 0; i < 93750000; i++)
+ vr4300_cycle(&device->vr4300);
+}
+
diff --git a/device.h b/device.h
new file mode 100644
index 000000000..0a252ad82
--- /dev/null
+++ b/device.h
@@ -0,0 +1,34 @@
+//
+// device.h: CEN64 device container.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __device_h__
+#define __device_h__
+#include "common.h"
+#include "bus/controller.h"
+#include "pif/controller.h"
+#include "vr4300/cpu.h"
+
+#define PIFROM_SIZE 2048
+
+struct cen64_device {
+ struct bus_controller bus;
+ struct pif_controller pif;
+ struct vr4300 vr4300;
+
+ uint8_t pifrom[PIFROM_SIZE];
+};
+
+struct cen64_device *device_create(const char *pifrom);
+void device_destroy(struct cen64_device *device);
+
+void device_run(struct cen64_device *device);
+
+#endif
+
diff --git a/pif/controller.c b/pif/controller.c
new file mode 100644
index 000000000..f01c5956e
--- /dev/null
+++ b/pif/controller.c
@@ -0,0 +1,31 @@
+//
+// pif/controller.c: Peripheral interface controller.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "bus/controller.h"
+#include "pif/controller.h"
+
+// Initializes the PIF.
+int init_pif(struct pif_controller *pif,
+ struct bus_controller *bus, const uint8_t *rom) {
+ pif->bus = bus;
+ pif->rom = rom;
+
+ return 0;
+}
+
+// Reads a word from PIFROM.
+int read_pifrom(struct pif_controller *pif, uint32_t *word, unsigned off) {
+ assert((off & 0x3) == 0 && "read_pifrom: Offset not word aligned.");
+
+ memcpy(word, pif->rom + off, sizeof(*word));
+ return 0;
+}
+
diff --git a/pif/controller.h b/pif/controller.h
new file mode 100644
index 000000000..16b51cdb0
--- /dev/null
+++ b/pif/controller.h
@@ -0,0 +1,28 @@
+//
+// pif/controller.h: Peripheral interface controller.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __pif_controller_h__
+#define __pif_controller_h__
+#include "common.h"
+
+struct bus_controller *bus;
+
+struct pif_controller {
+ struct bus_controller *bus;
+ const uint8_t *rom;
+};
+
+int init_pif(struct pif_controller *pif,
+ struct bus_controller *bus, const uint8_t *rom);
+
+int read_pifrom(struct pif_controller *pif, uint32_t *word, unsigned off);
+
+#endif
+
diff --git a/vr4300/cp0.c b/vr4300/cp0.c
new file mode 100644
index 000000000..fe4ac91e6
--- /dev/null
+++ b/vr4300/cp0.c
@@ -0,0 +1,18 @@
+//
+// vr4300/cp0.c: VR4300 system control coprocessor.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "vr4300/cp0.h"
+
+// Initializes the coprocessor.
+void vr4300_cp0_init(struct vr4300_cp0 *cp0) {
+ memset(cp0, 0, sizeof(*cp0));
+}
+
diff --git a/vr4300/cp0.h b/vr4300/cp0.h
new file mode 100644
index 000000000..1b668e172
--- /dev/null
+++ b/vr4300/cp0.h
@@ -0,0 +1,52 @@
+//
+// vr4300/cp0.h: VR4300 system control coprocessor.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __vr4300_cp0_h__
+#define __vr4300_cp0_h__
+#include "common.h"
+
+// Registers list.
+enum vr4300_cp0_register {
+ VR4300_CP0_REGISTER_INDEX,
+ VR4300_CP0_REGISTER_RANDOM,
+ VR4300_CP0_REGISTER_ENTRYLO0,
+ VR4300_CP0_REGISTER_ENTRYLO1,
+ VR4300_CP0_REGISTER_CONTEXT,
+ VR4300_CP0_REGISTER_PAGEMASK,
+ VR4300_CP0_REGISTER_WIRED,
+ VR4300_CP0_REGISTER_BADVADDR = 8,
+ VR4300_CP0_REGISTER_COUNT,
+ VR4300_CP0_REGISTER_ENTRYHI,
+ VR4300_CP0_REGISTER_COMPARE,
+ VR4300_CP0_REGISTER_STATUS,
+ VR4300_CP0_REGISTER_CAUSE,
+ VR4300_CP0_REGISTER_EPC,
+ VR4300_CP0_REGISTER_PRID,
+ VR4300_CP0_REGISTER_CONFIG,
+ VR4300_CP0_REGISTER_LLADDR,
+ VR4300_CP0_REGISTER_WATCHLO,
+ VR4300_CP0_REGISTER_WATCHHI,
+ VR4300_CP0_REGISTER_XCONTEXT,
+ VR4300_CP0_REGISTER_PARITYERROR = 26,
+ VR4300_CP0_REGISTER_CACHEERR,
+ VR4300_CP0_REGISTER_TAGLO,
+ VR4300_CP0_REGISTER_TAGHI,
+ VR4300_CP0_REGISTER_ERROREPC,
+ NUM_VR4300_CP0_REGISTERS = 32,
+};
+
+struct vr4300_cp0 {
+ uint64_t regs[NUM_VR4300_CP0_REGISTERS];
+};
+
+void vr4300_cp0_init(struct vr4300_cp0 *cp0);
+
+#endif
+
diff --git a/vr4300/cpu.c b/vr4300/cpu.c
new file mode 100644
index 000000000..e4327692f
--- /dev/null
+++ b/vr4300/cpu.c
@@ -0,0 +1,34 @@
+//
+// vr4300/cpu.c: VR4300 processor container.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "vr4300/cp0.h"
+#include "vr4300/cpu.h"
+#include "vr4300/icache.h"
+#include "vr4300/pipeline.h"
+
+// Sets the opaque pointer used for external accesses.
+static void vr4300_connect_bus(struct vr4300 *vr4300,
+ struct bus_controller *bus) {
+ vr4300->bus = bus;
+}
+
+// Initializes the VR4300 component.
+int vr4300_init(struct vr4300 *vr4300, struct bus_controller *bus) {
+ vr4300_connect_bus(vr4300, bus);
+
+ vr4300_cp0_init(&vr4300->cp0);
+ vr4300_icache_init(&vr4300->icache);
+ vr4300_pipeline_init(&vr4300->pipeline);
+
+ vr4300->signals = VR4300_SIGNAL_COLDRESET;
+ return 0;
+}
+
diff --git a/vr4300/cpu.h b/vr4300/cpu.h
new file mode 100644
index 000000000..17927a03a
--- /dev/null
+++ b/vr4300/cpu.h
@@ -0,0 +1,55 @@
+//
+// vr4300/cpu.h: VR4300 processor container.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __vr4300_cpu_h__
+#define __vr4300_cpu_h__
+#include "common.h"
+#include "vr4300/cp0.h"
+#include "vr4300/icache.h"
+#include "vr4300/pipeline.h"
+
+struct bus_controller;
+
+enum vr4300_signals {
+ VR4300_SIGNAL_FORCEEXIT = 0x000000001,
+ VR4300_SIGNAL_COLDRESET = 0x000000002,
+};
+
+enum vr4300_register {
+ VR4300_REGISTER_R0, VR4300_REGISTER_AT, VR4300_REGISTER_V0,
+ VR4300_REGISTER_V1, VR4300_REGISTER_A0, VR4300_REGISTER_A1,
+ VR4300_REGISTER_A2, VR4300_REGISTER_A3, VR4300_REGISTER_T0,
+ VR4300_REGISTER_T1, VR4300_REGISTER_T2, VR4300_REGISTER_T3,
+ VR4300_REGISTER_T4, VR4300_REGISTER_R5, VR4300_REGISTER_T6,
+ VR4300_REGISTER_T7, VR4300_REGISTER_S0, VR4300_REGISTER_S1,
+ VR4300_REGISTER_S2, VR4300_REGISTER_S3, VR4300_REGISTER_S4,
+ VR4300_REGISTER_S5, VR4300_REGISTER_S6, VR4300_REGISTER_S7,
+ VR4300_REGISTER_T8, VR4300_REGISTER_T9, VR4300_REGISTER_K0,
+ VR4300_REGISTER_K1, VR4300_REGISTER_GP, VR4300_REGISTER_SP,
+ VR4300_REGISTER_FP, VR4300_REGISTER_RA, VR4300_REGISTER_LO,
+ VR4300_REGISTER_HI, NUM_VR4300_REGISTERS
+};
+
+struct vr4300 {
+ uint64_t regs[NUM_VR4300_REGISTERS];
+
+ struct vr4300_cp0 cp0;
+ struct vr4300_icache icache;
+ struct vr4300_pipeline pipeline;
+
+ struct bus_controller *bus;
+ unsigned signals;
+};
+
+void vr4300_cycle(struct vr4300 *vr4300);
+int vr4300_init(struct vr4300 *vr4300, struct bus_controller *bus);
+
+#endif
+
diff --git a/vr4300/decoder.c b/vr4300/decoder.c
new file mode 100644
index 000000000..bea73a3d9
--- /dev/null
+++ b/vr4300/decoder.c
@@ -0,0 +1,255 @@
+//
+// vr4300/decoder.c: VR4300 decoder.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "vr4300/decoder.h"
+#include "vr4300/opcodes.h"
+
+// ============================================================================
+// Escaped opcode table: Special.
+//
+// 31---------26------------------------------------------5--------0
+// | SPECIAL/6 | | FMT/6 |
+// ------6----------------------------------------------------6-----
+// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--|
+// 000 | SLL | | SRL | SRA | SLLV | | SRLV | SRAV |
+// 001 | JR | JALR | | |SYSCALL| BREAK | | SYNC |
+// 010 | MFHI | MTHI | MFLO | MTLO | DSLLV | | DSRLV | DSRAV |
+// 011 | MULT | MULTU | DIV | DIVU | DMULT | DMULTU| DDIV | DDIVU |
+// 100 | ADD | ADDU | SUB | SUBU | AND | OR | XOR | NOR |
+// 101 | | | SLT | SLTU | DADD | DADDU | DSUB | DSUBU |
+// 110 | TGE | TGEU | TLT | TLTU | TEQ | | TNE | |
+// 111 | DSLL | | DSRL | DSRA |DSLL32 | |DSRL32 |DSRA32 |
+// |-------|-------|-------|-------|-------|-------|-------|-------|
+//
+// ============================================================================
+cen64_align(static const struct vr4300_opcode
+ vr4300_spec_opcode_table[64], CACHE_LINE_SIZE) = {
+ {SLL}, {INVALID}, {SRL}, {SRA},
+ {SLLV}, {INVALID}, {SRLV}, {SRAV},
+ {JR}, {JALR}, {INVALID}, {INVALID},
+ {SYSCALL}, {BREAK}, {INVALID}, {SYNC},
+ {MFHI}, {MTHI}, {MFLO}, {MTLO},
+ {DSLLV}, {INVALID}, {DSRLV}, {DSRAV},
+ {MULT}, {MULTU}, {DIV}, {DIVU},
+ {DMULT}, {DMULTU}, {DDIV}, {DDIVU},
+ {ADD}, {ADDU}, {SUB}, {SUBU},
+ {AND}, {OR}, {XOR}, {NOR},
+ {INVALID}, {INVALID}, {SLT}, {SLTU},
+ {DADD}, {DADDU}, {DSUB}, {DSUBU},
+ {TGE}, {TGEU}, {TLT}, {TLTU},
+ {TEQ}, {INVALID}, {TNE}, {INVALID},
+ {DSLL}, {INVALID}, {DSRL}, {DSRA},
+ {DSLL32}, {INVALID}, {DSRL32}, {DSRA32}
+};
+
+// ============================================================================
+// Escaped opcode table: RegImm.
+//
+// 31---------26----------20-------16------------------------------0
+// | = REGIMM | | FMT/5 | |
+// ------6---------------------5------------------------------------
+// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--|
+// 00 | BLTZ | BGEZ | BLTZL | BGEZL | | | | |
+// 01 | TGEI | TGEIU | TLTI | TLTIU | TEQI | | TNEI | |
+// 10 | BLTZAL| BGEZAL|BLTZALL|BGEZALL| | | | |
+// 11 | | | | | | | | |
+// |-------|-------|-------|-------|-------|-------|-------|-------|
+//
+// ============================================================================
+cen64_align(static const struct vr4300_opcode
+ vr4300_regimm_opcode_table[32], CACHE_LINE_SIZE) = {
+ {BLTZ}, {BGEZ}, {BLTZL}, {BGEZL},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {TGEI}, {TGEIU}, {TLTI}, {TLTIU},
+ {TEQI}, {INVALID}, {TNEI}, {INVALID},
+ {BLTZAL}, {BGEZAL}, {BLTZALL}, {BGEZALL},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID}
+};
+
+// ============================================================================
+// Escaped opcode table: COP0.
+//
+// 31--------26-25------21 ----------------------------------------0
+// | COP0/6 | FMT/5 | |
+// ------6----------5-----------------------------------------------
+// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--|
+// 00 | MFC0 | DMFC0 | CFC0 | --- | MTC0 | DMTC0 | CTC0 | --- |
+// 01 | BC0 | --- | --- | --- | --- | --- | --- | --- |
+// 10 | TLB | --- | --- | --- | --- | --- | --- | --- |
+// 11 | --- | --- | --- | --- | --- | --- | --- | --- |
+// |-------|-------|-------|-------|-------|-------|-------|-------|
+// ============================================================================
+cen64_align(static const struct vr4300_opcode
+ vr4300_cop0_opcode_table[32], CACHE_LINE_SIZE) = {
+ {MFC0}, {DMFC0}, {CFC0}, {INVALID},
+ {MTC0}, {DMTC0}, {CTC0}, {INVALID},
+ {BC0}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {TLB}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID}
+};
+
+// ============================================================================
+// Escaped opcode table: COP1.
+//
+// 31--------26-25------21 ----------------------------------------0
+// | COP1/6 | FMT/5 | |
+// ------6----------5-----------------------------------------------
+// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--|
+// 00 | MFC1 | DMFC1 | CFC1 | --- | MTC1 | DMTC1 | CTC1 | --- |
+// 01 | BC1 | --- | --- | --- | --- | --- | --- | --- |
+// 10 | FPUS | FPUD | --- | --- | FPUW | FPUL | --- | --- |
+// 11 | --- | --- | --- | --- | --- | --- | --- | --- |
+// |-------|-------|-------|-------|-------|-------|-------|-------|
+// ============================================================================
+cen64_align(static const struct vr4300_opcode
+ vr4300_cop1_opcode_table[32], CACHE_LINE_SIZE) = {
+ {MFC1}, {DMFC1}, {CFC1}, {INVALID},
+ {MTC1}, {DMTC1}, {CTC1}, {INVALID},
+ {BC1}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {FPUS}, {FPUD}, {INVALID}, {INVALID},
+ {FPUW}, {FPUL}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID}
+};
+
+// ============================================================================
+// Escaped opcode table: COP2.
+//
+// 31--------26-25------21 ----------------------------------------0
+// | COP2/6 | FMT/5 | |
+// ------6----------5-----------------------------------------------
+// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--|
+// 00 | MFC2 | DMFC2 | CFC2 | --- | MTC2 | DMTC2 | CTC2 | --- |
+// 01 | BC2 | --- | --- | --- | --- | --- | --- | --- |
+// 10 | --- | --- | --- | --- | --- | --- | --- | --- |
+// 11 | --- | --- | --- | --- | --- | --- | --- | --- |
+// |-------|-------|-------|-------|-------|-------|-------|-------|
+//
+// ============================================================================
+cen64_align(static const struct vr4300_opcode
+ vr4300_cop2_opcode_table[32], CACHE_LINE_SIZE) = {
+ {MFC2}, {DMFC2}, {CFC2}, {INVALID},
+ {MTC2}, {DMTC2}, {CTC2}, {INVALID},
+ {BC2}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID}
+};
+
+// ============================================================================
+// First-order opcode table.
+//
+// 0b000000 => Lookup in vr4300_spec_opcode_table.
+// 0b000001 => Lookup in vr4300_regimm_opcode_table.
+// 0b010000 => Lookup in vr4300_cop0_opcode_table.
+// 0b010001 => Lookup in vr4300_cop0_opcode_table.
+// 0b010010 => Lookup in vr4300_cop2_opcode_table.
+//
+// 31---------26---------------------------------------------------0
+// | OPCODE/6 | |
+// ------6----------------------------------------------------------
+// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--|
+// 000 | *SPEC | *RGIM | J | JAL | BEQ | BNE | BLEZ | BGTZ |
+// 001 | ADDI | ADDIU | SLTI | SLTIU | ANDI | ORI | XORI | LUI |
+// 010 | *COP0 | *COP1 | *COP2 | | BEQL | BNEL | BLEZL | BGTZL |
+// 011 | DADDI |DADDIU | LDL | LDR | | | | |
+// 100 | LB | LH | LWL | LW | LBU | LHU | LWR | LWU |
+// 101 | SB | SH | SWL | SW | SDL | SDR | SWR | CACHE |
+// 110 | LL | LWC1 | LWC2 | | LLD | LDC1 | LDC2 | LD |
+// 111 | SC | SWC1 | SWC2 | | SCD | SDC1 | SDC2 | SD |
+// |-------|-------|-------|-------|-------|-------|-------|-------|
+//
+// ============================================================================
+cen64_align(static const struct vr4300_opcode
+ vr4300_opcode_table[64], CACHE_LINE_SIZE) = {
+ {INVALID}, {INVALID}, {J}, {JAL},
+ {BEQ}, {BNE}, {BLEZ}, {BGTZ},
+ {ADDI}, {ADDIU}, {SLTI}, {SLTIU},
+ {ANDI}, {ORI}, {XORI}, {LUI},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {BEQL}, {BNEL}, {BLEZL}, {BGTZL},
+ {DADDI}, {DADDIU}, {LDL}, {LDR},
+ {INVALID}, {INVALID}, {INVALID}, {INVALID},
+ {LB}, {LH}, {LWL}, {LW},
+ {LBU}, {LHU}, {LWR}, {LWU},
+ {SB}, {SH}, {SWL}, {SW},
+ {SDL}, {SDR}, {SWR}, {CACHE},
+ {LL}, {LWC1}, {LWC2}, {INVALID},
+ {LLD}, {LDC1}, {LDC2}, {LD},
+ {SC}, {SWC1}, {SWC2}, {INVALID},
+ {SCD}, {SDC1}, {SDC2}, {SD}
+};
+
+// Escaped table listings. Most of these will never
+// see a processor cache line, so not much waste here.
+struct vr4300_opcode_escape {
+ const struct vr4300_opcode *table;
+ unsigned shift, mask;
+};
+
+cen64_align(static const struct vr4300_opcode_escape
+ vr4300_escape_table[64], CACHE_LINE_SIZE) = {
+ {vr4300_spec_opcode_table, 0, 0x3F}, {vr4300_regimm_opcode_table, 16, 0x1F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+
+ {vr4300_cop0_opcode_table, 21, 0x1F}, {vr4300_cop1_opcode_table, 21, 0x1F},
+ {vr4300_cop2_opcode_table, 21, 0x1F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+ {vr4300_opcode_table, 26, 0x3F}, {vr4300_opcode_table, 26, 0x3F},
+};
+
+// Decodes an instruction word.
+const struct vr4300_opcode* vr4300_decode_instruction(uint32_t iw) {
+ const struct vr4300_opcode_escape *escape = vr4300_escape_table + (iw >> 26);
+ unsigned index = iw >> escape->shift & escape->mask;
+ return escape->table + index;
+}
+
diff --git a/vr4300/decoder.h b/vr4300/decoder.h
new file mode 100644
index 000000000..0749f1955
--- /dev/null
+++ b/vr4300/decoder.h
@@ -0,0 +1,35 @@
+//
+// vr4300/decoder.h: VR4300 decoder.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __vr4300_decoder_h__
+#define __vr4300_decoder_h__
+#include "common.h"
+#include "vr4300/opcodes.h"
+
+#define GET_RS(opcode) ((opcode) >> 21 & 0x1F)
+#define GET_RT(opcode) ((opcode) >> 16 & 0x1F)
+#define GET_RD(opcode) ((opcode) >> 11 & 0x1F)
+
+#define GET_FS(opcode) ((opcode) >> 11 & 0x1F)
+#define GET_FT(opcode) ((opcode) >> 16 & 0x1F)
+#define GET_FD(opcode) ((opcode) >> 6 & 0x1F)
+
+#define OPCODE_INFO_NONE (0)
+#define OPCODE_INFO_BRANCH (1 << 1)
+
+struct vr4300_opcode {
+ uint8_t id;
+ uint8_t flags;
+};
+
+const struct vr4300_opcode* vr4300_decode_instruction(uint32_t);
+
+#endif
+
diff --git a/vr4300/docs/vr43xx.pdf b/vr4300/docs/vr43xx.pdf
new file mode 100644
index 000000000..dabe6c0e6
Binary files /dev/null and b/vr4300/docs/vr43xx.pdf differ
diff --git a/vr4300/fault.c b/vr4300/fault.c
new file mode 100644
index 000000000..acdb9e2a3
--- /dev/null
+++ b/vr4300/fault.c
@@ -0,0 +1,96 @@
+//
+// vr4300/fault.c: VR4300 fault management.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "bus/controller.h"
+#include "vr4300/cp0.h"
+#include "vr4300/cpu.h"
+#include "vr4300/fault.h"
+#include "vr4300/pipeline.h"
+
+const char *vr4300_fault_mnemonics[NUM_VR4300_FAULTS] = {
+#define X(fault) #fault,
+#include "vr4300/fault.md"
+#undef X
+};
+
+// Sets attributes common to all exceptions.
+static void vr4300_common_exceptions(struct vr4300_pipeline *pipeline) {
+ pipeline->icrf_latch.segment = get_default_segment();
+
+ pipeline->exception_history = 0;
+ pipeline->fault_present = true;
+ pipeline->cycles_to_stall = 2;
+ pipeline->skip_stages = 0;
+}
+
+// Sets attributes common to all interlocks.
+static void vr4300_common_interlocks(struct vr4300_pipeline *pipeline,
+ unsigned cycles_to_stall, unsigned skip_stages) {
+ pipeline->cycles_to_stall = cycles_to_stall;
+ pipeline->skip_stages = skip_stages;
+}
+
+// Raise a fault that originated in the DC stage.
+static void vr4300_dc_fault(struct vr4300_pipeline *pipeline,
+ enum vr4300_fault_id fault) {
+ vr4300_common_exceptions(pipeline);
+ pipeline->exdc_latch.common.fault = fault;
+ pipeline->rfex_latch.common.fault = fault;
+ pipeline->icrf_latch.common.fault = fault;
+}
+
+// IADE: Instruction address error exception
+void VR4300_IADE(unused(struct vr4300 *vr4300)) {
+ abort();
+}
+
+// UNC: Uncached read interlock.
+void VR4300_UNC(struct vr4300 *vr4300) {
+ struct vr4300_pipeline *pipeline = &vr4300->pipeline;
+ struct vr4300_icrf_latch *icrf_latch = &pipeline->icrf_latch;
+ struct vr4300_rfex_latch *rfex_latch = &pipeline->rfex_latch;
+ const struct segment *segment = icrf_latch->segment;
+ uint64_t address;
+
+ vr4300_common_interlocks(pipeline, ~0, 4);
+
+ address = icrf_latch->common.pc - segment->offset;
+ bus_read_word(vr4300->bus, address, &rfex_latch->iw);
+ pipeline->cycles_to_stall = 50;
+}
+
+// RST: External reset exception.
+void VR4300_RST(struct vr4300 *vr4300) {
+ struct vr4300_pipeline *pipeline = &vr4300->pipeline;
+ struct vr4300_cp0 *cp0 = &vr4300->cp0;
+
+ // Prepare pipeline for restart.
+ vr4300->pipeline.icrf_latch.pc = 0xFFFFFFFFBFC00000ULL;
+ vr4300_dc_fault(pipeline, VR4300_FAULT_RST);
+
+ // Cold reset exception.
+ if (vr4300->signals & VR4300_SIGNAL_COLDRESET) {
+ vr4300->signals &= ~VR4300_SIGNAL_COLDRESET;
+
+ cp0->regs[VR4300_CP0_REGISTER_STATUS] &= ~0x08300000ULL;
+ cp0->regs[VR4300_CP0_REGISTER_CONFIG] &= ~0xFFFF7FF0ULL;
+
+ cp0->regs[VR4300_CP0_REGISTER_STATUS] |= 0x00400004ULL;
+ cp0->regs[VR4300_CP0_REGISTER_CONFIG] |= 0x7006E460ULL;
+
+ cp0->regs[VR4300_CP0_REGISTER_RANDOM] = 31;
+ }
+
+ // Soft reset exception.
+ else
+ abort();
+}
+
diff --git a/vr4300/fault.h b/vr4300/fault.h
new file mode 100644
index 000000000..053865ab3
--- /dev/null
+++ b/vr4300/fault.h
@@ -0,0 +1,30 @@
+//
+// vr4300/fault.h: VR4300 fault management.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __vr4300_fault_h__
+#define __vr4300_fault_h__
+
+struct vr4300;
+
+enum vr4300_fault_id {
+#define X(fault) VR4300_FAULT_##fault,
+#include "vr4300/fault.md"
+ NUM_VR4300_FAULTS
+#undef X
+};
+
+extern const char *vr4300_fault_mnemonics[NUM_VR4300_FAULTS];
+
+#define X(fault) void VR4300_##fault(struct vr4300 *vr4300);
+#include "vr4300/fault.md"
+#undef X
+
+#endif
+
diff --git a/vr4300/fault.md b/vr4300/fault.md
new file mode 100644
index 000000000..938db0777
--- /dev/null
+++ b/vr4300/fault.md
@@ -0,0 +1,19 @@
+//
+// vr4300/fault.md: VR4300 fault management.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef VR4300_FAULT_LIST
+#define VR4300_FAULT_LIST \
+ X(NONE) X(CP0I) X(RST) X(NMI) X(OVFL) X(TRAP) X(FPE) X(DADE) X(DTLB) \
+ X(WAT) X(INTR) X(DCM) X(DCB) X(COP) X(DBE) X(SYSC) X(BRPT) X(CPU) \
+ X(RSVD) X(LDI) X(MCI) X(IADE) X(ITM) X(ICB) X(UNC) X(IBE)
+#endif
+
+VR4300_FAULT_LIST
+
diff --git a/vr4300/icache.c b/vr4300/icache.c
new file mode 100644
index 000000000..e244e0255
--- /dev/null
+++ b/vr4300/icache.c
@@ -0,0 +1,121 @@
+//
+// vr4300/icache.c: VR4300 instruction cache.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "vr4300/icache.h"
+
+static inline struct vr4300_icache_line* get_line(
+ struct vr4300_icache *icache, uint64_t vaddr);
+static inline const struct vr4300_icache_line* get_line_const(
+ const struct vr4300_icache *icache, uint64_t vaddr);
+
+static inline uint32_t get_tag(const struct vr4300_icache_line *line);
+static void invalidate_line(struct vr4300_icache_line *line);
+static bool is_valid(const struct vr4300_icache_line *line);
+static void set_tag(struct vr4300_icache_line *line, uint32_t tag);
+static void validate_line(struct vr4300_icache_line *line, uint32_t tag);
+
+// Returns the line for a given virtual address.
+struct vr4300_icache_line* get_line(
+ struct vr4300_icache *icache, uint64_t vaddr) {
+ return icache->lines + (vaddr >> 5 & 0x1FF);
+}
+
+// Returns the line for a given virtual address.
+const struct vr4300_icache_line* get_line_const(
+ const struct vr4300_icache *icache, uint64_t vaddr) {
+ return icache->lines + (vaddr >> 5 & 0x1FF);
+}
+
+// Returns the physical tag associated with the line.
+uint32_t get_tag(const struct vr4300_icache_line *line) {
+ return line->metadata >> 12;
+}
+
+// Invalidates the line, but leaves the physical tag untouched.
+void invalidate_line(struct vr4300_icache_line *line) {
+ line->metadata &= ~0x1;
+}
+
+// Returns true if the line is valid, otherwise returns false.
+bool is_valid(const struct vr4300_icache_line *line) {
+ return (line->metadata & 0x1) == 0x1;
+}
+
+// Sets the tag of the specified line, retaining current valid bit.
+void set_tag(struct vr4300_icache_line *line, uint32_t tag) {
+ line->metadata = (tag << 12) | (line->metadata & 0x1);
+}
+
+// Sets the line's physical tag and validates the line.
+static void validate_line(struct vr4300_icache_line *line, uint32_t tag) {
+ line->metadata = (tag << 12) | 0x1;
+}
+
+// Fills an instruction cache line with data.
+void vr4300_icache_fill(struct vr4300_icache *icache,
+ uint64_t vaddr, uint32_t paddr, const void *data) {
+ struct vr4300_icache_line *line = get_line(icache, vaddr);
+
+ memcpy(line->data, data, sizeof(line->data));
+ validate_line(line, paddr >> 5);
+}
+
+// Returns the tag of the line associated with vaddr.
+uint32_t vr4300_icache_get_tag(const struct vr4300_icache *icache,
+ uint64_t vaddr) {
+ const struct vr4300_icache_line *line = get_line_const(icache, vaddr);
+
+ return get_tag(line);
+}
+
+// Initializes the instruction cache.
+void vr4300_icache_init(struct vr4300_icache *icache) {
+ memset(icache->lines, 0, sizeof(icache->lines));
+
+}
+
+// Invalidates an instruction cache line (regardless if hit or miss).
+void vr4300_icache_invalidate(struct vr4300_icache *icache, uint64_t vaddr) {
+ struct vr4300_icache_line *line = get_line(icache, vaddr);
+
+ invalidate_line(line);
+}
+
+// Invalidates an instruction cache line (only on a hit).
+void vr4300_icache_invalidate_hit(struct vr4300_icache *icache,
+ uint64_t vaddr, uint32_t paddr) {
+ struct vr4300_icache_line *line = get_line(icache, vaddr);
+ uint32_t ptag = get_tag(line);
+
+ if (ptag == (paddr >> 5) && is_valid(line))
+ invalidate_line(line);
+}
+
+// Probes the instruction cache for a matching line.
+const struct vr4300_icache_line* vr4300_icache_probe(
+ const struct vr4300_icache *icache, uint64_t vaddr, uint32_t paddr) {
+ const struct vr4300_icache_line *line = get_line_const(icache, vaddr);
+ uint32_t ptag = get_tag(line);
+
+ // Virtually index, and physically tagged.
+ return (ptag == (paddr >> 5) && is_valid(line))
+ ? line
+ : NULL;
+}
+
+// Sets the physical tag associated with the line.
+void vr4300_icache_set_tag(struct vr4300_icache *icache,
+ uint64_t vaddr, uint32_t tag) {
+ struct vr4300_icache_line *line = get_line(icache, vaddr);
+
+ set_tag(line, tag);
+}
+
diff --git a/vr4300/icache.h b/vr4300/icache.h
new file mode 100644
index 000000000..aff3211e7
--- /dev/null
+++ b/vr4300/icache.h
@@ -0,0 +1,41 @@
+//
+// vr4300/icache.h: VR4300 instruction cache.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __vr4300_icache_h__
+#define __vr4300_icache_h__
+#include "common.h"
+
+struct vr4300_icache_line {
+ uint8_t data[8 * 4];
+ uint32_t metadata;
+};
+
+struct vr4300_icache {
+ struct vr4300_icache_line lines[512];
+};
+
+void vr4300_icache_init(struct vr4300_icache *icache);
+int vr4300_icache_serialize(struct vr4300_icache *icache, FILE *f);
+int vr4300_icache_unserialize(struct vr4300_icache *icache, FILE *f);
+
+void vr4300_icache_fill(struct vr4300_icache *icache,
+ uint64_t vaddr, uint32_t paddr, const void *data);
+uint32_t vr4300_icache_get_tag(const struct vr4300_icache *icache,
+ uint64_t vaddr);
+void vr4300_icache_invalidate(struct vr4300_icache *icache, uint64_t vaddr);
+void vr4300_icache_invalidate_hit(struct vr4300_icache *icache,
+ uint64_t vaddr, uint32_t paddr);
+const struct vr4300_icache_line* vr4300_icache_probe(
+ const struct vr4300_icache *icache, uint64_t vaddr, uint32_t paddr);
+void vr4300_icache_set_tag(struct vr4300_icache *icache,
+ uint64_t vaddr, uint32_t tag);
+
+#endif
+
diff --git a/vr4300/opcodes.c b/vr4300/opcodes.c
new file mode 100644
index 000000000..3a9915936
--- /dev/null
+++ b/vr4300/opcodes.c
@@ -0,0 +1,18 @@
+//
+// vr4300/opcodes.c: VR4300 opcode types and info.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "vr4300/opcodes.h"
+
+const char *vr4300_opcode_mnemonics[NUM_VR4300_OPCODES] = {
+#define X(op) #op,
+#include "vr4300/opcodes.md"
+#undef X
+};
+
diff --git a/vr4300/opcodes.h b/vr4300/opcodes.h
new file mode 100644
index 000000000..269a4dcda
--- /dev/null
+++ b/vr4300/opcodes.h
@@ -0,0 +1,190 @@
+//
+// vr4300/opcodes.h: VR4300 opcode types and info.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __vr4300_opcodes_h__
+#define __vr4300_opcodes_h__
+#include "common.h"
+
+enum vr4300_opcode_id {
+#define X(op) VR4300_OPCODE_##op,
+#include "vr4300/opcodes.md"
+ NUM_VR4300_OPCODES
+#undef X
+};
+
+extern const char *vr4300_opcode_mnemonics[NUM_VR4300_OPCODES];
+
+/* Flags for each instruction. */
+#define VR4300_BUILD_OP(op, flags) \
+ (VR4300_OPCODE_##op), (flags)
+
+#define INFO1(x) (OPCODE_INFO_##x)
+#define INFO2(x,y) (INFO1(x) | OPCODE_INFO_##y)
+#define INFO3(x,y,z) (INFO2(x,y) | OPCODE_INFO_##z)
+#define INFO4(x,y,z,a) (INFO3(x,y,z) | OPCODE_INFO_##a)
+#define INFO5(x,y,z,a,b) (INFO4(x,y,z,a) | OPCODE_INFO_##b)
+#define INVALID VR4300_BUILD_OP(INV, INFO1(NONE))
+
+#define BC0 VR4300_BUILD_OP(BC0, INFO1(BRANCH))
+#define BC1 VR4300_BUILD_OP(BC1, INFO1(BRANCH))
+#define BC2 VR4300_BUILD_OP(BC1, INFO1(BRANCH))
+#define FPUS VR4300_BUILD_OP(FPUS, INFO1(NONE))
+#define FPUD VR4300_BUILD_OP(FPUD, INFO1(NONE))
+#define FPUW VR4300_BUILD_OP(FPUW, INFO1(NONE))
+#define FPUL VR4300_BUILD_OP(FPUL, INFO1(NONE))
+#define TLB VR4300_BUILD_OP(TLB, INFO1(NONE))
+
+#define ADD VR4300_BUILD_OP(ADD, INFO1(NONE))
+#define ADDI VR4300_BUILD_OP(ADDI, INFO1(NONE))
+#define ADDIU VR4300_BUILD_OP(ADDIU, INFO1(NONE))
+#define ADDU VR4300_BUILD_OP(ADDU, INFO1(NONE))
+#define AND VR4300_BUILD_OP(AND, INFO1(NONE))
+#define ANDI VR4300_BUILD_OP(ANDI, INFO1(NONE))
+#define BEQ VR4300_BUILD_OP(BEQ, INFO1(BRANCH))
+#define BEQL VR4300_BUILD_OP(BEQL, INFO1(BRANCH))
+#define BGEZ VR4300_BUILD_OP(BGEZ, INFO1(BRANCH))
+#define BGEZAL VR4300_BUILD_OP(BGEZAL, INFO1(BRANCH))
+#define BGEZALL VR4300_BUILD_OP(BGEZALL, INFO1(BRANCH))
+#define BGEZL VR4300_BUILD_OP(BGEZL, INFO1(BRANCH))
+#define BGTZ VR4300_BUILD_OP(BGTZ, INFO1(BRANCH))
+#define BGTZL VR4300_BUILD_OP(BGTZL, INFO1(BRANCH))
+#define BLEZ VR4300_BUILD_OP(BLEZ, INFO1(BRANCH))
+#define BLEZL VR4300_BUILD_OP(BLEZL, INFO1(BRANCH))
+#define BLTZ VR4300_BUILD_OP(BLTZ, INFO1(BRANCH))
+#define BLTZAL VR4300_BUILD_OP(BLTZAL, INFO1(BRANCH))
+#define BLTZALL VR4300_BUILD_OP(BLTZALL, INFO1(BRANCH))
+#define BLTZL VR4300_BUILD_OP(BLTZL, INFO1(BRANCH))
+#define BNE VR4300_BUILD_OP(BNE, INFO1(BRANCH))
+#define BNEL VR4300_BUILD_OP(BNEL, INFO1(BRANCH))
+#define BREAK VR4300_BUILD_OP(BREAK, INFO1(NONE))
+#define CACHE VR4300_BUILD_OP(CACHE, INFO1(NONE))
+#define CFC0 VR4300_BUILD_OP(CFC0, INFO1(NONE))
+#define CFC1 VR4300_BUILD_OP(CFC1, INFO1(NONE))
+#define CFC2 VR4300_BUILD_OP(CFC2, INFO1(NONE))
+#define COP0 VR4300_BUILD_OP(COP0, INFO1(NONE))
+#define COP1 VR4300_BUILD_OP(COP1, INFO1(NONE))
+#define COP2 VR4300_BUILD_OP(COP2, INFO1(NONE))
+#define CTC0 VR4300_BUILD_OP(CTC0, INFO1(NONE))
+#define CTC1 VR4300_BUILD_OP(CTC1, INFO1(NONE))
+#define CTC2 VR4300_BUILD_OP(CTC2, INFO1(NONE))
+#define DADD VR4300_BUILD_OP(DADD, INFO1(NONE))
+#define DADDI VR4300_BUILD_OP(DADDI, INFO1(NONE))
+#define DADDIU VR4300_BUILD_OP(DADDIU, INFO1(NONE))
+#define DADDU VR4300_BUILD_OP(DADDU, INFO1(NONE))
+#define DDIV VR4300_BUILD_OP(DDIV, INFO1(NONE))
+#define DDIVU VR4300_BUILD_OP(DDIVU, INFO1(NONE))
+#define DIV VR4300_BUILD_OP(DIV, INFO1(NONE))
+#define DIVU VR4300_BUILD_OP(DIVU, INFO1(NONE))
+#define DMFC0 VR4300_BUILD_OP(DMFC0, INFO1(NONE))
+#define DMFC1 VR4300_BUILD_OP(DMFC1, INFO1(NONE))
+#define DMFC2 VR4300_BUILD_OP(DMFC2, INFO1(NONE))
+#define DMTC0 VR4300_BUILD_OP(DMTC0, INFO1(NONE))
+#define DMTC1 VR4300_BUILD_OP(DMTC1, INFO1(NONE))
+#define DMTC2 VR4300_BUILD_OP(DMTC2, INFO1(NONE))
+#define DMULT VR4300_BUILD_OP(DMULT, INFO1(NONE))
+#define DMULTU VR4300_BUILD_OP(DMULTU, INFO1(NONE))
+#define DSLL VR4300_BUILD_OP(DSLL, INFO1(NONE))
+#define DSLLV VR4300_BUILD_OP(DSLLV, INFO1(NONE))
+#define DSLL32 VR4300_BUILD_OP(DSLL32, INFO1(NONE))
+#define DSRA VR4300_BUILD_OP(DSRA, INFO1(NONE))
+#define DSRAV VR4300_BUILD_OP(DSRAV, INFO1(NONE))
+#define DSRA32 VR4300_BUILD_OP(DSRA32, INFO1(NONE))
+#define DSRL VR4300_BUILD_OP(DSRL, INFO1(NONE))
+#define DSRLV VR4300_BUILD_OP(DSRLV, INFO1(NONE))
+#define DSRL32 VR4300_BUILD_OP(DSRL32, INFO1(NONE))
+#define DSUB VR4300_BUILD_OP(DSUB, INFO1(NONE))
+#define DSUBU VR4300_BUILD_OP(DSUBU, INFO1(NONE))
+#define ERET VR4300_BUILD_OP(ERET, INFO1(NONE))
+#define J VR4300_BUILD_OP(J, INFO1(BRANCH))
+#define JAL VR4300_BUILD_OP(JAL, INFO1(BRANCH))
+#define JALR VR4300_BUILD_OP(JALR, INFO1(BRANCH))
+#define JR VR4300_BUILD_OP(JR, INFO1(BRANCH))
+#define LB VR4300_BUILD_OP(LB, INFO1(NONE))
+#define LBU VR4300_BUILD_OP(LBU, INFO1(NONE))
+#define LD VR4300_BUILD_OP(LD, INFO1(NONE))
+#define LDC0 VR4300_BUILD_OP(LDC0, INFO1(NONE))
+#define LDC1 VR4300_BUILD_OP(LDC1, INFO1(NONE))
+#define LDC2 VR4300_BUILD_OP(LDC2, INFO1(NONE))
+#define LDL VR4300_BUILD_OP(LDL, INFO1(NONE))
+#define LDR VR4300_BUILD_OP(LDR, INFO1(NONE))
+#define LH VR4300_BUILD_OP(LH, INFO1(NONE))
+#define LHU VR4300_BUILD_OP(LHU, INFO1(NONE))
+#define LL VR4300_BUILD_OP(LL, INFO1(NONE))
+#define LLD VR4300_BUILD_OP(LLD, INFO1(NONE))
+#define LUI VR4300_BUILD_OP(LUI, INFO1(NONE))
+#define LW VR4300_BUILD_OP(LW, INFO1(NONE))
+#define LWC0 VR4300_BUILD_OP(LWC0, INFO1(NONE))
+#define LWC1 VR4300_BUILD_OP(LWC1, INFO1(NONE))
+#define LWC2 VR4300_BUILD_OP(LWC2, INFO1(NONE))
+#define LWL VR4300_BUILD_OP(LWL, INFO1(NONE))
+#define LWR VR4300_BUILD_OP(LWR, INFO1(NONE))
+#define LWU VR4300_BUILD_OP(LWU, INFO1(NONE))
+#define MFC0 VR4300_BUILD_OP(MFC0, INFO1(NONE))
+#define MFC1 VR4300_BUILD_OP(MFC1, INFO1(NONE))
+#define MFC2 VR4300_BUILD_OP(MFC2, INFO1(NONE))
+#define MFHI VR4300_BUILD_OP(MFHI, INFO1(NONE))
+#define MFLO VR4300_BUILD_OP(MFLO, INFO1(NONE))
+#define MTC0 VR4300_BUILD_OP(MTC0, INFO1(NONE))
+#define MTC1 VR4300_BUILD_OP(MTC1, INFO1(NONE))
+#define MTC2 VR4300_BUILD_OP(MTC2, INFO1(NONE))
+#define MTHI VR4300_BUILD_OP(MTHI, INFO1(NONE))
+#define MTLO VR4300_BUILD_OP(MTLO, INFO1(NONE))
+#define MULT VR4300_BUILD_OP(MULT, INFO1(NONE))
+#define MULTU VR4300_BUILD_OP(MULTU, INFO1(NONE))
+#define NOR VR4300_BUILD_OP(NOR, INFO1(NONE))
+#define OR VR4300_BUILD_OP(OR, INFO1(NONE))
+#define ORI VR4300_BUILD_OP(ORI, INFO1(NONE))
+#define SB VR4300_BUILD_OP(SB, INFO1(NONE))
+#define SC VR4300_BUILD_OP(SC, INFO1(NONE))
+#define SCD VR4300_BUILD_OP(SCD, INFO1(NONE))
+#define SD VR4300_BUILD_OP(SD, INFO1(NONE))
+#define SDC0 VR4300_BUILD_OP(SDC0, INFO1(NONE))
+#define SDC1 VR4300_BUILD_OP(SDC1, INFO1(NONE))
+#define SDC2 VR4300_BUILD_OP(SDC2, INFO1(NONE))
+#define SDL VR4300_BUILD_OP(SDL, INFO1(NONE))
+#define SDR VR4300_BUILD_OP(SDR, INFO1(NONE))
+#define SH VR4300_BUILD_OP(SH, INFO1(NONE))
+#define SLL VR4300_BUILD_OP(SLL, INFO1(NONE))
+#define SLLV VR4300_BUILD_OP(SLLV, INFO1(NONE))
+#define SLT VR4300_BUILD_OP(SLT, INFO1(NONE))
+#define SLTI VR4300_BUILD_OP(SLTI, INFO1(NONE))
+#define SLTIU VR4300_BUILD_OP(SLTIU, INFO1(NONE))
+#define SLTU VR4300_BUILD_OP(SLTU, INFO1(NONE))
+#define SRA VR4300_BUILD_OP(SRA, INFO1(NONE))
+#define SRAV VR4300_BUILD_OP(SRAV, INFO1(NONE))
+#define SRL VR4300_BUILD_OP(SRL, INFO1(NONE))
+#define SRLV VR4300_BUILD_OP(SRLV, INFO1(NONE))
+#define SUB VR4300_BUILD_OP(SUB, INFO1(NONE))
+#define SUBU VR4300_BUILD_OP(SUBU, INFO1(NONE))
+#define SW VR4300_BUILD_OP(SW, INFO1(NONE))
+#define SWC0 VR4300_BUILD_OP(SWC0, INFO1(NONE))
+#define SWC1 VR4300_BUILD_OP(SWC1, INFO1(NONE))
+#define SWC2 VR4300_BUILD_OP(SWC2, INFO1(NONE))
+#define SWL VR4300_BUILD_OP(SWL, INFO1(NONE))
+#define SWR VR4300_BUILD_OP(SWR, INFO1(NONE))
+#define SYNC VR4300_BUILD_OP(SYNC, INFO1(NONE))
+#define SYSCALL VR4300_BUILD_OP(SYSCALL, INFO1(NONE))
+#define TEQ VR4300_BUILD_OP(TEQ, INFO1(NONE))
+#define TEQI VR4300_BUILD_OP(TEQI, INFO1(NONE))
+#define TGE VR4300_BUILD_OP(TGE, INFO1(NONE))
+#define TGEI VR4300_BUILD_OP(TGEI, INFO1(NONE))
+#define TGEIU VR4300_BUILD_OP(TGEIU, INFO1(NONE))
+#define TGEU VR4300_BUILD_OP(TGEU, INFO1(NONE))
+#define TLT VR4300_BUILD_OP(TLT, INFO1(NONE))
+#define TLTI VR4300_BUILD_OP(TLTI, INFO1(NONE))
+#define TLTIU VR4300_BUILD_OP(TLTIU, INFO1(NONE))
+#define TLTU VR4300_BUILD_OP(TLTU, INFO1(NONE))
+#define TNE VR4300_BUILD_OP(TNE, INFO1(NONE))
+#define TNEI VR4300_BUILD_OP(TNEI, INFO1(NONE))
+#define XOR VR4300_BUILD_OP(XOR, INFO1(NONE))
+#define XORI VR4300_BUILD_OP(XORI, INFO1(NONE))
+
+#endif
+
diff --git a/vr4300/opcodes.md b/vr4300/opcodes.md
new file mode 100644
index 000000000..adfa96e7d
--- /dev/null
+++ b/vr4300/opcodes.md
@@ -0,0 +1,34 @@
+//
+// vr4300/opcodes.md: VR4300 opcode types and info.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef VR4300_OPCODE_TABLE
+#define VR4300_OPCODE_TABLE X(INV) \
+ X(ADD) X(ADDI) X(ADDIU) X(ADDU) X(AND) X(ANDI) X(BC0) X(BC1) X(BC2) \
+ X(BEQ) X(BEQL) X(BGEZ) X(BGEZAL) X(BGEZALL) X(BGEZL) X(BGTZ) X(BGTZL) \
+ X(BLEZ) X(BLEZL) X(BLTZ) X(BLTZAL) X(BLTZALL) X(BLTZL) X(BNE) X(BNEL) \
+ X(BREAK) X(CACHE) X(CFC0) X(CFC1) X(CFC2) X(COP0) X(COP1) X(COP2) \
+ X(CTC0) X(CTC1) X(CTC2) X(DADD) X(DADDI) X(DADDIU) X(DADDU) X(DDIV) \
+ X(DDIVU) X(DIV) X(DIVU) X(DMFC0) X(DMFC1) X(DMFC2) X(DMTC0) X(DMTC1) \
+ X(DMTC2) X(DMULT) X(DMULTU) X(DSLL) X(DSLLV) X(DSLL32) X(DSRA) X(DSRAV) \
+ X(DSRA32) X(DSRL) X(DSRLV) X(DSRL32) X(DSUB) X(DSUBU) X(FPUD) X(FPUL) \
+ X(FPUS) X(FPUW) X(J) X(JAL) X(JALR) X(JR) X(LB) X(LBU) X(LD) X(LDC0) \
+ X(LDC1) X(LDC2) X(LDL) X(LDR) X(LH) X(LHU) X(LL) X(LLD) X(LUI) X(LW) \
+ X(LWC0) X(LWC1) X(LWC2) X(LWL) X(LWR) X(LWU) X(MFC0) X(MFC1) X(MFC2) \
+ X(MFHI) X(MFLO) X(MTC0) X(MTC1) X(MTC2) X(MTHI) X(MTLO) X(MULT) \
+ X(MULTU) X(NOR) X(OR) X(ORI) X(SB) X(SC) X(SCD) X(SD) X(SDC0) X(SDC1) \
+ X(SDC2) X(SDL) X(SDR) X(SH) X(SLL) X(SLLV) X(SLT) X(SLTI) X(SLTIU) \
+ X(SLTU) X(SRA) X(SRAV) X(SRL) X(SRLV) X(SUB) X(SUBU) X(SW) X(SWC0) \
+ X(SWC1) X(SWC2) X(SWL) X(SWR) X(SYNC) X(SYSCALL) X(TEQ) X(TEQI) X(TGE) \
+ X(TGEI) X(TGEIU) X(TGEU) X(TLB) X(TLT) X(TLTI) X(TLTIU) X(TLTU) X(TNE) \
+ X(TNEI) X(XOR) X(XORI)
+#endif
+
+VR4300_OPCODE_TABLE
+
diff --git a/vr4300/pipeline.c b/vr4300/pipeline.c
new file mode 100644
index 000000000..42cd66001
--- /dev/null
+++ b/vr4300/pipeline.c
@@ -0,0 +1,285 @@
+//
+// vr4300/pipeline.c: VR4300 processor pipeline.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "vr4300/cp0.h"
+#include "vr4300/cpu.h"
+#include "vr4300/decoder.h"
+#include "vr4300/fault.h"
+#include "vr4300/pipeline.h"
+#include "vr4300/segment.h"
+
+// Instruction cache stage.
+static inline int vr4300_ic_stage (struct vr4300 *vr4300) {
+ struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
+ const struct segment *segment = icrf_latch->segment;
+ uint64_t pc = icrf_latch->pc;
+
+ icrf_latch->common.pc = pc;
+
+ // Look up the segment that we're in.
+ if ((pc - segment->start) > segment->length) {
+ uint32_t cp0_status = vr4300->cp0.regs[VR4300_CP0_REGISTER_STATUS];
+
+ if (unlikely((segment = get_segment(pc, cp0_status)) == NULL)) {
+ VR4300_IADE(vr4300);
+ return 1;
+ }
+
+ icrf_latch->segment = segment;
+ }
+
+ // We didn't have an IADE, so reset the status vector.
+ icrf_latch->common.fault = VR4300_FAULT_NONE;
+ return 0;
+}
+
+// Register fetch and decode stage.
+static inline int vr4300_rf_stage (struct vr4300 *vr4300) {
+ const struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
+ struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
+ const struct segment *segment = icrf_latch->segment;
+
+ rfex_latch->common = icrf_latch->common;
+
+ if (!segment->cached) {
+ VR4300_UNC(vr4300);
+ return 1;
+ }
+
+ return 0;
+}
+
+// Execution stage.
+static inline int vr4300_ex_stage (struct vr4300 *vr4300) {
+ const struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
+ struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
+
+ exdc_latch->common = rfex_latch->common;
+ return 0;
+}
+
+// Data cache fetch stage.
+static inline int vr4300_dc_stage (struct vr4300 *vr4300) {
+ const struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
+ struct vr4300_dcwb_latch *dcwb_latch = &vr4300->pipeline.dcwb_latch;
+
+ dcwb_latch->common = exdc_latch->common;
+ return 0;
+}
+
+// Writeback stage.
+static inline int vr4300_wb_stage (struct vr4300 *vr4300) {
+ const struct vr4300_dcwb_latch *dcwb_latch = &vr4300->pipeline.dcwb_latch;
+
+ if (dcwb_latch->common.fault != VR4300_FAULT_NONE)
+ return 0;
+
+ return 0;
+}
+
+// Advances the processor pipeline by one pclock.
+// May have exceptions, so check for aborted stages.
+static void vr4300_cycle_slow_wb(struct vr4300 *vr4300) {
+ struct vr4300_pipeline *pipeline = &vr4300->pipeline;
+ struct vr4300_dcwb_latch *dcwb_latch = &pipeline->dcwb_latch;
+ struct vr4300_exdc_latch *exdc_latch = &pipeline->exdc_latch;
+ struct vr4300_rfex_latch *rfex_latch = &pipeline->rfex_latch;
+ struct vr4300_icrf_latch *icrf_latch = &pipeline->icrf_latch;
+
+ // If we haven't had exceptions for at least a
+ // full pipeline's length, switch back to fast mode.
+ if (pipeline->exception_history++ > 4)
+ pipeline->fault_present = false;
+
+ if (dcwb_latch->common.fault == VR4300_FAULT_NONE) {
+ if (vr4300_wb_stage(vr4300))
+ return;
+ }
+
+ else
+ dcwb_latch->common = exdc_latch->common;
+
+ if (exdc_latch->common.fault == VR4300_FAULT_NONE) {
+ if (vr4300_dc_stage(vr4300))
+ return;
+ }
+
+ else
+ exdc_latch->common = rfex_latch->common;
+
+ if (rfex_latch->common.fault == VR4300_FAULT_NONE) {
+ if (vr4300_ex_stage(vr4300))
+ return;
+ }
+
+ else
+ rfex_latch->common = icrf_latch->common;
+
+ if (icrf_latch->common.fault == VR4300_FAULT_NONE)
+ if (vr4300_rf_stage(vr4300))
+ return;
+
+ if (vr4300_ic_stage(vr4300))
+ return;
+}
+
+// Advances the processor pipeline by one pclock.
+// May have exceptions, so check for aborted stages.
+//
+// Starts from DC stage (WB resolved an interlock).
+static void vr4300_cycle_slow_dc(struct vr4300 *vr4300) {
+ struct vr4300_pipeline *pipeline = &vr4300->pipeline;
+ struct vr4300_exdc_latch *exdc_latch = &pipeline->exdc_latch;
+ struct vr4300_rfex_latch *rfex_latch = &pipeline->rfex_latch;
+ struct vr4300_icrf_latch *icrf_latch = &pipeline->icrf_latch;
+
+ if (exdc_latch->common.fault == VR4300_FAULT_NONE) {
+ if (vr4300_dc_stage(vr4300))
+ return;
+ }
+
+ else
+ exdc_latch->common = rfex_latch->common;
+
+ if (rfex_latch->common.fault == VR4300_FAULT_NONE) {
+ if (vr4300_ex_stage(vr4300))
+ return;
+ }
+
+ else
+ rfex_latch->common = icrf_latch->common;
+
+ if (icrf_latch->common.fault == VR4300_FAULT_NONE)
+ if (vr4300_rf_stage(vr4300))
+ return;
+
+ if (vr4300_ic_stage(vr4300))
+ return;
+
+ pipeline->skip_stages = 0;
+}
+
+// Advances the processor pipeline by one pclock.
+// May have exceptions, so check for aborted stages.
+//
+// Starts from EX stage (DC resolved an interlock).
+static void vr4300_cycle_slow_ex(struct vr4300 *vr4300) {
+ struct vr4300_pipeline *pipeline = &vr4300->pipeline;
+ struct vr4300_rfex_latch *rfex_latch = &pipeline->rfex_latch;
+ struct vr4300_icrf_latch *icrf_latch = &pipeline->icrf_latch;
+
+ if (rfex_latch->common.fault == VR4300_FAULT_NONE) {
+ if (vr4300_ex_stage(vr4300))
+ return;
+ }
+
+ else
+ rfex_latch->common = icrf_latch->common;
+
+ if (icrf_latch->common.fault == VR4300_FAULT_NONE)
+ if (vr4300_rf_stage(vr4300))
+ return;
+
+ if (vr4300_ic_stage(vr4300))
+ return;
+
+ pipeline->skip_stages = 0;
+}
+
+// Advances the processor pipeline by one pclock.
+// May have exceptions, so check for aborted stages.
+//
+// Starts from RF stage (EX resolved an interlock).
+static void vr4300_cycle_slow_rf(struct vr4300 *vr4300) {
+ struct vr4300_pipeline *pipeline = &vr4300->pipeline;
+ struct vr4300_icrf_latch *icrf_latch = &pipeline->icrf_latch;
+
+ if (icrf_latch->common.fault == VR4300_FAULT_NONE)
+ if (vr4300_rf_stage(vr4300))
+ return;
+
+ if (vr4300_ic_stage(vr4300))
+ return;
+
+ pipeline->skip_stages = 0;
+}
+
+// Advances the processor pipeline by one pclock.
+// May have exceptions, so check for aborted stages.
+//
+// Starts from IC stage (RF resolved an interlock).
+static void vr4300_cycle_slow_ic(struct vr4300 *vr4300) {
+ struct vr4300_pipeline *pipeline = &vr4300->pipeline;
+
+ if (vr4300_ic_stage(vr4300))
+ return;
+
+ pipeline->skip_stages = 0;
+}
+
+// LUT of stages for fault handling.
+typedef void (*pipeline_function)(struct vr4300 *vr4300);
+static const pipeline_function pipeline_function_lut[5] = {
+ vr4300_cycle_slow_wb,
+ vr4300_cycle_slow_dc,
+ vr4300_cycle_slow_ex,
+ vr4300_cycle_slow_rf,
+ vr4300_cycle_slow_ic,
+};
+
+// Advances the processor pipeline by one pclock.
+void vr4300_cycle(struct vr4300 *vr4300) {
+ struct vr4300_pipeline *pipeline = &vr4300->pipeline;
+
+ // We're stalling for an interlock,
+ // or we just took an exception...
+ if (pipeline->cycles_to_stall > 0) {
+ pipeline->cycles_to_stall--;
+ return;
+ }
+
+ // The reset exception has a very high priority and will abort basically
+ // anything that's active, even if we have an interlock or something that's
+ // current active. Thus, we check for it here and handle it early.
+ if (unlikely(vr4300->signals & VR4300_SIGNAL_COLDRESET))
+ VR4300_RST(vr4300);
+
+ // Ordinarily, we would need to check every pipeline stage to see if it is
+ // aborted, and conditionally not execute it. Since faults are rare, we'll
+ // only bother checking for aborted stages when we know they can be present.
+ if (pipeline->fault_present || pipeline->skip_stages) {
+ pipeline_function_lut[pipeline->skip_stages](vr4300);
+ return;
+ }
+
+ if (vr4300_wb_stage(vr4300))
+ return;
+
+ if (vr4300_dc_stage(vr4300))
+ return;
+
+ if (vr4300_ex_stage(vr4300))
+ return;
+
+ if (vr4300_rf_stage(vr4300))
+ return;
+
+ if (vr4300_ic_stage(vr4300))
+ return;
+}
+
+// Initializes the pipeline with default values.
+void vr4300_pipeline_init(struct vr4300_pipeline *pipeline) {
+ memset(pipeline, 0, sizeof(*pipeline));
+
+ pipeline->icrf_latch.segment = get_default_segment();
+}
+
diff --git a/vr4300/pipeline.h b/vr4300/pipeline.h
new file mode 100644
index 000000000..3a1ee9452
--- /dev/null
+++ b/vr4300/pipeline.h
@@ -0,0 +1,59 @@
+//
+// vr4300/pipeline.h: VR4300 processor pipeline.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __vr4300_pipeline_h__
+#define __vr4300_pipeline_h__
+#include "common.h"
+#include "vr4300/fault.h"
+#include "vr4300/segment.h"
+
+struct vr4300;
+
+struct vr4300_latch {
+ uint64_t pc;
+ enum vr4300_fault_id fault;
+ uint32_t cause_data;
+};
+
+struct vr4300_icrf_latch {
+ struct vr4300_latch common;
+ const struct segment *segment;
+ uint64_t pc;
+};
+
+struct vr4300_rfex_latch {
+ struct vr4300_latch common;
+ uint32_t iw;
+};
+
+struct vr4300_exdc_latch {
+ struct vr4300_latch common;
+};
+
+struct vr4300_dcwb_latch {
+ struct vr4300_latch common;
+};
+
+struct vr4300_pipeline {
+ struct vr4300_dcwb_latch dcwb_latch;
+ struct vr4300_exdc_latch exdc_latch;
+ struct vr4300_rfex_latch rfex_latch;
+ struct vr4300_icrf_latch icrf_latch;
+
+ unsigned exception_history;
+ unsigned cycles_to_stall;
+ unsigned skip_stages;
+ bool fault_present;
+};
+
+void vr4300_pipeline_init(struct vr4300_pipeline *pipeline);
+
+#endif
+
diff --git a/vr4300/segment.c b/vr4300/segment.c
new file mode 100644
index 000000000..fbf283d06
--- /dev/null
+++ b/vr4300/segment.c
@@ -0,0 +1,273 @@
+//
+// vr4300/segment.c: VR4300 MMU segment manager.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#include "common.h"
+#include "vr4300/segment.h"
+
+//
+// Note: sseg, ksseg, kseg0, kseg1, and kseg3 do not appear below.
+//
+// As stated on pages 128, 130, and 134 of the "NEC VR43xx
+// Microprocessor User's Manual": "The VR4300 internally uses 64-bit
+// addresses. In the 32-bit mode, a 32-bit value with bits 32 through
+// 63 sign-extended is used an address."
+//
+
+static const struct segment USEGs[] = {
+ /* useg, suseg, kuseg. */ {
+ 0x0000000000000000ULL, /* start */
+ 0x0000000080000000ULL, /* length */
+ 0x0000000000000000ULL, /* offset */
+
+ true, /* mapped */
+ true, /* cached */
+
+ /* xuseg, xsuseg, xkuseg. */ }, {
+ 0x0000000000000000ULL, /* start */
+ 0x0000010000000000ULL, /* length */
+ 0x0000000000000000ULL, /* offset */
+
+ true, /* mapped */
+ true, /* cached */
+}};
+
+/* xsseg, xksseg. */
+static const struct segment XSSEG = {
+ 0x4000000000000000ULL, /* start */
+ 0x0000010000000000ULL, /* length */
+ 0x0000000000000000ULL, /* offset */
+
+ true, /* mapped */
+ true, /* cached */
+};
+
+static const struct segment KSEGs[] = {
+ /* (c)kseg0. */ {
+ 0xFFFFFFFF80000000ULL, /* start */
+ 0x0000000020000000ULL, /* length */
+ 0xFFFFFFFF80000000ULL, /* offset */
+
+ false, /* mapped */
+ true, /* cached */
+
+ /* (c)kseg1. */ }, {
+ 0xFFFFFFFFA0000000ULL, /* start */
+ 0x0000000020000000ULL, /* length */
+ 0xFFFFFFFFA0000000ULL, /* offset */
+
+ false, /* mapped */
+ false, /* cached */
+
+ /* (c)sseg, (c)ksseg. */ }, {
+ 0xFFFFFFFFC0000000ULL, /* start */
+ 0x0000000020000000ULL, /* length */
+ 0x0000000000000000ULL, /* offset */
+
+ true, /* mapped */
+ true, /* cached */
+
+ /* (c)kseg3. */ }, {
+ 0xFFFFFFFFE0000000ULL, /* start */
+ 0x0000000020000000ULL, /* length */
+ 0x0000000000000000ULL, /* offset */
+
+ true, /* mapped */
+ true, /* cached */
+}};
+
+static const struct segment XKSEG = {
+ 0xC000000000000000ULL, /* start */
+ 0x0000010000000000ULL, /* length */
+ 0x0000000000000000ULL, /* offset */
+
+ true, /* mapped */
+ true, /* cached */
+};
+
+static const struct segment XKPHYS0 = {
+ 0x8000000000000000ULL, /* start */
+ 0x0000000100000000ULL, /* length */
+ 0x8000000000000000ULL, /* offset */
+
+ false, /* mapped */
+ true, /* cached */
+};
+
+static const struct segment XKPHYS1 = {
+ 0x8800000000000000ULL, /* start */
+ 0x0000000100000000ULL, /* length */
+ 0x8800000000000000ULL, /* offset */
+
+ false, /* mapped */
+ true, /* cached */
+};
+
+static const struct segment XKPHYS2 = {
+ 0x9000000000000000ULL, /* start */
+ 0x0000000100000000ULL, /* length */
+ 0x9000000000000000ULL, /* offset */
+
+ false, /* mapped */
+ false, /* cached */
+};
+
+static const struct segment XKPHYS3 = {
+ 0x9800000000000000ULL, /* start */
+ 0x0000000100000000ULL, /* length */
+ 0x9800000000000000ULL, /* offset */
+
+ false, /* mapped */
+ true, /* cached */
+};
+
+static const struct segment XKPHYS4 = {
+ 0xA000000000000000ULL, /* start */
+ 0x0000000100000000ULL, /* length */
+ 0xA000000000000000ULL, /* offset */
+
+ false, /* mapped */
+ true, /* cached */
+};
+
+static const struct segment XKPHYS5 = {
+ 0xA800000000000000ULL, /* start */
+ 0x0000000100000000ULL, /* length */
+ 0xA800000000000000ULL, /* offset */
+
+ false, /* mapped */
+ true, /* cached */
+};
+
+static const struct segment XKPHYS6 = {
+ 0xB000000000000000ULL, /* start */
+ 0x0000000100000000ULL, /* length */
+ 0xB000000000000000ULL, /* offset */
+
+ false, /* mapped */
+ true, /* cached */
+};
+
+static const struct segment XKPHYS7 = {
+ 0xB800000000000000ULL, /* start */
+ 0x0000000100000000ULL, /* length */
+ 0xB800000000000000ULL, /* offset */
+
+ false, /* mapped */
+ true, /* cached */
+};
+
+static const struct segment *kernel_segs_lut[16] = {
+ &XKPHYS0,
+ &XKPHYS1,
+ &XKPHYS2,
+ &XKPHYS3,
+ &XKPHYS4,
+ &XKPHYS5,
+ &XKPHYS6,
+ &XKPHYS7,
+ &XKSEG,
+ &XKSEG,
+ &XKSEG,
+ &XKSEG,
+ &XKSEG,
+ &XKSEG,
+ &XKSEG,
+ &XKSEG,
+};
+
+
+// Returns a default segment that should cause
+// a cached segment miss and result in a lookup.
+const struct segment* get_default_segment(void) {
+ static const struct segment default_segment = {
+ 1ULL,
+ 0ULL,
+ 0ULL,
+ false,
+ false,
+ };
+
+ return &default_segment;
+}
+
+// Returns the segment given a CP0 status register and a virtual address.
+const struct segment* get_segment(uint64_t address, uint32_t cp0_status) {
+ const struct segment *seg;
+
+ // LUT used to determine if we're in a 64-bit mode or not.
+ // i.e., if we're in supervisor mode, is the ux bit set?
+ cen64_align(static const uint8_t segment_mode_lut[256], CACHE_LINE_SIZE) = {
+#define _ sizeof(*seg)
+/*ks:sx:ux | k k k k, s, k, k, k, u, k, k, k, ?, k, k, k */
+/* 0: 0: 0 |*/ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+/* 0: 0: 1 |*/ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,_,_,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+/* 0: 1: 0 |*/ 0,0,0,0,0,0,0,0,_,_,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+/* 0: 1: 1 |*/ 0,0,0,0,0,0,0,0,_,_,0,0,0,0,0,0,_,_,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+/* 1: 0: 0 |*/ _,_,_,_,_,_,_,_,0,0,_,_,_,_,_,_,0,0,_,_,_,_,_,_,0,0,_,_,_,_,_,_,
+/* 1: 0: 1 |*/ _,_,_,_,_,_,_,_,0,0,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0,0,_,_,_,_,_,_,
+/* 1: 1: 0 |*/ _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0,0,_,_,_,_,_,_,0,0,_,_,_,_,_,_,
+/* 1: 1: 1 |*/ _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0,0,_,_,_,_,_,_,
+#undef _
+ };
+
+ unsigned segment_mode = segment_mode_lut[cp0_status & 0xFF];
+ unsigned mode_and_flags_mask = cp0_status & 0x1E;
+
+#ifndef NDEBUG
+ uint64_t sexaddress = (int64_t) ((int32_t) address);
+
+ char kernel = (cp0_status & 0x6) || ((cp0_status & 0x18) == 0);
+ char supervisor = ((cp0_status & 0x6) == 0) && ((cp0_status & 0x18) == 0x8);
+ char user = ((cp0_status & 0x6) == 0) && ((cp0_status & 0x18) == 0x10);
+
+ char use_kx = kernel && (cp0_status & 0x80);
+ char use_sx = supervisor && (cp0_status & 0x40);
+ char use_ux = user && (cp0_status & 0x20);
+ char use_64 = use_kx | use_sx | use_ux;
+
+ // Ensure that only one of {kernel, supervisor, user} are produced.
+ assert(((kernel + supervisor + user) == 1) && "Impossible situation.");
+
+ // Ensure that either 64-bit mode is used, or the address is sign-extended.
+ assert((use_64 || (sexaddress == address)) && "Invalid 32-bit address.");
+#endif
+
+ // Check for useg/suseg/kuseg or xuseg/xsuseg/xkuseg first.
+ seg = (const struct segment *) ((uintptr_t) USEGs + segment_mode);
+
+ if (address < seg->length)
+ return seg;
+
+ // If we're not in user mode...
+ else if (mode_and_flags_mask != 0x10) {
+ seg = &KSEGs[2];
+
+ // Assume we're csseg and check for xsseg/xksseg.
+ if ((address >> 40) == 0x400000)
+ return &XSSEG;
+
+ // If we're in kernel mode, check for ckseg0, ckseg1, and ckseg3.
+ else if (mode_and_flags_mask != 0x08) {
+ if (address >= KSEGs[0].start)
+ return KSEGs + (address >> 29 & 0x3);
+
+ // Check for xkseg and xkphys.
+ else if ((address - XKPHYS0.start) < 0x400000FF80000000ULL)
+ seg = kernel_segs_lut[address >> 59 & 0xF];
+ }
+
+ // Check matching segment or return invalid.
+ if (likely((address - seg->start) < seg->length))
+ return seg;
+ }
+
+ return NULL;
+}
+
diff --git a/vr4300/segment.h b/vr4300/segment.h
new file mode 100644
index 000000000..35cfdb5d5
--- /dev/null
+++ b/vr4300/segment.h
@@ -0,0 +1,28 @@
+//
+// vr4300/segment.h: VR4300 MMU segment manager.
+//
+// CEN64: Cycle-Accurate Nintendo 64 Simulator.
+// Copyright (C) 2014, Tyler J. Stachecki.
+//
+// This file is subject to the terms and conditions defined in
+// 'LICENSE', which is part of this source code package.
+//
+
+#ifndef __vr4300_segment_h__
+#define __vr4300_segment_h__
+#include "common.h"
+
+struct segment {
+ uint64_t start;
+ uint64_t length;
+ uint64_t offset;
+
+ bool cached;
+ bool mapped;
+};
+
+const struct segment* get_default_segment(void);
+const struct segment* get_segment(uint64_t address, uint32_t cp0_status);
+
+#endif
+