mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-23 14:33:13 -04:00
Add more TLB support, verify things.
This commit is contained in:
parent
aba5b13ba1
commit
e6bc8ebe64
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
62
vr4300/cp0.c
62
vr4300/cp0.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
11
vr4300/cp0.h
11
vr4300/cp0.h
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
Loading…
Reference in a new issue