Start executing PIF ROM.

This commit is contained in:
Tyler Stachecki 2014-03-09 22:02:31 -04:00
parent 2f3aded155
commit ca81cc95f5
20 changed files with 1196 additions and 250 deletions

23
bus/address.h Normal file
View file

@ -0,0 +1,23 @@
//
// bus/address.h: System bus address ranges.
//
// 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_address_h__
#define __bus_address_h__
/* Peripheral interface RAM. */
#define PIF_RAM_BASE_ADDRESS 0x1FC007C0
#define PIF_RAM_ADDRESS_LEN 0x00000040
/* Peripheral interface ROM. */
#define PIF_ROM_BASE_ADDRESS 0x1FC00000
#define PIF_ROM_ADDRESS_LEN 0x000007C0
#endif

View file

@ -9,28 +9,32 @@
//
#include "common.h"
#include "bus/address.h"
#include "bus/controller.h"
#include "bus/memorymap.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;
if ((bus->map = create_memory_map(1)) == NULL)
return -1;
map_address_range(bus->map, PIF_ROM_BASE_ADDRESS, PIF_ROM_ADDRESS_LEN,
bus->pif, read_pif_rom, write_pif_rom);
return 0;
}
// Issues a read request to the bus.
unsigned bus_read_word(struct bus_controller *bus,
int bus_read_word(struct bus_controller *bus,
uint32_t address, uint32_t *word) {
const struct memory_mapping *node;
if (address >= 0x1FC00000 && address < 0x1FC07C00)
return read_pifrom(bus->pif, word, address & 0xFFC);
if ((node = resolve_mapped_address(bus->map, address)) == NULL) {
fprintf(stderr, "bus_read_word: Failed to access: 0x%.8X\n", address);
abort();
}
printf("bus_read_word: Failed to access: 0x%.8X\n", address);
abort();
return 0;
return node->on_read(node->instance, address, word);
}

View file

@ -10,21 +10,21 @@
#ifndef __bus_controller_h__
#define __bus_controller_h__
#define BUS_REQUEST_QUEUE_SIZE 8
#include "common.h"
#include "memorymap.h"
struct bus_request;
struct vr4300;
struct bus_controller {
struct bus_request *rq[BUS_REQUEST_QUEUE_SIZE];
unsigned num_requests, rq_head, rq_tail;
struct memory_map *map;
struct pif_controller *pif;
struct vr4300 *vr4300;
};
int bus_init(struct bus_controller *bus);
unsigned bus_read_word(struct bus_controller *bus,
int bus_read_word(struct bus_controller *bus,
uint32_t address, uint32_t *word);
#endif

230
bus/memorymap.c Normal file
View file

@ -0,0 +1,230 @@
//
// bus/memorymap.c: System memory mapper.
//
// 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 "memorymap.h"
static void fixup(struct memory_map *, struct memory_map_node *);
static void rotate_left(struct memory_map *, struct memory_map_node *);
static void rotate_right(struct memory_map *, struct memory_map_node *);
// Creates a new memory map.
struct memory_map *create_memory_map(unsigned num_maps) {
struct memory_map_node *mappings;
struct memory_map *map;
size_t alloc_size = sizeof(*map) + sizeof(*mappings) * (num_maps + 1);
if ((map = (struct memory_map*) malloc(alloc_size)) == NULL)
return NULL;
mappings = (struct memory_map_node*) (map + 1);
// Initialize the allocation.
memset(map, 0, alloc_size);
map->mappings = mappings;
// Initialize the tree.
map->num_mappings = num_maps;
map->nil = &mappings[num_maps];
map->root = map->nil;
return map;
}
// Releases memory allocated for a memory map.
void destroy_memory_map(struct memory_map *memory_map) {
free(memory_map);
}
// Rebalances the tree after a node is inserted.
static void fixup(struct memory_map *map, struct memory_map_node *node) {
struct memory_map_node *cur;
// Rebalance the whole tree as needed.
while (node->parent->color == MEMORY_MAP_RED) {
if (node->parent == node->parent->parent->left) {
cur = node->parent->parent->right;
// Case 1: We only need to update colors.
if (cur->color == MEMORY_MAP_RED) {
node->parent->color = MEMORY_MAP_BLACK;
cur->color = MEMORY_MAP_BLACK;
node->parent->parent->color = MEMORY_MAP_RED;
node = node->parent->parent;
}
else {
// Case 2: We need to perform a left rotation.
if (node == node->parent->right) {
node = node->parent;
rotate_left(map, node);
}
// Case 3: We need to perform a right rotation.
node->parent->color = MEMORY_MAP_BLACK;
node->parent->parent->color = MEMORY_MAP_RED;
rotate_right(map, node->parent->parent);
}
}
else {
cur = node->parent->parent->left;
// Case 1: We only need to update colors.
if (cur->color == MEMORY_MAP_RED) {
node->parent->color = MEMORY_MAP_BLACK;
cur->color = MEMORY_MAP_BLACK;
node->parent->parent->color = MEMORY_MAP_RED;
node = node->parent->parent;
}
else {
// Case 2: We need to perform a right rotation.
if (node == node->parent->left) {
node = node->parent;
rotate_right(map, node);
}
// Case 3: We need to perform a left rotation.
node->parent->color = MEMORY_MAP_BLACK;
node->parent->parent->color = MEMORY_MAP_RED;
rotate_left(map, node->parent->parent);
}
}
}
// When we rebalanced the tree, we might have accidentally colored
// the root red, so unconditionally color if back after rebalancing.
map->root->color = MEMORY_MAP_BLACK;
}
// Inserts a mapping into the tree.
void map_address_range(struct memory_map *map, uint32_t start, uint32_t length,
void *instance, memory_function on_read, memory_function on_write) {
struct memory_map_node *check = map->root;
struct memory_map_node *cur = map->nil;
uint32_t end = start + length - 1;
struct memory_map_node *newNode;
struct memory_mapping mapping;
// Make sure we have enough space in the map.
assert(map->next_map_index < map->num_mappings &&
"Tried to insert into a memory_map with no free mappings.");
newNode = &map->mappings[map->next_map_index++];
// Walk down the tree.
while (check != map->nil) {
cur = check;
check = (start < cur->mapping.start)
? check->left : check->right;
}
// Insert the entry.
if (cur == map->nil)
map->root = newNode;
else if (start < cur->mapping.start)
cur->left = newNode;
else
cur->right = newNode;
newNode->left = map->nil;
newNode->right = map->nil;
newNode->parent = cur;
// Initialize the entry.
mapping.instance = instance;
mapping.on_read = on_read;
mapping.on_write = on_write;
mapping.end = end;
mapping.length = length;
mapping.start = start;
newNode->mapping = mapping;
// Rebalance the tree.
newNode->color = MEMORY_MAP_RED;
fixup(map, newNode);
}
// Returns a pointer to a region given an address.
const struct memory_mapping *resolve_mapped_address(
const struct memory_map *map, uint32_t address) {
const struct memory_map_node *cur = map->root;
do {
if (address < cur->mapping.start)
cur = cur->left;
else if (address > cur->mapping.end)
cur = cur->right;
else
return &cur->mapping;
} while (cur != map->nil);
return NULL;
}
// Performs a left rotation centered at n.
static void rotate_left(struct memory_map *map, struct memory_map_node *n) {
struct memory_map_node *y = n->right;
// Turn y's left subtree into n's right subtree.
n->right = y->left;
if (y->left != map->nil)
y->left->parent = n;
// Link n's parent to y.
y->parent = n->parent;
if (n->parent == map->nil)
map->root = y;
else if (n == n->parent->left)
n->parent->left = y;
else
n->parent->right = y;
// Put n on y's left.
y->left = n;
n->parent = y;
}
// Performs a right rotation centered at n.
static void rotate_right(struct memory_map *map, struct memory_map_node *n) {
struct memory_map_node *y = n->left;
// Turn y's right subtree into n's left subtree.
n->left = y->right;
if (y->right != map->nil)
y->right->parent = n;
// Link n's parent to y.
y->parent = n->parent;
if (n->parent == map->nil)
map->root = y;
else if (n == n->parent->left)
n->parent->left = y;
else
n->parent->right = y;
// Put n on y's right.
y->right = n;
n->parent = y;
}

63
bus/memorymap.h Normal file
View file

@ -0,0 +1,63 @@
//
// bus/memory_map.h: System memory mapper.
//
// 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_memory_map_h__
#define __bus_memory_map_h__
#include "common.h"
// Callback functions to handle reads/writes.
typedef int (*memory_function)(void *, uint32_t, uint32_t *);
enum memory_map_color {
MEMORY_MAP_BLACK,
MEMORY_MAP_RED
};
struct memory_mapping {
void *instance;
memory_function on_read;
memory_function on_write;
uint32_t length;
uint32_t start;
uint32_t end;
};
struct memory_map_node {
struct memory_map_node *left;
struct memory_map_node *parent;
struct memory_map_node *right;
struct memory_mapping mapping;
enum memory_map_color color;
};
struct memory_map {
struct memory_map_node *mappings;
struct memory_map_node *nil;
struct memory_map_node *root;
unsigned next_map_index;
unsigned num_mappings;
};
struct memory_map* create_memory_map(unsigned num_mappings);
void destroy_memory_map(struct memory_map *memory_map);
void map_address_range(struct memory_map *memory_map,
uint32_t start, uint32_t length, void *instance,
memory_function on_read, memory_function on_write);
const struct memory_mapping* resolve_mapped_address(
const struct memory_map *memory_map, uint32_t address);
#endif

View file

@ -82,5 +82,22 @@ typedef char bool;
#define unused(decl) decl
#endif
// Byte order swap functions.
static inline uint32_t byteswap_32(uint32_t word) {
#ifdef BIG_ENDIAN_HOST
return word;
#elif defined(_MSC_VER)
return _byteswap_ulong(word);
#elif defined(__GNUC__)
return __builtin_bswap32(word);
#else
return
(((((word) >> 24) & 0x000000FF) | \
(((word) >> 8) & 0x0000FF00) | \
(((word) << 8) & 0x00FF0000) | \
(((word) << 24) & 0xFF000000));
#endif
}
#endif

View file

@ -61,6 +61,9 @@ struct cen64_device *device_create(const char *pifrom) {
}
// Initialize the bus.
device->bus.pif = &device->pif;
device->bus.vr4300 = &device->vr4300;
if (bus_init(&device->bus)) {
printf("create_device: Failed to initialize the bus.\n");
@ -68,9 +71,6 @@ struct cen64_device *device_create(const char *pifrom) {
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");

View file

@ -9,6 +9,7 @@
//
#include "common.h"
#include "bus/address.h"
#include "bus/controller.h"
#include "pif/controller.h"
@ -21,11 +22,20 @@ int init_pif(struct pif_controller *pif,
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.");
// Reads a word from PIF ROM.
int read_pif_rom(void *opaque, uint32_t address, uint32_t *word) {
struct pif_controller *pif = (struct pif_controller*) opaque;
unsigned offset = address - PIF_ROM_BASE_ADDRESS;
memcpy(word, pif->rom + off, sizeof(*word));
memcpy(word, pif->rom + offset, sizeof(*word));
return 0;
}
// Writes a word to PIF ROM.
int write_pif_rom(void unused(*opaque),
uint32_t unused(address), uint32_t unused(*word)) {
assert("Attempt to write to PIF ROM.");
return -1;
}

View file

@ -22,7 +22,8 @@ struct pif_controller {
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);
int read_pif_rom(void *opaque, uint32_t address, uint32_t *word);
int write_pif_rom(void *opaque, uint32_t address, uint32_t *word);
#endif

View file

@ -10,9 +10,10 @@
#include "common.h"
#include "vr4300/cp0.h"
#include "vr4300/cpu.h"
// Initializes the coprocessor.
void vr4300_cp0_init(struct vr4300_cp0 *cp0) {
memset(cp0, 0, sizeof(*cp0));
void vr4300_cp0_init(struct vr4300 unused(*vr4300)) {
memset(vr4300->regs, 0, sizeof(*vr4300->regs) * NUM_VR4300_CP0_REGISTERS);
}

View file

@ -12,41 +12,39 @@
#define __vr4300_cp0_h__
#include "common.h"
struct vr4300;
// 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,
VR4300_CP0_REGISTER_INDEX = 32,
VR4300_CP0_REGISTER_RANDOM = 33,
VR4300_CP0_REGISTER_ENTRYLO0 = 34,
VR4300_CP0_REGISTER_ENTRYLO1 = 35,
VR4300_CP0_REGISTER_CONTEXT = 36,
VR4300_CP0_REGISTER_PAGEMASK = 37,
VR4300_CP0_REGISTER_WIRED = 38,
VR4300_CP0_REGISTER_BADVADDR = 40,
VR4300_CP0_REGISTER_COUNT = 41,
VR4300_CP0_REGISTER_ENTRYHI = 42,
VR4300_CP0_REGISTER_COMPARE = 43,
VR4300_CP0_REGISTER_STATUS = 44,
VR4300_CP0_REGISTER_CAUSE = 45,
VR4300_CP0_REGISTER_EPC = 46,
VR4300_CP0_REGISTER_PRID = 47,
VR4300_CP0_REGISTER_CONFIG = 48,
VR4300_CP0_REGISTER_LLADDR = 49,
VR4300_CP0_REGISTER_WATCHLO = 50,
VR4300_CP0_REGISTER_WATCHHI = 51,
VR4300_CP0_REGISTER_XCONTEXT = 52,
VR4300_CP0_REGISTER_PARITYERROR = 58,
VR4300_CP0_REGISTER_CACHEERR = 59,
VR4300_CP0_REGISTER_TAGLO = 60,
VR4300_CP0_REGISTER_TAGHI = 61,
VR4300_CP0_REGISTER_ERROREPC = 62,
NUM_VR4300_CP0_REGISTERS = 32,
};
struct vr4300_cp0 {
uint64_t regs[NUM_VR4300_CP0_REGISTERS];
};
void vr4300_cp0_init(struct vr4300_cp0 *cp0);
void vr4300_cp0_init(struct vr4300 *vr4300);
#endif

View file

@ -24,7 +24,7 @@ static void vr4300_connect_bus(struct vr4300 *vr4300,
int vr4300_init(struct vr4300 *vr4300, struct bus_controller *bus) {
vr4300_connect_bus(vr4300, bus);
vr4300_cp0_init(&vr4300->cp0);
vr4300_cp0_init(vr4300);
vr4300_icache_init(&vr4300->icache);
vr4300_pipeline_init(&vr4300->pipeline);

View file

@ -33,14 +33,42 @@ enum vr4300_register {
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
VR4300_REGISTER_FP, VR4300_REGISTER_RA,
// CP0 registers.
VR4300_REGISTER_CP0_0, VR4300_REGISTER_CP0_1, VR4300_REGISTER_CP0_2,
VR4300_REGISTER_CP0_3, VR4300_REGISTER_CP0_4, VR4300_REGISTER_CP0_5,
VR4300_REGISTER_CP0_6, VR4300_REGISTER_CP0_7, VR4300_REGISTER_CP0_8,
VR4300_REGISTER_CP0_9, VR4300_REGISTER_CP0_10, VR4300_REGISTER_CP0_11,
VR4300_REGISTER_CP0_12, VR4300_REGISTER_CP0_13, VR4300_REGISTER_CP0_14,
VR4300_REGISTER_CP0_15, VR4300_REGISTER_CP0_16, VR4300_REGISTER_CP0_17,
VR4300_REGISTER_CP0_18, VR4300_REGISTER_CP0_19, VR4300_REGISTER_CP0_20,
VR4300_REGISTER_CP0_21, VR4300_REGISTER_CP0_22, VR4300_REGISTER_CP0_23,
VR4300_REGISTER_CP0_24, VR4300_REGISTER_CP0_25, VR4300_REGISTER_CP0_26,
VR4300_REGISTER_CP0_27, VR4300_REGISTER_CP0_28, VR4300_REGISTER_CP0_29,
VR4300_REGISTER_CP0_30, VR4300_REGISTER_CP0_31,
// CP1 registers.
VR4300_REGISTER_CP1_0, VR4300_REGISTER_CP1_1, VR4300_REGISTER_CP1_2,
VR4300_REGISTER_CP1_3, VR4300_REGISTER_CP1_4, VR4300_REGISTER_CP1_5,
VR4300_REGISTER_CP1_6, VR4300_REGISTER_CP1_7, VR4300_REGISTER_CP1_8,
VR4300_REGISTER_CP1_9, VR4300_REGISTER_CP1_10, VR4300_REGISTER_CP1_11,
VR4300_REGISTER_CP1_12, VR4300_REGISTER_CP1_13, VR4300_REGISTER_CP1_14,
VR4300_REGISTER_CP1_15, VR4300_REGISTER_CP1_16, VR4300_REGISTER_CP1_17,
VR4300_REGISTER_CP1_18, VR4300_REGISTER_CP1_19, VR4300_REGISTER_CP1_20,
VR4300_REGISTER_CP1_21, VR4300_REGISTER_CP1_22, VR4300_REGISTER_CP1_23,
VR4300_REGISTER_CP1_24, VR4300_REGISTER_CP1_25, VR4300_REGISTER_CP1_26,
VR4300_REGISTER_CP1_27, VR4300_REGISTER_CP1_28, VR4300_REGISTER_CP1_29,
VR4300_REGISTER_CP1_30, VR4300_REGISTER_CP1_31,
// Miscellanious registers.
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;

View file

@ -23,10 +23,12 @@
#define OPCODE_INFO_NONE (0)
#define OPCODE_INFO_BRANCH (1 << 1)
#define OPCODE_INFO_NEEDRS (1 << 2)
#define OPCODE_INFO_NEEDRT (1 << 3)
struct vr4300_opcode {
uint8_t id;
uint8_t flags;
uint32_t id;
uint32_t flags;
};
const struct vr4300_opcode* vr4300_decode_instruction(uint32_t);

View file

@ -15,6 +15,9 @@
#include "vr4300/fault.h"
#include "vr4300/pipeline.h"
// Currently used a fixed value...
#define MEMORY_CYCLE_DELAY 50
const char *vr4300_fault_mnemonics[NUM_VR4300_FAULTS] = {
#define X(fault) #fault,
#include "vr4300/fault.md"
@ -47,9 +50,60 @@ static void vr4300_dc_fault(struct vr4300_pipeline *pipeline,
pipeline->icrf_latch.common.fault = fault;
}
// DADE: Data address error exception
void VR4300_DADE(unused(struct vr4300 *vr4300)) {
abort(); // Hammertime!
}
// DCB: Data cache busy interlock.
void VR4300_DCB(struct vr4300 *vr4300) {
struct vr4300_pipeline *pipeline = &vr4300->pipeline;
struct vr4300_exdc_latch *exdc_latch = &pipeline->exdc_latch;
struct vr4300_bus_request *request = &exdc_latch->request;
vr4300_common_interlocks(pipeline, MEMORY_CYCLE_DELAY, 5);
bus_read_word(vr4300->bus, request->address & ~0x3U, &request->word);
}
// IADE: Instruction address error exception
void VR4300_IADE(unused(struct vr4300 *vr4300)) {
abort();
abort(); // Hammertime!
}
// LDI: Load delay interlock.
void VR4300_LDI(struct vr4300 *vr4300) {
struct vr4300_pipeline *pipeline = &vr4300->pipeline;
struct vr4300_exdc_latch *exdc_latch = &pipeline->exdc_latch;
// We'll do EX again, but clear the 'busy' flag.
exdc_latch->request.type = VR4300_BUS_REQUEST_NONE;
vr4300_common_interlocks(pipeline, 0, 2);
}
// RST: External reset exception.
void VR4300_RST(struct vr4300 *vr4300) {
struct vr4300_pipeline *pipeline = &vr4300->pipeline;
// 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;
vr4300->regs[VR4300_CP0_REGISTER_STATUS] &= ~0x08300000ULL;
vr4300->regs[VR4300_CP0_REGISTER_CONFIG] &= ~0xFFFF7FF0ULL;
vr4300->regs[VR4300_CP0_REGISTER_STATUS] |= 0x00400004ULL;
vr4300->regs[VR4300_CP0_REGISTER_CONFIG] |= 0x7006E460ULL;
vr4300->regs[VR4300_CP0_REGISTER_RANDOM] = 31;
}
// Soft reset exception.
else
abort();
}
// UNC: Uncached read interlock.
@ -60,37 +114,10 @@ void VR4300_UNC(struct vr4300 *vr4300) {
const struct segment *segment = icrf_latch->segment;
uint64_t address;
vr4300_common_interlocks(pipeline, ~0, 4);
vr4300_common_interlocks(pipeline, MEMORY_CYCLE_DELAY, 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();
rfex_latch->iw = byteswap_32(rfex_latch->iw);
}

384
vr4300/functions.c Normal file
View file

@ -0,0 +1,384 @@
//
// vr4300/functions.c: VR4300 execution functions.
//
// 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.
//
#define VR4300_BUILD_FUNCS
#include "common.h"
#include "cpu.h"
#include "decoder.h"
#include "pipeline.h"
// Mask to negate second operand if subtract operation.
cen64_align(static const uint64_t vr4300_addsub_lut[2], 16) = {
0x0ULL, ~0x0ULL
};
// Mask to select outputs for bitwise operations.
cen64_align(static const uint64_t vr4300_bitwise_lut[4][2], 64) = {
{~0ULL, 0ULL}, // AND
{~0ULL, ~0ULL}, // OR
{ 0ULL, ~0ULL}, // XOR
{ 0ULL, 0ULL}, // -
};
// Mask to kill the instruction word if "likely" branch.
cen64_align(static const uint32_t vr4300_branch_lut[2], 8) = {
~0U, 0U
};
// Mask to selectively sign-extend loaded values.
cen64_align(static const uint64_t vr4300_load_sex_mask[2], 16) = {
~0ULL, 0ULL
};
//
// ADD
// SUB
//
void VR4300_ADD_SUB(struct vr4300 *vr4300, uint64_t rs, uint64_t rt) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t iw = rfex_latch->iw;
uint64_t mask = vr4300_addsub_lut[iw & 0x1];
unsigned dest;
uint64_t rd;
dest = GET_RD(iw);
rt = (rt ^ mask) - mask;
rd = rs + rt;
assert(((rd >> 31) == (rd >> 32)) && "Overflow exception.");
exdc_latch->result = (int32_t) rd;
exdc_latch->dest = dest;
}
//
// ADDI
// SUBI
//
void VR4300_ADDI_SUBI(struct vr4300 *vr4300, uint64_t rs, uint64_t rt) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t iw = rfex_latch->iw;
uint64_t mask = vr4300_addsub_lut[iw & 0x1];
unsigned dest;
dest = GET_RT(iw);
rt = (int16_t) iw;
rt = (rt ^ mask) - mask;
rt = rs + rt;
assert(((rt >> 31) == (rt >> 32)) && "Overflow exception.");
exdc_latch->result = (int32_t) rt;
exdc_latch->dest = dest;
}
//
// ADDIU
// SUBIU
//
void VR4300_ADDIU_SUBIU(struct vr4300 *vr4300, uint64_t rs, uint64_t rt) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t iw = rfex_latch->iw;
uint64_t mask = vr4300_addsub_lut[iw & 0x1];
unsigned dest;
dest = GET_RT(iw);
rt = (int16_t) iw;
rt = (rt ^ mask) - mask;
rt = rs + rt;
exdc_latch->result = (int32_t) rt;
exdc_latch->dest = dest;
}
//
// ADDU
// SUBU
//
void VR4300_ADDU_SUBU(struct vr4300 *vr4300, uint64_t rs, uint64_t rt) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t iw = rfex_latch->iw;
uint64_t mask = vr4300_addsub_lut[iw & 0x1];
unsigned dest;
uint64_t rd;
dest = GET_RD(iw);
rt = (rt ^ mask) - mask;
rd = rs + rt;
exdc_latch->result = (int32_t) rd;
exdc_latch->dest = dest;
}
//
// AND
// OR
// XOR
//
void VR4300_AND_OR_XOR(struct vr4300 *vr4300, uint64_t rs, uint64_t rt) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t iw = rfex_latch->iw;
uint64_t and_mask = vr4300_bitwise_lut[iw >> 26 & 0x3][0];
uint64_t xor_mask = vr4300_bitwise_lut[iw >> 26 & 0x3][1];
unsigned dest;
uint64_t rd;
dest = GET_RD(iw);
rd = ((rs & rt) & and_mask) | ((rs ^ rt) & xor_mask);
exdc_latch->result = rd;
exdc_latch->dest = dest;
}
//
// ANDI
// ORI
// XORI
//
void VR4300_ANDI_ORI_XORI(struct vr4300 *vr4300, uint64_t rs, uint64_t rt) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t iw = rfex_latch->iw;
uint64_t and_mask = vr4300_bitwise_lut[iw >> 26 & 0x3][0];
uint64_t xor_mask = vr4300_bitwise_lut[iw >> 26 & 0x3][1];
uint64_t or_mask = and_mask & xor_mask;
unsigned dest;
dest = GET_RT(iw);
rt = (uint16_t) iw;
rs = (or_mask) ? (uint64_t) ((int16_t) rs) : rs;
rt = ((rs & rt) & and_mask) | ((rs ^ rt) & xor_mask);
exdc_latch->result = (uint16_t) rt;
exdc_latch->dest = dest;
}
//
// BEQ
// BEQL
// BNE
// BNEL
//
void VR4300_BEQ_BEQL_BNE_BNEL(struct vr4300 *vr4300, uint64_t rs, uint64_t rt) {
struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
uint32_t iw = rfex_latch->iw;
uint32_t mask = vr4300_branch_lut[iw >> 30 & 0x1];
uint64_t offset = (int16_t) iw << 2;
bool is_eq = iw >> 26 & 0x1;
bool cmp = rs == rt;
if (cmp != is_eq) {
rfex_latch->iw_mask = mask;
return;
}
icrf_latch->pc = rfex_latch->common.pc + (offset + 4);
}
//
// BGEZ
// BGEZL
// BLTZ
// BLTZL
//
void VR4300_BGEZ_BGEZL_BLTZ_BLTZL(
struct vr4300 *vr4300, uint64_t rs, uint64_t unused(rt)) {
struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
uint32_t iw = rfex_latch->iw;
uint32_t mask = vr4300_branch_lut[iw >> 27 & 0x1];
uint64_t offset = (int16_t) iw << 2;
bool is_lt = iw >> 26 & 0x1;
bool cmp = (int64_t) rs < 0;
if (cmp != is_lt) {
rfex_latch->iw_mask = mask;
return;
}
icrf_latch->pc = rfex_latch->common.pc + (offset + 4);
}
//
// BGEZAL
// BGEZALL
// BLTZAL
// BLTZALL
//
void VR4300_BGEZAL_BGEZALL_BLTZAL_BLTZALL(
struct vr4300 *vr4300, uint64_t rs, uint64_t unused(rt)) {
struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t iw = rfex_latch->iw;
uint32_t mask = vr4300_branch_lut[iw >> 27 & 0x1];
uint64_t offset = (int16_t) iw << 2;
bool is_lt = iw >> 26 & 0x1;
bool cmp = (int64_t) rs < 0;
if (cmp != is_lt) {
rfex_latch->iw_mask = mask;
return;
}
icrf_latch->pc = rfex_latch->common.pc + (offset + 4);
exdc_latch->result = rfex_latch->common.pc + 4;
exdc_latch->dest = VR4300_REGISTER_RA;
}
//
// BGTZ
// BGTZL
// BLEZ
// BLEZL
//
void VR4300_BGTZ_BGTZL_BLEZ_BLEZL(
struct vr4300 *vr4300, uint64_t rs, uint64_t unused(rt)) {
struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
uint32_t iw = rfex_latch->iw;
uint32_t mask = vr4300_branch_lut[iw >> 30 & 0x1];
uint64_t offset = (int16_t) iw << 2;
bool is_le = iw >> 26 & 0x1;
bool cmp = (int64_t) rs <= 0;
if (cmp != is_le) {
rfex_latch->iw_mask = mask;
return;
}
icrf_latch->pc = rfex_latch->common.pc + (offset + 4);
}
//
// INV
//
void VR4300_INV(struct vr4300 *vr4300,
uint64_t unused(rs), uint64_t unused(rt)) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
enum vr4300_opcode_id opcode = rfex_latch->opcode.id;
#ifndef NDEBUG
fprintf(stderr, "Unimplemented instruction: %s [0x%.8X] @ 0x%.16llX\n",
vr4300_opcode_mnemonics[opcode], rfex_latch->iw, (long long unsigned)
rfex_latch->common.pc);
#endif
assert(0 && "Unimplemented instruction encountered.");
}
//
// LB
// LBU
// LH
// LHU
// LW
// LWU
//
// TODO/FIXME: Check for unaligned addresses.
//
void VR4300_LOAD(struct vr4300 *vr4300, uint64_t rs, uint64_t unused(rt)) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t iw = rfex_latch->iw;
uint64_t sex_mask = vr4300_load_sex_mask[iw >> 28 & 0x1];
unsigned dest = GET_RT(iw);
exdc_latch->request.address = rs + (int16_t) iw;
exdc_latch->request.type = VR4300_BUS_REQUEST_READ;
exdc_latch->request.size = iw >> 26 & 0x3;
exdc_latch->result = sex_mask;
exdc_latch->dest = dest;
}
//
// LUI
//
void VR4300_LUI(struct vr4300 *vr4300,
uint64_t unused(rs), uint64_t unused(rt)) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t iw = rfex_latch->iw;
uint64_t imm = (int16_t) iw << 16;
unsigned dest = GET_RT(iw);
exdc_latch->result = imm;
exdc_latch->dest = dest;
}
//
// MTC0
// TODO/FIXME: Combine with MTC{1,2}?
//
void VR4300_MTCx(struct vr4300 *vr4300, uint64_t unused(rs), uint64_t rt) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t iw = rfex_latch->iw;
unsigned dest = GET_RD(iw) + 32;
// TODO/FIXME: Sign extend, or...?
// Would make sense for EPC, etc.
exdc_latch->result = (int32_t) rt;
exdc_latch->dest = dest;
}
//
// SLL
// TODO/FIXME: Implement.
//
void VR4300_SLLx(struct vr4300 *vr4300,
uint64_t unused(rs), uint64_t unused(rt)) {
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
exdc_latch->result = 0x00000000;
exdc_latch->dest = 0;
}
// Function lookup table.
cen64_align(const vr4300_function
vr4300_function_table[NUM_VR4300_OPCODES], CACHE_LINE_SIZE) = {
#define X(op) op,
#include "vr4300/opcodes.md"
#undef X
};

