Add more TLB support, verify things.

This commit is contained in:
Tyler Stachecki 2014-08-23 20:04:30 -04:00
parent aba5b13ba1
commit e6bc8ebe64
8 changed files with 93 additions and 19 deletions

View file

@ -67,10 +67,25 @@ int tlb_probe(struct cen64_tlb *tlb, uint64_t vaddr, uint8_t vasid) {
return -1;
}
// Reads data from the specified TLB index.
int tlb_read(struct cen64_tlb *tlb, unsigned index,
uint64_t *entry_hi, uint32_t *page_mask) {
*page_mask = tlb->page_mask[index] << 13;
*entry_hi =
(tlb->vpn2[index] & 0x18000000LLU << 35) |
(tlb->vpn2[index] & 0x7FFFFFFLLU << 13) |
(tlb->global[index] & 1 << 12) |
(tlb->asid[index]);
return 0;
}
// Writes an entry to the TLB.
int tlb_write(struct cen64_tlb *tlb, unsigned index, uint64_t entry_hi,
uint64_t entry_lo_0, uint64_t entry_lo_1, uint32_t page_mask) {
tlb->page_mask[index] = page_mask;
tlb->page_mask[index] = page_mask >> 13;
tlb->vpn2[index] =
(entry_hi >> 35 & 0x18000000U) |
(entry_hi >> 13 & 0x7FFFFFF);

View file

@ -21,6 +21,9 @@ struct cen64_tlb {
void tlb_init(struct cen64_tlb *tlb);
int tlb_probe(struct cen64_tlb *tlb, uint64_t vpn2, uint8_t vasid);
int tlb_read(struct cen64_tlb *tlb, unsigned index,
uint64_t *entry_hi, uint32_t *page_mask);
int tlb_write(struct cen64_tlb *tlb, unsigned index, uint64_t entry_hi,
uint64_t entry_lo_0, uint64_t entry_lo_1, uint32_t page_mask);

View file

@ -95,7 +95,7 @@ int read_pi_regs(void *opaque, uint32_t address, uint32_t *word) {
// Writes a word to cartridge ROM.
int write_cart_rom(void *opaque, uint32_t address, uint32_t word, uint32_t dqm) {
assert(0 && "Attempt to write to cart ROM.");
//assert(0 && "Attempt to write to cart ROM.");
return 0;
}

View file

@ -52,6 +52,34 @@ static inline uint64_t mask_reg(unsigned reg, uint64_t data) {
return vr4300_cp0_reg_masks[reg] & data;
};
//
// DMFC0
//
int VR4300_DMFC0(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
unsigned dest = GET_RT(iw);
unsigned src = GET_RD(iw);
exdc_latch->result = mask_reg(src, vr4300->regs[32 + src]);
exdc_latch->dest = dest;
return 0;
}
//
// DMTC0
//
int VR4300_DMTC0(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
unsigned dest = 32 + GET_RD(iw);
if (dest == VR4300_CP0_REGISTER_COMPARE)
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] &= ~0x8000;
vr4300->regs[dest] = rt;
return 0;
}
//
// ERET
//
@ -97,7 +125,7 @@ int VR4300_MFC0(struct vr4300 *vr4300,
unsigned src = GET_RD(iw);
exdc_latch->result = mask_reg(src, vr4300->regs[32 + src]);
exdc_latch->dest = dest;
exdc_latch->dest = (int32_t) dest;
return 0;
}
@ -111,7 +139,7 @@ int VR4300_MTC0(struct vr4300 *vr4300,
if (dest == VR4300_CP0_REGISTER_COMPARE)
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] &= ~0x8000;
vr4300->regs[dest] = rt;
vr4300->regs[dest] = (int32_t) rt;
return 0;
}
@ -122,12 +150,32 @@ int VR4300_TLBP(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
uint64_t entry_hi = mask_reg(10, vr4300->regs[VR4300_CP0_REGISTER_ENTRYHI]);
if (tlb_probe(&vr4300->tlb, entry_hi, entry_hi & 0xFF) != -1)
if (tlb_probe(&vr4300->cp0.tlb, entry_hi, entry_hi & 0xFF) != -1)
vr4300->regs[VR4300_CP0_REGISTER_INDEX] |= 0x80000000;
return 0;
}
//
// TLBR
//
int VR4300_TLBR(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
unsigned index = vr4300->regs[VR4300_CP0_REGISTER_INDEX] & 0x3F;
uint64_t entry_hi;
uint32_t page_mask;
uint32_t pfn0 = vr4300->cp0.pfn[index][0];
uint32_t pfn1 = vr4300->cp0.pfn[index][1];
uint8_t state0 = vr4300->cp0.state[index][0];
uint8_t state1 = vr4300->cp0.state[index][1];
tlb_read(&vr4300->cp0.tlb, index, &entry_hi, &page_mask);
vr4300->regs[VR4300_CP0_REGISTER_ENTRYLO0] = (pfn0 >> 6) | state0;
vr4300->regs[VR4300_CP0_REGISTER_ENTRYLO1] = (pfn1 >> 6) | state1;
return 0;
}
//
// TLBWI
//
@ -139,12 +187,16 @@ int VR4300_TLBWI(struct vr4300 *vr4300,
uint32_t page_mask = mask_reg(5, vr4300->regs[VR4300_CP0_REGISTER_PAGEMASK]);
unsigned index = vr4300->regs[VR4300_CP0_REGISTER_INDEX] & 0x3F;
tlb_write(&vr4300->tlb, index, entry_hi, entry_lo_0, entry_lo_1, page_mask);
tlb_write(&vr4300->cp0.tlb, index, entry_hi, entry_lo_0, entry_lo_1, page_mask);
vr4300->cp0.pfn[index][0] = (entry_lo_0 << 6) & ~0xFFFU;
vr4300->cp0.pfn[index][1] = (entry_lo_1 << 6) & ~0xFFFU;
vr4300->cp0.state[index][0] = entry_lo_0 & 0x3F;
vr4300->cp0.state[index][1] = entry_lo_1 & 0x3F;
return 0;
}
// Initializes the coprocessor.
void vr4300_cp0_init(struct vr4300 *vr4300) {
tlb_init(&vr4300->tlb);
tlb_init(&vr4300->cp0.tlb);
}

View file

@ -11,9 +11,17 @@
#ifndef __vr4300_cp0_h__
#define __vr4300_cp0_h__
#include "common.h"
#include "tlb/tlb.h"
struct vr4300;
struct vr4300_cp0 {
struct cen64_tlb tlb;
uint32_t pfn[32][2];
uint8_t state[32][2];
};
// Registers list.
enum vr4300_cp0_register {
VR4300_CP0_REGISTER_INDEX = 32,
@ -44,10 +52,13 @@ enum vr4300_cp0_register {
NUM_VR4300_CP0_REGISTERS = 32,
};
int VR4300_DMFC0(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_DMTC0(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_ERET(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_MFC0(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_MTC0(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_TLBP(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_TLBR(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_TLBWI(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
void vr4300_cp0_init(struct vr4300 *vr4300);

View file

@ -11,7 +11,6 @@
#ifndef __vr4300_cpu_h__
#define __vr4300_cpu_h__
#include "common.h"
#include "tlb/tlb.h"
#include "vr4300/cp0.h"
#include "vr4300/cp1.h"
#include "vr4300/dcache.h"
@ -94,8 +93,7 @@ struct vr4300 {
// Align the TLB to a 16-byte boundary for vectorization.
uint8_t padding_for_tlb[(16 - (sizeof(struct vr4300_pipeline) % 16)) % 16];
struct cen64_tlb tlb;
struct vr4300_cp0 cp0;
struct vr4300_cp1 cp1;
struct bus_controller *bus;

View file

@ -764,16 +764,11 @@ int VR4300_DSRLV(struct vr4300 *vr4300,
int VR4300_INV(struct vr4300 *vr4300,
uint32_t iw, 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;
debug("Unimplemented instruction: %s [0x%.8X] @ 0x%.16llX\n",
vr4300_opcode_mnemonics[opcode], iw, (long long unsigned)
vr4300_opcode_mnemonics[rfex_latch->opcode.id], iw, (long long unsigned)
rfex_latch->common.pc);
// TODO/FIXME: Implement this instruction later.
if (opcode != VR4300_OPCODE_TLBR)
assert(0 && "Unimplemented instruction encountered.");
return 0;
}

View file

@ -161,8 +161,8 @@ extern const char *vr4300_opcode_mnemonics[NUM_VR4300_OPCODES];
#define BC0 VR4300_BUILD_OP(BC0, INV, INFO1(BRANCH))
#define CFC0 VR4300_BUILD_OP(CFC0, INV, INFO1(NONE))
#define CTC0 VR4300_BUILD_OP(CTC0, INV, INFO1(NONE))
#define DMFC0 VR4300_BUILD_OP(DMFC0, INV, INFO1(NONE))
#define DMTC0 VR4300_BUILD_OP(DMTC0, INV, INFO1(NONE))
#define DMFC0 VR4300_BUILD_OP(DMFC0, DMFC0, INFO1(NONE))
#define DMTC0 VR4300_BUILD_OP(DMTC0, DMTC0, INFO1(NEEDRT))
#define LDC0 VR4300_BUILD_OP(LDC0, INV, INFO1(NONE))
#define LWC0 VR4300_BUILD_OP(LWC0, INV, INFO1(NONE))
#define MFC0 VR4300_BUILD_OP(MFC0, MFC0, INFO1(NONE))
@ -173,7 +173,7 @@ extern const char *vr4300_opcode_mnemonics[NUM_VR4300_OPCODES];
#define CACHE VR4300_BUILD_OP(CACHE, CACHE, INFO1(NEEDRS))
#define ERET VR4300_BUILD_OP(ERET, ERET, INFO1(NONE))
#define TLBP VR4300_BUILD_OP(TLBP, TLBP, INFO1(NONE))
#define TLBR VR4300_BUILD_OP(TLBR, INV, INFO1(NONE))
#define TLBR VR4300_BUILD_OP(TLBR, TLBR, INFO1(NONE))
#define TLBWI VR4300_BUILD_OP(TLBWI, TLBWI, INFO1(NONE))
#define TLBWR VR4300_BUILD_OP(TLBWR, INV, INFO1(NONE))