mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-20 21:17:58 -04:00
The VALID and DIRTY bits were not being shifted into the proper positions after reading them from the line states.
172 lines
5.4 KiB
C
172 lines
5.4 KiB
C
//
|
|
// vr4300/dcache.c: VR4300 instruction cache.
|
|
//
|
|
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
|
|
// Copyright (C) 2015, 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 uint32_t get_tag(const struct vr4300_dcache_line *line);
|
|
static inline bool is_valid(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 void set_dirty(struct vr4300_dcache_line *line);
|
|
static void set_tag(struct vr4300_dcache_line *line, uint32_t tag);
|
|
static void set_taglo(struct vr4300_dcache_line *line, uint32_t taglo);
|
|
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 physical tag associated with the line.
|
|
uint32_t get_tag(const struct vr4300_dcache_line *line) {
|
|
return line->metadata & ~0xFFFU;
|
|
}
|
|
|
|
// 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 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 | (line->metadata & 0x1);
|
|
}
|
|
|
|
// Sets the tag of the specified line and valid bit.
|
|
void set_taglo(struct vr4300_dcache_line *line, uint32_t taglo) {
|
|
line->metadata = (taglo << 4 & 0xFFFFF000U) | (taglo >> 7 & 0x1) | (taglo >> 5 & 0x2);
|
|
}
|
|
|
|
// 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 | 0x1;
|
|
}
|
|
|
|
// Sets the physical tag associated with the line, marks as dirty.
|
|
void vr4300_dcache_create_dirty_exclusive(
|
|
struct vr4300_dcache *dcache, uint64_t vaddr, uint32_t paddr) {
|
|
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
|
|
|
|
set_tag(line, paddr & ~0xFFFU);
|
|
line->metadata |= 0x3;
|
|
}
|
|
|
|
// 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 & ~0xFFFU);
|
|
}
|
|
|
|
// Returns the tag of the line associated with vaddr.
|
|
uint32_t vr4300_dcache_get_tag(const struct vr4300_dcache_line *line, uint64_t vaddr) {
|
|
return get_tag(line) | (vaddr & 0xFF0U);
|
|
}
|
|
|
|
// Gets the physical tag associated with the line.
|
|
uint32_t vr4300_dcache_get_taglo(struct vr4300_dcache *dcache, uint64_t vaddr) {
|
|
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
|
|
|
|
uint32_t taglo = ((line->metadata & 0x1) << 1) | ((line->metadata & 0x2) >> 1);
|
|
return (taglo << 6) | (line->metadata >> 4 & 0x0FFFFF00U);
|
|
}
|
|
|
|
// Initializes the instruction cache.
|
|
void vr4300_dcache_init(struct vr4300_dcache *dcache) {
|
|
}
|
|
|
|
// Invalidates an instruction cache line (regardless if hit or miss).
|
|
void vr4300_dcache_invalidate(struct vr4300_dcache_line *line) {
|
|
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 & ~0xFFFU) && is_valid(line))
|
|
invalidate_line(line);
|
|
}
|
|
|
|
// Probes the instruction cache for a matching line.
|
|
struct vr4300_dcache_line* vr4300_dcache_probe(
|
|
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);
|
|
|
|
// Virtually index, and physically tagged.
|
|
if (ptag == (paddr & ~0xFFFU) && is_valid(line))
|
|
return line;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// Marks the line as dirty.
|
|
void vr4300_dcache_set_dirty(struct vr4300_dcache_line *line) {
|
|
set_dirty(line);
|
|
}
|
|
|
|
// Sets the physical tag associated with the line.
|
|
void vr4300_dcache_set_taglo(struct vr4300_dcache *dcache,
|
|
uint64_t vaddr, uint32_t taglo) {
|
|
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
|
|
|
|
set_taglo(line, taglo);
|
|
}
|
|
|
|
// Returns the line if it's dirty and valid.
|
|
// Call before replacement of writeback entry.
|
|
struct vr4300_dcache_line *vr4300_dcache_should_flush_line(
|
|
struct vr4300_dcache *dcache, uint64_t vaddr) {
|
|
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
|
|
|
|
return is_dirty(line) && is_valid(line)
|
|
? line : NULL;
|
|
}
|
|
|
|
// Writes back the block if the line is valid, then invalidates the line.
|
|
struct vr4300_dcache_line *vr4300_dcache_wb_invalidate(
|
|
struct vr4300_dcache *dcache, uint64_t vaddr) {
|
|
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
|
|
|
|
if (is_valid(line)) {
|
|
invalidate_line(line);
|
|
return line;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|