View file

@ -19,172 +19,181 @@ enum vr4300_opcode_id {
#undef X
};
struct vr4300;
typedef void (*const vr4300_function)(struct vr4300 *, uint64_t, uint64_t);
extern const vr4300_function vr4300_function_table[NUM_VR4300_OPCODES];
extern const char *vr4300_opcode_mnemonics[NUM_VR4300_OPCODES];
/* Flags for each instruction. */
#define VR4300_BUILD_OP(op, flags) \
#ifdef VR4300_BUILD_FUNCS
#define VR4300_BUILD_OP(op, func, flags) \
(VR4300_##func)
#else
#define VR4300_BUILD_OP(op, func, flags) \
(VR4300_OPCODE_##op), (flags)
#endif
#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 INVALID VR4300_BUILD_OP(INVALID, 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 BC0 VR4300_BUILD_OP(BC0, INV, INFO1(BRANCH))
#define BC1 VR4300_BUILD_OP(BC1, INV, INFO1(BRANCH))
#define BC2 VR4300_BUILD_OP(BC1, INV, INFO1(BRANCH))
#define FPUS VR4300_BUILD_OP(FPUS, INV, INFO1(NONE))
#define FPUD VR4300_BUILD_OP(FPUD, INV, INFO1(NONE))
#define FPUW VR4300_BUILD_OP(FPUW, INV, INFO1(NONE))
#define FPUL VR4300_BUILD_OP(FPUL, INV, INFO1(NONE))
#define TLB VR4300_BUILD_OP(TLB, INV, 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))
#define ADD VR4300_BUILD_OP(ADD, ADD_SUB, INFO2(NEEDRS, NEEDRT))
#define ADDI VR4300_BUILD_OP(ADDI, ADDI_SUBI, INFO1(NEEDRS))
#define ADDIU VR4300_BUILD_OP(ADDIU, ADDIU_SUBIU, INFO1(NEEDRS))
#define ADDU VR4300_BUILD_OP(ADDU, ADDU_SUBU, INFO2(NEEDRS, NEEDRT))
#define AND VR4300_BUILD_OP(AND, AND_OR_XOR, INFO2(NEEDRS, NEEDRT))
#define ANDI VR4300_BUILD_OP(ANDI, ANDI_ORI_XORI, INFO1(NEEDRS))
#define BEQ VR4300_BUILD_OP(BEQ, BEQ_BEQL_BNE_BNEL, INFO3(BRANCH, NEEDRS, NEEDRT))
#define BEQL VR4300_BUILD_OP(BEQL, BEQ_BEQL_BNE_BNEL, INFO3(BRANCH, NEEDRS, NEEDRT))
#define BGEZ VR4300_BUILD_OP(BGEZ, BGEZ_BGEZL_BLTZ_BLTZL, INFO2(BRANCH, NEEDRS))
#define BGEZAL VR4300_BUILD_OP(BGEZAL, BGEZAL_BGEZALL_BLTZAL_BLTZALL, INFO2(BRANCH, NEEDRS))
#define BGEZALL VR4300_BUILD_OP(BGEZALL, BGEZAL_BGEZALL_BLTZAL_BLTZALL, INFO2(BRANCH, NEEDRS))
#define BGEZL VR4300_BUILD_OP(BGEZL, BGEZ_BGEZL_BLTZ_BLTZL, INFO2(BRANCH, NEEDRS))
#define BGTZ VR4300_BUILD_OP(BGTZ, BGTZ_BGTZL_BLEZ_BLEZL, INFO2(BRANCH, NEEDRS))
#define BGTZL VR4300_BUILD_OP(BGTZL, BGTZ_BGTZL_BLEZ_BLEZL, INFO2(BRANCH, NEEDRS))
#define BLEZ VR4300_BUILD_OP(BLEZ, BGTZ_BGTZL_BLEZ_BLEZL, INFO2(BRANCH, NEEDRS))
#define BLEZL VR4300_BUILD_OP(BLEZL, BGTZ_BGTZL_BLEZ_BLEZL, INFO2(BRANCH, NEEDRS))
#define BLTZ VR4300_BUILD_OP(BLTZ, BGEZ_BGEZL_BLTZ_BLTZL, INFO2(BRANCH, NEEDRS))
#define BLTZAL VR4300_BUILD_OP(BLTZAL, BGEZAL_BGEZALL_BLTZAL_BLTZALL, INFO2(BRANCH, NEEDRS))
#define BLTZALL VR4300_BUILD_OP(BLTZALL, BGEZAL_BGEZALL_BLTZAL_BLTZALL, INFO2(BRANCH, NEEDRS))
#define BLTZL VR4300_BUILD_OP(BLTZL, BGEZ_BGEZL_BLTZ_BLTZL, INFO2(BRANCH, NEEDRS))
#define BNE VR4300_BUILD_OP(BNE, BEQ_BEQL_BNE_BNEL, INFO3(BRANCH, NEEDRS, NEEDRT))
#define BNEL VR4300_BUILD_OP(BNEL, BEQ_BEQL_BNE_BNEL, INFO3(BRANCH, NEEDRS, NEEDRT))
#define BREAK VR4300_BUILD_OP(BREAK, INV, INFO1(NONE))
#define CACHE VR4300_BUILD_OP(CACHE, INV, INFO1(NONE))
#define CFC0 VR4300_BUILD_OP(CFC0, INV, INFO1(NONE))
#define CFC1 VR4300_BUILD_OP(CFC1, INV, INFO1(NONE))
#define CFC2 VR4300_BUILD_OP(CFC2, INV, INFO1(NONE))
#define COP0 VR4300_BUILD_OP(COP0, INV, INFO1(NONE))
#define COP1 VR4300_BUILD_OP(COP1, INV, INFO1(NONE))
#define COP2 VR4300_BUILD_OP(COP2, INV, INFO1(NONE))
#define CTC0 VR4300_BUILD_OP(CTC0, INV, INFO1(NONE))
#define CTC1 VR4300_BUILD_OP(CTC1, INV, INFO1(NONE))
#define CTC2 VR4300_BUILD_OP(CTC2, INV, INFO1(NONE))
#define DADD VR4300_BUILD_OP(DADD, INV, INFO1(NONE))
#define DADDI VR4300_BUILD_OP(DADDI, INV, INFO1(NONE))
#define DADDIU VR4300_BUILD_OP(DADDIU, INV, INFO1(NONE))
#define DADDU VR4300_BUILD_OP(DADDU, INV, INFO1(NONE))
#define DDIV VR4300_BUILD_OP(DDIV, INV, INFO1(NONE))
#define DDIVU VR4300_BUILD_OP(DDIVU, INV, INFO1(NONE))
#define DIV VR4300_BUILD_OP(DIV, INV, INFO1(NONE))
#define DIVU VR4300_BUILD_OP(DIVU, INV, INFO1(NONE))
#define DMFC0 VR4300_BUILD_OP(DMFC0, INV, INFO1(NONE))
#define DMFC1 VR4300_BUILD_OP(DMFC1, INV, INFO1(NONE))
#define DMFC2 VR4300_BUILD_OP(DMFC2, INV, INFO1(NONE))
#define DMTC0 VR4300_BUILD_OP(DMTC0, INV, INFO1(NONE))
#define DMTC1 VR4300_BUILD_OP(DMTC1, INV, INFO1(NONE))
#define DMTC2 VR4300_BUILD_OP(DMTC2, INV, INFO1(NONE))
#define DMULT VR4300_BUILD_OP(DMULT, INV, INFO1(NONE))
#define DMULTU VR4300_BUILD_OP(DMULTU, INV, INFO1(NONE))
#define DSLL VR4300_BUILD_OP(DSLL, INV, INFO1(NONE))
#define DSLLV VR4300_BUILD_OP(DSLLV, INV, INFO1(NONE))
#define DSLL32 VR4300_BUILD_OP(DSLL32, INV, INFO1(NONE))
#define DSRA VR4300_BUILD_OP(DSRA, INV, INFO1(NONE))
#define DSRAV VR4300_BUILD_OP(DSRAV, INV, INFO1(NONE))
#define DSRA32 VR4300_BUILD_OP(DSRA32, INV, INFO1(NONE))
#define DSRL VR4300_BUILD_OP(DSRL, INV, INFO1(NONE))
#define DSRLV VR4300_BUILD_OP(DSRLV, INV, INFO1(NONE))
#define DSRL32 VR4300_BUILD_OP(DSRL32, INV, INFO1(NONE))
#define DSUB VR4300_BUILD_OP(DSUB, INV, INFO1(NONE))
#define DSUBU VR4300_BUILD_OP(DSUBU, INV, INFO1(NONE))
#define ERET VR4300_BUILD_OP(ERET, INV, INFO1(NONE))
#define J VR4300_BUILD_OP(J, INV, INFO1(BRANCH))
#define JAL VR4300_BUILD_OP(JAL, INV, INFO1(BRANCH))
#define JALR VR4300_BUILD_OP(JALR, INV, INFO1(BRANCH))
#define JR VR4300_BUILD_OP(JR, INV, INFO1(BRANCH))
#define LB VR4300_BUILD_OP(LB, LOAD, INFO1(NEEDRT))
#define LBU VR4300_BUILD_OP(LBU, LOAD, INFO1(NEEDRT))
#define LD VR4300_BUILD_OP(LD, INV, INFO1(NONE))
#define LDC0 VR4300_BUILD_OP(LDC0, INV, INFO1(NONE))
#define LDC1 VR4300_BUILD_OP(LDC1, INV, INFO1(NONE))
#define LDC2 VR4300_BUILD_OP(LDC2, INV, INFO1(NONE))
#define LDL VR4300_BUILD_OP(LDL, INV, INFO1(NONE))
#define LDR VR4300_BUILD_OP(LDR, INV, INFO1(NONE))
#define LH VR4300_BUILD_OP(LH, LOAD, INFO1(NEEDRT))
#define LHU VR4300_BUILD_OP(LHU, LOAD, INFO1(NEEDRT))
#define LL VR4300_BUILD_OP(LL, INV, INFO1(NONE))
#define LLD VR4300_BUILD_OP(LLD, INV, INFO1(NONE))
#define LUI VR4300_BUILD_OP(LUI, LUI, INFO1(NONE))
#define LW VR4300_BUILD_OP(LW, LOAD, INFO1(NEEDRT))
#define LWC0 VR4300_BUILD_OP(LWC0, INV, INFO1(NONE))
#define LWC1 VR4300_BUILD_OP(LWC1, INV, INFO1(NONE))
#define LWC2 VR4300_BUILD_OP(LWC2, INV, INFO1(NONE))
#define LWL VR4300_BUILD_OP(LWL, INV, INFO1(NONE))
#define LWR VR4300_BUILD_OP(LWR, INV, INFO1(NONE))
#define LWU VR4300_BUILD_OP(LWU, LOAD, INFO1(NEEDRT))
#define MFC0 VR4300_BUILD_OP(MFC0, INV, INFO1(NONE))
#define MFC1 VR4300_BUILD_OP(MFC1, INV, INFO1(NONE))
#define MFC2 VR4300_BUILD_OP(MFC2, INV, INFO1(NONE))
#define MFHI VR4300_BUILD_OP(MFHI, INV, INFO1(NONE))
#define MFLO VR4300_BUILD_OP(MFLO, INV, INFO1(NONE))
#define MTC0 VR4300_BUILD_OP(MTC0, MTCx, INFO1(NEEDRT))
#define MTC1 VR4300_BUILD_OP(MTC1, INV, INFO1(NONE))
#define MTC2 VR4300_BUILD_OP(MTC2, INV, INFO1(NONE))
#define MTHI VR4300_BUILD_OP(MTHI, INV, INFO1(NONE))
#define MTLO VR4300_BUILD_OP(MTLO, INV, INFO1(NONE))
#define MULT VR4300_BUILD_OP(MULT, INV, INFO1(NONE))
#define MULTU VR4300_BUILD_OP(MULTU, INV, INFO1(NONE))
#define NOR VR4300_BUILD_OP(NOR, INV, INFO1(NONE))
#define OR VR4300_BUILD_OP(OR, AND_OR_XOR, INFO2(NEEDRS, NEEDRT))
#define ORI VR4300_BUILD_OP(ORI, ANDI_ORI_XORI, INFO1(NEEDRS))
#define SB VR4300_BUILD_OP(SB, INV, INFO1(NONE))
#define SC VR4300_BUILD_OP(SC, INV, INFO1(NONE))
#define SCD VR4300_BUILD_OP(SCD, INV, INFO1(NONE))
#define SD VR4300_BUILD_OP(SD, INV, INFO1(NONE))
#define SDC0 VR4300_BUILD_OP(SDC0, INV, INFO1(NONE))
#define SDC1 VR4300_BUILD_OP(SDC1, INV, INFO1(NONE))
#define SDC2 VR4300_BUILD_OP(SDC2, INV, INFO1(NONE))
#define SDL VR4300_BUILD_OP(SDL, INV, INFO1(NONE))
#define SDR VR4300_BUILD_OP(SDR, INV, INFO1(NONE))
#define SH VR4300_BUILD_OP(SH, INV, INFO1(NONE))
#define SLL VR4300_BUILD_OP(SLL, SLLx, INFO1(NONE))
#define SLLV VR4300_BUILD_OP(SLLV, INV, INFO1(NONE))
#define SLT VR4300_BUILD_OP(SLT, INV, INFO1(NONE))
#define SLTI VR4300_BUILD_OP(SLTI, INV, INFO1(NONE))
#define SLTIU VR4300_BUILD_OP(SLTIU, INV, INFO1(NONE))
#define SLTU VR4300_BUILD_OP(SLTU, INV, INFO1(NONE))
#define SRA VR4300_BUILD_OP(SRA, INV, INFO1(NONE))
#define SRAV VR4300_BUILD_OP(SRAV, INV, INFO1(NONE))
#define SRL VR4300_BUILD_OP(SRL, INV, INFO1(NONE))
#define SRLV VR4300_BUILD_OP(SRLV, INV, INFO1(NONE))
#define SUB VR4300_BUILD_OP(SUB, ADD_SUB, INFO2(NEEDRS, NEEDRT))
#define SUBU VR4300_BUILD_OP(SUBU, ADDU_SUBU, INFO1(NEEDRS))
#define SW VR4300_BUILD_OP(SW, INV, INFO1(NONE))
#define SWC0 VR4300_BUILD_OP(SWC0, INV, INFO1(NONE))
#define SWC1 VR4300_BUILD_OP(SWC1, INV, INFO1(NONE))
#define SWC2 VR4300_BUILD_OP(SWC2, INV, INFO1(NONE))
#define SWL VR4300_BUILD_OP(SWL, INV, INFO1(NONE))
#define SWR VR4300_BUILD_OP(SWR, INV, INFO1(NONE))
#define SYNC VR4300_BUILD_OP(SYNC, INV, INFO1(NONE))
#define SYSCALL VR4300_BUILD_OP(SYSCALL, INV, INFO1(NONE))
#define TEQ VR4300_BUILD_OP(TEQ, INV, INFO1(NONE))
#define TEQI VR4300_BUILD_OP(TEQI, INV, INFO1(NONE))
#define TGE VR4300_BUILD_OP(TGE, INV, INFO1(NONE))
#define TGEI VR4300_BUILD_OP(TGEI, INV, INFO1(NONE))
#define TGEIU VR4300_BUILD_OP(TGEIU, INV, INFO1(NONE))
#define TGEU VR4300_BUILD_OP(TGEU, INV, INFO1(NONE))
#define TLT VR4300_BUILD_OP(TLT, INV, INFO1(NONE))
#define TLTI VR4300_BUILD_OP(TLTI, INV, INFO1(NONE))
#define TLTIU VR4300_BUILD_OP(TLTIU, INV, INFO1(NONE))
#define TLTU VR4300_BUILD_OP(TLTU, INV, INFO1(NONE))
#define TNE VR4300_BUILD_OP(TNE, INV, INFO1(NONE))
#define TNEI VR4300_BUILD_OP(TNEI, INV, INFO1(NONE))
#define XOR VR4300_BUILD_OP(XOR, AND_OR_XOR, INFO2(NEEDRS, NEEDRT))
#define XORI VR4300_BUILD_OP(XORI, ANDI_ORI_XORI, INFO1(NEEDRS))
#endif

View file

@ -9,7 +9,7 @@
//
#ifndef VR4300_OPCODE_TABLE
#define VR4300_OPCODE_TABLE X(INV) \
#define VR4300_OPCODE_TABLE X(INVALID) \
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) \

View file

@ -13,20 +13,32 @@
#include "vr4300/cpu.h"
#include "vr4300/decoder.h"
#include "vr4300/fault.h"
#include "vr4300/opcodes.h"
#include "vr4300/pipeline.h"
#include "vr4300/segment.h"
// Prints out instructions and their virtual address as they are executed.
// Note: These instructions should _may_ be speculative and killed later...
//#define PRINT_EXEC
// Instruction cache stage.
static inline int vr4300_ic_stage (struct vr4300 *vr4300) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
const struct segment *segment = icrf_latch->segment;
uint64_t pc = icrf_latch->pc;
uint32_t decode_iw;
icrf_latch->common.pc = pc;
// Finish decoding instruction in RF.
decode_iw = rfex_latch->iw &= rfex_latch->iw_mask;
rfex_latch->opcode = *vr4300_decode_instruction(decode_iw);
rfex_latch->iw_mask = ~0U;
// 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];
uint32_t cp0_status = vr4300->regs[VR4300_CP0_REGISTER_STATUS];
if (unlikely((segment = get_segment(pc, cp0_status)) == NULL)) {
VR4300_IADE(vr4300);
@ -38,6 +50,7 @@ static inline int vr4300_ic_stage (struct vr4300 *vr4300) {
// We didn't have an IADE, so reset the status vector.
icrf_latch->common.fault = VR4300_FAULT_NONE;
icrf_latch->pc += 4;
return 0;
}
@ -60,18 +73,85 @@ static inline int vr4300_rf_stage (struct vr4300 *vr4300) {
// Execution stage.
static inline int vr4300_ex_stage (struct vr4300 *vr4300) {
const struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
const struct vr4300_dcwb_latch *dcwb_latch = &vr4300->pipeline.dcwb_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint64_t rs_reg, rt_reg, temp;
uint32_t flags, iw;
unsigned rs, rt;
exdc_latch->common = rfex_latch->common;
flags = rfex_latch->opcode.flags;
if (exdc_latch->request.type == VR4300_BUS_REQUEST_NONE)
flags &= ~(OPCODE_INFO_NEEDRS | OPCODE_INFO_NEEDRT);
iw = rfex_latch->iw;
rt = GET_RT(iw);
rs = GET_RS(iw);
// Check to see if we should hold off execution due to a LDI.
if (((dcwb_latch->dest == rs) && (flags & OPCODE_INFO_NEEDRS)) ||
((dcwb_latch->dest == rt) && (flags & OPCODE_INFO_NEEDRT))) {
VR4300_LDI(vr4300);
return 1;
}
// No LDI, so we just need to forward results from DC/WB.
// This is done to preserve RF state and fwd without branching.
temp = vr4300->regs[dcwb_latch->dest];
vr4300->regs[dcwb_latch->dest] = dcwb_latch->result;
vr4300->regs[VR4300_REGISTER_R0] = 0x0000000000000000ULL;
rs_reg = vr4300->regs[GET_RS(iw)];
rt_reg = vr4300->regs[GET_RT(iw)];
vr4300->regs[dcwb_latch->dest] = temp;
// Finally, execute the instruction.
#ifdef PRINT_EXEC
fprintf(stderr, "%.16llX: %s\n", (unsigned long long) rfex_latch->common.pc,
vr4300_opcode_mnemonics[rfex_latch->opcode.id]);
#endif
exdc_latch->request.type = VR4300_BUS_REQUEST_NONE;
vr4300_function_table[rfex_latch->opcode.id](vr4300, rs_reg, rt_reg);
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_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
struct vr4300_dcwb_latch *dcwb_latch = &vr4300->pipeline.dcwb_latch;
const struct segment *segment = exdc_latch->segment;
uint64_t address = exdc_latch->request.address;
dcwb_latch->common = exdc_latch->common;
dcwb_latch->result = exdc_latch->result;
dcwb_latch->dest = exdc_latch->dest;
// Look up the segment that we're in.
if (exdc_latch->request.type != VR4300_BUS_REQUEST_NONE) {
if ((address - segment->start) > segment->length) {
uint32_t cp0_status = vr4300->regs[VR4300_CP0_REGISTER_STATUS];
if (unlikely((segment = get_segment(address, cp0_status)) == NULL)) {
VR4300_DADE(vr4300);
return 1;
}
}
exdc_latch->segment = segment;
exdc_latch->request.address -= segment->offset;
if (exdc_latch->request.type == VR4300_BUS_REQUEST_READ) {
VR4300_DCB(vr4300); // TODO/FIXME: Not accurate.
return 1;
}
else
assert(0 && "Unsupported DC stage request type.");
}
return 0;
}
@ -82,6 +162,8 @@ static inline int vr4300_wb_stage (struct vr4300 *vr4300) {
if (dcwb_latch->common.fault != VR4300_FAULT_NONE)
return 0;
vr4300->regs[dcwb_latch->dest] = dcwb_latch->result;
vr4300->regs[VR4300_REGISTER_R0] = 0x0000000000000000ULL;
return 0;
}
@ -194,6 +276,48 @@ static void vr4300_cycle_slow_ex(struct vr4300 *vr4300) {
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).
// Fixes up the DC/WB latches after memory reads.
static void vr4300_cycle_slow_ex_fixdc(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;
struct vr4300_exdc_latch *exdc_latch = &pipeline->exdc_latch;
struct vr4300_dcwb_latch *dcwb_latch = &pipeline->dcwb_latch;
struct vr4300_bus_request *request = &exdc_latch->request;
uint32_t word = request->word, mask = ~0U;
mask = mask >> (32 - (request->size << 3));
mask = mask << (request->address & 0x3);
word &= mask;
// Shall we sign extend?
word = word >> (request->address & 0x3);
dcwb_latch->result = exdc_latch->result >> (request->address & 0x3);
dcwb_latch->result |= word;
// Continue with the rest of the pipeline.
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.
//
@ -227,12 +351,13 @@ static void vr4300_cycle_slow_ic(struct vr4300 *vr4300) {
// LUT of stages for fault handling.
typedef void (*pipeline_function)(struct vr4300 *vr4300);
static const pipeline_function pipeline_function_lut[5] = {
static const pipeline_function pipeline_function_lut[6] = {
vr4300_cycle_slow_wb,
vr4300_cycle_slow_dc,
vr4300_cycle_slow_ex,
vr4300_cycle_slow_rf,
vr4300_cycle_slow_ic,
vr4300_cycle_slow_ex_fixdc,
};
// Advances the processor pipeline by one pclock.
@ -281,5 +406,6 @@ void vr4300_pipeline_init(struct vr4300_pipeline *pipeline) {
memset(pipeline, 0, sizeof(*pipeline));
pipeline->icrf_latch.segment = get_default_segment();
pipeline->exdc_latch.segment = get_default_segment();
}

View file

@ -11,11 +11,26 @@
#ifndef __vr4300_pipeline_h__
#define __vr4300_pipeline_h__
#include "common.h"
#include "vr4300/decoder.h"
#include "vr4300/fault.h"
#include "vr4300/segment.h"
struct vr4300;
enum vr4300_bus_request_type {
VR4300_BUS_REQUEST_NONE,
VR4300_BUS_REQUEST_READ,
VR4300_BUS_REQUEST_WRITE,
};
struct vr4300_bus_request {
uint64_t address;
uint32_t word;
unsigned size;
enum vr4300_bus_request_type type;
};
struct vr4300_latch {
uint64_t pc;
enum vr4300_fault_id fault;
@ -30,15 +45,23 @@ struct vr4300_icrf_latch {
struct vr4300_rfex_latch {
struct vr4300_latch common;
uint32_t iw;
struct vr4300_opcode opcode;
uint32_t iw, iw_mask;
};
struct vr4300_exdc_latch {
struct vr4300_latch common;
const struct segment *segment;
int64_t result;
uint32_t dest;
struct vr4300_bus_request request;
};
struct vr4300_dcwb_latch {
struct vr4300_latch common;
int64_t result;
uint32_t dest;
};
struct vr4300_pipeline {