mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-22 22:12:45 -04:00
Start executing PIF ROM.
This commit is contained in:
parent
2f3aded155
commit
ca81cc95f5
23
bus/address.h
Normal file
23
bus/address.h
Normal 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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
230
bus/memorymap.c
Normal 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
63
bus/memorymap.h
Normal 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
|
||||
|
17
common.h
17
common.h
|
@ -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
|
||||
|
||||
|
|
6
device.c
6
device.c
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
58
vr4300/cp0.h
58
vr4300/cp0.h
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
34
vr4300/cpu.h
34
vr4300/cpu.h
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
384
vr4300/functions.c
Normal 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
|
||||
};
|
||||
|
317
vr4300/opcodes.h
317
vr4300/opcodes.h
|
@ -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
|
||||
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue