mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-22 22:12:45 -04:00
VR4300: Start adding data cache support.
This commit is contained in:
parent
49cbfc8994
commit
656103920b
|
@ -33,6 +33,7 @@ int vr4300_init(struct vr4300 *vr4300, struct bus_controller *bus) {
|
|||
vr4300_connect_bus(vr4300, bus);
|
||||
|
||||
vr4300_cp0_init(vr4300);
|
||||
vr4300_dcache_init(&vr4300->dcache);
|
||||
vr4300_icache_init(&vr4300->icache);
|
||||
vr4300_pipeline_init(&vr4300->pipeline);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#define __vr4300_cpu_h__
|
||||
#include "common.h"
|
||||
#include "vr4300/cp0.h"
|
||||
#include "vr4300/dcache.h"
|
||||
#include "vr4300/icache.h"
|
||||
#include "vr4300/pipeline.h"
|
||||
|
||||
|
@ -81,6 +82,7 @@ struct vr4300 {
|
|||
uint64_t regs[NUM_VR4300_REGISTERS];
|
||||
uint32_t mi_regs[NUM_MI_REGISTERS];
|
||||
|
||||
struct vr4300_dcache dcache;
|
||||
struct vr4300_icache icache;
|
||||
struct vr4300_pipeline pipeline;
|
||||
|
||||
|
|
138
vr4300/dcache.c
Normal file
138
vr4300/dcache.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
//
|
||||
// vr4300/dcache.c: VR4300 instruction cache.
|
||||
//
|
||||
// CEN64: Cycle-Accurate Nintendo 64 Simulator.
|
||||
// Copyright (C) 2014, Tyler J. Stachecki.
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
#include "common.h"
|
||||
#include "vr4300/dcache.h"
|
||||
|
||||
static inline struct vr4300_dcache_line* get_line(
|
||||
struct vr4300_dcache *dcache, uint64_t vaddr);
|
||||
static inline const struct vr4300_dcache_line* get_line_const(
|
||||
const struct vr4300_dcache *dcache, uint64_t vaddr);
|
||||
|
||||
static inline uint32_t get_tag(const struct vr4300_dcache_line *line);
|
||||
static void invalidate_line(struct vr4300_dcache_line *line);
|
||||
static bool is_dirty(const struct vr4300_dcache_line *line);
|
||||
static bool is_valid(const struct vr4300_dcache_line *line);
|
||||
static void set_clean(struct vr4300_dcache_line *line);
|
||||
static void set_dirty(struct vr4300_dcache_line *line);
|
||||
static void set_tag(struct vr4300_dcache_line *line, uint32_t tag);
|
||||
static void validate_line(struct vr4300_dcache_line *line, uint32_t tag);
|
||||
|
||||
// Returns the line for a given virtual address.
|
||||
struct vr4300_dcache_line* get_line(
|
||||
struct vr4300_dcache *dcache, uint64_t vaddr) {
|
||||
return dcache->lines + (vaddr >> 4 & 0x1FF);
|
||||
}
|
||||
|
||||
// Returns the line for a given virtual address.
|
||||
const struct vr4300_dcache_line* get_line_const(
|
||||
const struct vr4300_dcache *dcache, uint64_t vaddr) {
|
||||
return dcache->lines + (vaddr >> 4 & 0x1FF);
|
||||
}
|
||||
|
||||
// Returns the physical tag associated with the line.
|
||||
uint32_t get_tag(const struct vr4300_dcache_line *line) {
|
||||
return line->metadata >> 12;
|
||||
}
|
||||
|
||||
// Invalidates the line, but leaves the physical tag untouched.
|
||||
void invalidate_line(struct vr4300_dcache_line *line) {
|
||||
line->metadata &= ~0x1;
|
||||
}
|
||||
|
||||
// Returns true if the line is valid, otherwise returns false.
|
||||
bool is_dirty(const struct vr4300_dcache_line *line) {
|
||||
return (line->metadata & 0x2) == 0x2;
|
||||
}
|
||||
|
||||
// Returns true if the line is valid, otherwise returns false.
|
||||
bool is_valid(const struct vr4300_dcache_line *line) {
|
||||
return (line->metadata & 0x1) == 0x1;
|
||||
}
|
||||
|
||||
// Sets the state of the line to clean.
|
||||
void set_clean(struct vr4300_dcache_line *line) {
|
||||
line->metadata &= ~0x2;
|
||||
}
|
||||
|
||||
// Sets the state of the line to dirty.
|
||||
void set_dirty(struct vr4300_dcache_line *line) {
|
||||
line->metadata |= 0x2;
|
||||
}
|
||||
|
||||
// Sets the tag of the specified line, retaining current valid bit.
|
||||
void set_tag(struct vr4300_dcache_line *line, uint32_t tag) {
|
||||
line->metadata = (tag << 12) | (line->metadata & 0x1);
|
||||
}
|
||||
|
||||
// Sets the line's physical tag and validates the line.
|
||||
static void validate_line(struct vr4300_dcache_line *line, uint32_t tag) {
|
||||
line->metadata = (tag << 12) | 0x1;
|
||||
}
|
||||
|
||||
// Fills an instruction cache line with data.
|
||||
void vr4300_dcache_fill(struct vr4300_dcache *dcache,
|
||||
uint64_t vaddr, uint32_t paddr, const void *data) {
|
||||
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
|
||||
|
||||
memcpy(line->data, data, sizeof(line->data));
|
||||
validate_line(line, paddr >> 4);
|
||||
}
|
||||
|
||||
// Returns the tag of the line associated with vaddr.
|
||||
uint32_t vr4300_dcache_get_tag(const struct vr4300_dcache *dcache,
|
||||
uint64_t vaddr) {
|
||||
const struct vr4300_dcache_line *line = get_line_const(dcache, vaddr);
|
||||
|
||||
return get_tag(line);
|
||||
}
|
||||
|
||||
// Initializes the instruction cache.
|
||||
void vr4300_dcache_init(struct vr4300_dcache *dcache) {
|
||||
memset(dcache->lines, 0, sizeof(dcache->lines));
|
||||
}
|
||||
|
||||
// Invalidates an instruction cache line (regardless if hit or miss).
|
||||
void vr4300_dcache_invalidate(struct vr4300_dcache *dcache, uint64_t vaddr) {
|
||||
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
|
||||
|
||||
invalidate_line(line);
|
||||
}
|
||||
|
||||
// Invalidates an instruction cache line (only on a hit).
|
||||
void vr4300_dcache_invalidate_hit(struct vr4300_dcache *dcache,
|
||||
uint64_t vaddr, uint32_t paddr) {
|
||||
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
|
||||
uint32_t ptag = get_tag(line);
|
||||
|
||||
if (ptag == (paddr >> 4) && is_valid(line))
|
||||
invalidate_line(line);
|
||||
}
|
||||
|
||||
// Probes the instruction cache for a matching line.
|
||||
const struct vr4300_dcache_line* vr4300_dcache_probe(
|
||||
const struct vr4300_dcache *dcache, uint64_t vaddr, uint32_t paddr) {
|
||||
const struct vr4300_dcache_line *line = get_line_const(dcache, vaddr);
|
||||
uint32_t ptag = get_tag(line);
|
||||
|
||||
// Virtually index, and physically tagged.
|
||||
return (ptag == (paddr >> 4) && is_valid(line))
|
||||
? line
|
||||
: NULL;
|
||||
}
|
||||
|
||||
// Sets the physical tag associated with the line.
|
||||
void vr4300_dcache_set_tag(struct vr4300_dcache *dcache,
|
||||
uint64_t vaddr, uint32_t tag) {
|
||||
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
|
||||
|
||||
set_tag(line, tag);
|
||||
}
|
||||
|
39
vr4300/dcache.h
Normal file
39
vr4300/dcache.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// vr4300/dcache.h: VR4300 instruction cache.
|
||||
//
|
||||
// CEN64: Cycle-Accurate Nintendo 64 Simulator.
|
||||
// Copyright (C) 2014, Tyler J. Stachecki.
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
#ifndef __vr4300_dcache_h__
|
||||
#define __vr4300_dcache_h__
|
||||
#include "common.h"
|
||||
|
||||
struct vr4300_dcache_line {
|
||||
uint8_t data[4 * 4];
|
||||
uint32_t metadata;
|
||||
};
|
||||
|
||||
struct vr4300_dcache {
|
||||
struct vr4300_dcache_line lines[512];
|
||||
};
|
||||
|
||||
void vr4300_dcache_init(struct vr4300_dcache *dcache);
|
||||
|
||||
void vr4300_dcache_fill(struct vr4300_dcache *dcache,
|
||||
uint64_t vaddr, uint32_t paddr, const void *data);
|
||||
uint32_t vr4300_dcache_get_tag(const struct vr4300_dcache *dcache,
|
||||
uint64_t vaddr);
|
||||
void vr4300_dcache_invalidate(struct vr4300_dcache *dcache, uint64_t vaddr);
|
||||
void vr4300_dcache_invalidate_hit(struct vr4300_dcache *dcache,
|
||||
uint64_t vaddr, uint32_t paddr);
|
||||
const struct vr4300_dcache_line* vr4300_dcache_probe(
|
||||
const struct vr4300_dcache *dcache, uint64_t vaddr, uint32_t paddr);
|
||||
void vr4300_dcache_set_tag(struct vr4300_dcache *dcache,
|
||||
uint64_t vaddr, uint32_t tag);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in a new issue