Move TLB faults into the normal Fault code. The TLB no longer fills in IPRs through its own fault() method; this is handled by the fault's invoke() methods.
arch/alpha/faults.cc: Move TLB fault code into the normal fault invoke() method. arch/alpha/faults.hh: Move DTB/ITB fault handling code into their own class with a specific invoke() method. Have DTB/ITB faults derive from these classes. Unfortunately the DtbAlignmentFault is somewhat odd; it's a normal alignment fault, but it must also set some specific IPRs. arch/alpha/tlb.cc: arch/alpha/tlb.hh: Setting IPRs is now handled through the fault itself. --HG-- extra : convert_revision : 5cb92ce2186ff79f632bfcbc9ba62a8a04400eae
This commit is contained in:
parent
1507bfb20a
commit
c1046488e0
4 changed files with 166 additions and 86 deletions
|
@ -30,6 +30,9 @@
|
|||
#include "cpu/exec_context.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "base/trace.hh"
|
||||
#if FULL_SYSTEM
|
||||
#include "arch/alpha/ev5.hh"
|
||||
#endif
|
||||
|
||||
namespace AlphaISA
|
||||
{
|
||||
|
@ -70,6 +73,10 @@ FaultName DtbAcvFault::_name = "dfault";
|
|||
FaultVect DtbAcvFault::_vect = 0x0381;
|
||||
FaultStat DtbAcvFault::_count;
|
||||
|
||||
FaultName DtbAlignmentFault::_name = "unalign";
|
||||
FaultVect DtbAlignmentFault::_vect = 0x0301;
|
||||
FaultStat DtbAlignmentFault::_count;
|
||||
|
||||
FaultName ItbMissFault::_name = "itbmiss";
|
||||
FaultVect ItbMissFault::_vect = 0x0181;
|
||||
FaultStat ItbMissFault::_count;
|
||||
|
@ -125,6 +132,44 @@ void ArithmeticFault::invoke(ExecContext * xc)
|
|||
panic("Arithmetic traps are unimplemented!");
|
||||
}
|
||||
|
||||
void DtbFault::invoke(ExecContext * xc)
|
||||
{
|
||||
// Set fault address and flags. Even though we're modeling an
|
||||
// EV5, we use the EV6 technique of not latching fault registers
|
||||
// on VPTE loads (instead of locking the registers until IPR_VA is
|
||||
// read, like the EV5). The EV6 approach is cleaner and seems to
|
||||
// work with EV5 PAL code, but not the other way around.
|
||||
if (!xc->misspeculating()
|
||||
&& !(reqFlags & VPTE) && !(reqFlags & NO_FAULT)) {
|
||||
// set VA register with faulting address
|
||||
xc->setMiscReg(AlphaISA::IPR_VA, vaddr);
|
||||
|
||||
// set MM_STAT register flags
|
||||
xc->setMiscReg(AlphaISA::IPR_MM_STAT,
|
||||
(((EV5::Opcode(xc->getInst()) & 0x3f) << 11)
|
||||
| ((EV5::Ra(xc->getInst()) & 0x1f) << 6)
|
||||
| (flags & 0x3f)));
|
||||
|
||||
// set VA_FORM register with faulting formatted address
|
||||
xc->setMiscReg(AlphaISA::IPR_VA_FORM,
|
||||
xc->readMiscReg(AlphaISA::IPR_MVPTBR) | (vaddr.vpn() << 3));
|
||||
}
|
||||
|
||||
AlphaFault::invoke(xc);
|
||||
}
|
||||
|
||||
void ItbFault::invoke(ExecContext * xc)
|
||||
{
|
||||
if (!xc->misspeculating()) {
|
||||
xc->setMiscReg(AlphaISA::IPR_ITB_TAG, pc);
|
||||
xc->setMiscReg(AlphaISA::IPR_IFAULT_VA_FORM,
|
||||
xc->readMiscReg(AlphaISA::IPR_IVPTBR) |
|
||||
(AlphaISA::VAddr(pc).vpn() << 3));
|
||||
}
|
||||
|
||||
AlphaFault::invoke(xc);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace AlphaISA
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#ifndef __ALPHA_FAULTS_HH__
|
||||
#define __ALPHA_FAULTS_HH__
|
||||
|
||||
#include "arch/alpha/isa_traits.hh"
|
||||
#include "sim/faults.hh"
|
||||
|
||||
// The design of the "name" and "vect" functions is in sim/faults.hh
|
||||
|
@ -130,85 +131,167 @@ class InterruptFault : public AlphaFault
|
|||
FaultStat & countStat() {return _count;}
|
||||
};
|
||||
|
||||
class NDtbMissFault : public AlphaFault
|
||||
class DtbFault : public AlphaFault
|
||||
{
|
||||
#if FULL_SYSTEM
|
||||
private:
|
||||
AlphaISA::VAddr vaddr;
|
||||
uint32_t reqFlags;
|
||||
uint64_t flags;
|
||||
public:
|
||||
DtbFault(AlphaISA::VAddr _vaddr, uint32_t _reqFlags, uint64_t _flags)
|
||||
: vaddr(_vaddr), reqFlags(_reqFlags), flags(_flags)
|
||||
{ }
|
||||
#endif
|
||||
FaultName name() = 0;
|
||||
FaultVect vect() = 0;
|
||||
FaultStat & countStat() = 0;
|
||||
#if FULL_SYSTEM
|
||||
void invoke(ExecContext * xc);
|
||||
#endif
|
||||
};
|
||||
|
||||
class NDtbMissFault : public DtbFault
|
||||
{
|
||||
private:
|
||||
static FaultName _name;
|
||||
static FaultVect _vect;
|
||||
static FaultStat _count;
|
||||
public:
|
||||
#if FULL_SYSTEM
|
||||
NDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
|
||||
: DtbFault(vaddr, reqFlags, flags)
|
||||
{ }
|
||||
#endif
|
||||
FaultName name() {return _name;}
|
||||
FaultVect vect() {return _vect;}
|
||||
FaultStat & countStat() {return _count;}
|
||||
};
|
||||
|
||||
class PDtbMissFault : public AlphaFault
|
||||
class PDtbMissFault : public DtbFault
|
||||
{
|
||||
private:
|
||||
static FaultName _name;
|
||||
static FaultVect _vect;
|
||||
static FaultStat _count;
|
||||
public:
|
||||
#if FULL_SYSTEM
|
||||
PDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
|
||||
: DtbFault(vaddr, reqFlags, flags)
|
||||
{ }
|
||||
#endif
|
||||
FaultName name() {return _name;}
|
||||
FaultVect vect() {return _vect;}
|
||||
FaultStat & countStat() {return _count;}
|
||||
};
|
||||
|
||||
class DtbPageFault : public AlphaFault
|
||||
class DtbPageFault : public DtbFault
|
||||
{
|
||||
private:
|
||||
static FaultName _name;
|
||||
static FaultVect _vect;
|
||||
static FaultStat _count;
|
||||
public:
|
||||
#if FULL_SYSTEM
|
||||
DtbPageFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
|
||||
: DtbFault(vaddr, reqFlags, flags)
|
||||
{ }
|
||||
#endif
|
||||
FaultName name() {return _name;}
|
||||
FaultVect vect() {return _vect;}
|
||||
FaultStat & countStat() {return _count;}
|
||||
};
|
||||
|
||||
class DtbAcvFault : public AlphaFault
|
||||
class DtbAcvFault : public DtbFault
|
||||
{
|
||||
private:
|
||||
static FaultName _name;
|
||||
static FaultVect _vect;
|
||||
static FaultStat _count;
|
||||
public:
|
||||
#if FULL_SYSTEM
|
||||
DtbAcvFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
|
||||
: DtbFault(vaddr, reqFlags, flags)
|
||||
{ }
|
||||
#endif
|
||||
FaultName name() {return _name;}
|
||||
FaultVect vect() {return _vect;}
|
||||
FaultStat & countStat() {return _count;}
|
||||
};
|
||||
|
||||
class ItbMissFault : public AlphaFault
|
||||
class DtbAlignmentFault : public DtbFault
|
||||
{
|
||||
private:
|
||||
static FaultName _name;
|
||||
static FaultVect _vect;
|
||||
static FaultStat _count;
|
||||
public:
|
||||
#if FULL_SYSTEM
|
||||
DtbAlignmentFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
|
||||
: DtbFault(vaddr, reqFlags, flags)
|
||||
{ }
|
||||
#endif
|
||||
FaultName name() {return _name;}
|
||||
FaultVect vect() {return _vect;}
|
||||
FaultStat & countStat() {return _count;}
|
||||
};
|
||||
|
||||
class ItbPageFault : public AlphaFault
|
||||
class ItbFault : public AlphaFault
|
||||
{
|
||||
private:
|
||||
Addr pc;
|
||||
public:
|
||||
ItbFault(Addr _pc)
|
||||
: pc(_pc)
|
||||
{ }
|
||||
FaultName name() { panic("Dtb Fault is a base class"); }
|
||||
FaultVect vect() { panic("Dtb Fault is a base class"); }
|
||||
FaultStat & countStat() { panic("Dtb Fault is a base class"); }
|
||||
#if FULL_SYSTEM
|
||||
void invoke(ExecContext * xc);
|
||||
#endif
|
||||
};
|
||||
|
||||
class ItbMissFault : public ItbFault
|
||||
{
|
||||
private:
|
||||
static FaultName _name;
|
||||
static FaultVect _vect;
|
||||
static FaultStat _count;
|
||||
public:
|
||||
ItbMissFault(Addr pc)
|
||||
: ItbFault(pc)
|
||||
{ }
|
||||
FaultName name() {return _name;}
|
||||
FaultVect vect() {return _vect;}
|
||||
FaultStat & countStat() {return _count;}
|
||||
};
|
||||
|
||||
class ItbAcvFault : public AlphaFault
|
||||
class ItbPageFault : public ItbFault
|
||||
{
|
||||
private:
|
||||
static FaultName _name;
|
||||
static FaultVect _vect;
|
||||
static FaultStat _count;
|
||||
public:
|
||||
ItbPageFault(Addr pc)
|
||||
: ItbFault(pc)
|
||||
{ }
|
||||
FaultName name() {return _name;}
|
||||
FaultVect vect() {return _vect;}
|
||||
FaultStat & countStat() {return _count;}
|
||||
};
|
||||
|
||||
class ItbAcvFault : public ItbFault
|
||||
{
|
||||
private:
|
||||
static FaultName _name;
|
||||
static FaultVect _vect;
|
||||
static FaultStat _count;
|
||||
public:
|
||||
ItbAcvFault(Addr pc)
|
||||
: ItbFault(pc)
|
||||
{ }
|
||||
FaultName name() {return _name;}
|
||||
FaultVect vect() {return _vect;}
|
||||
FaultStat & countStat() {return _count;}
|
||||
|
|
|
@ -290,17 +290,6 @@ AlphaITB::regStats()
|
|||
accesses = hits + misses;
|
||||
}
|
||||
|
||||
void
|
||||
AlphaITB::fault(Addr pc, ExecContext *xc) const
|
||||
{
|
||||
if (!xc->misspeculating()) {
|
||||
xc->setMiscReg(AlphaISA::IPR_ITB_TAG, pc);
|
||||
xc->setMiscReg(AlphaISA::IPR_IFAULT_VA_FORM,
|
||||
xc->readMiscReg(AlphaISA::IPR_IVPTBR) |
|
||||
(AlphaISA::VAddr(pc).vpn() << 3));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Fault
|
||||
AlphaITB::translate(MemReqPtr &req) const
|
||||
|
@ -319,9 +308,8 @@ AlphaITB::translate(MemReqPtr &req) const
|
|||
} else {
|
||||
// verify that this is a good virtual address
|
||||
if (!validVirtualAddress(req->vaddr)) {
|
||||
fault(req->vaddr, req->xc);
|
||||
acv++;
|
||||
return new ItbAcvFault;
|
||||
return new ItbAcvFault(req->vaddr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -336,9 +324,8 @@ AlphaITB::translate(MemReqPtr &req) const
|
|||
// only valid in kernel mode
|
||||
if (ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM)) !=
|
||||
AlphaISA::mode_kernel) {
|
||||
fault(req->vaddr, req->xc);
|
||||
acv++;
|
||||
return new ItbAcvFault;
|
||||
return new ItbAcvFault(req->vaddr);
|
||||
}
|
||||
|
||||
req->paddr = req->vaddr & PAddrImplMask;
|
||||
|
@ -358,9 +345,8 @@ AlphaITB::translate(MemReqPtr &req) const
|
|||
asn);
|
||||
|
||||
if (!pte) {
|
||||
fault(req->vaddr, req->xc);
|
||||
misses++;
|
||||
return new ItbPageFault;
|
||||
return new ItbPageFault(req->vaddr);
|
||||
}
|
||||
|
||||
req->paddr = (pte->ppn << AlphaISA::PageShift) +
|
||||
|
@ -370,9 +356,8 @@ AlphaITB::translate(MemReqPtr &req) const
|
|||
if (!(pte->xre &
|
||||
(1 << ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM))))) {
|
||||
// instruction access fault
|
||||
fault(req->vaddr, req->xc);
|
||||
acv++;
|
||||
return new ItbAcvFault;
|
||||
return new ItbAcvFault(req->vaddr);
|
||||
}
|
||||
|
||||
hits++;
|
||||
|
@ -465,34 +450,6 @@ AlphaDTB::regStats()
|
|||
accesses = read_accesses + write_accesses;
|
||||
}
|
||||
|
||||
void
|
||||
AlphaDTB::fault(MemReqPtr &req, uint64_t flags) const
|
||||
{
|
||||
ExecContext *xc = req->xc;
|
||||
AlphaISA::VAddr vaddr = req->vaddr;
|
||||
|
||||
// Set fault address and flags. Even though we're modeling an
|
||||
// EV5, we use the EV6 technique of not latching fault registers
|
||||
// on VPTE loads (instead of locking the registers until IPR_VA is
|
||||
// read, like the EV5). The EV6 approach is cleaner and seems to
|
||||
// work with EV5 PAL code, but not the other way around.
|
||||
if (!xc->misspeculating()
|
||||
&& !(req->flags & VPTE) && !(req->flags & NO_FAULT)) {
|
||||
// set VA register with faulting address
|
||||
xc->setMiscReg(AlphaISA::IPR_VA, req->vaddr);
|
||||
|
||||
// set MM_STAT register flags
|
||||
xc->setMiscReg(AlphaISA::IPR_MM_STAT,
|
||||
(((Opcode(xc->getInst()) & 0x3f) << 11)
|
||||
| ((Ra(xc->getInst()) & 0x1f) << 6)
|
||||
| (flags & 0x3f)));
|
||||
|
||||
// set VA_FORM register with faulting formatted address
|
||||
xc->setMiscReg(AlphaISA::IPR_VA_FORM,
|
||||
xc->readMiscReg(AlphaISA::IPR_MVPTBR) | (vaddr.vpn() << 3));
|
||||
}
|
||||
}
|
||||
|
||||
Fault
|
||||
AlphaDTB::translate(MemReqPtr &req, bool write) const
|
||||
{
|
||||
|
@ -507,10 +464,10 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
|
|||
* Check for alignment faults
|
||||
*/
|
||||
if (req->vaddr & (req->size - 1)) {
|
||||
fault(req, write ? MM_STAT_WR_MASK : 0);
|
||||
DPRINTF(TLB, "Alignment Fault on %#x, size = %d", req->vaddr,
|
||||
req->size);
|
||||
return genAlignmentFault();
|
||||
uint64_t flags = write ? MM_STAT_WR_MASK : 0;
|
||||
return new DtbAlignmentFault(req->vaddr, req->flags, flags);
|
||||
}
|
||||
|
||||
if (pc & 0x1) {
|
||||
|
@ -525,12 +482,11 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
|
|||
} else {
|
||||
// verify that this is a good virtual address
|
||||
if (!validVirtualAddress(req->vaddr)) {
|
||||
fault(req, (write ? MM_STAT_WR_MASK : 0) |
|
||||
MM_STAT_BAD_VA_MASK |
|
||||
MM_STAT_ACV_MASK);
|
||||
|
||||
if (write) { write_acv++; } else { read_acv++; }
|
||||
return new DtbPageFault;
|
||||
uint64_t flags = (write ? MM_STAT_WR_MASK : 0) |
|
||||
MM_STAT_BAD_VA_MASK |
|
||||
MM_STAT_ACV_MASK;
|
||||
return new DtbPageFault(req->vaddr, req->flags, flags);
|
||||
}
|
||||
|
||||
// Check for "superpage" mapping
|
||||
|
@ -544,10 +500,10 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
|
|||
// only valid in kernel mode
|
||||
if (DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM)) !=
|
||||
AlphaISA::mode_kernel) {
|
||||
fault(req, ((write ? MM_STAT_WR_MASK : 0) |
|
||||
MM_STAT_ACV_MASK));
|
||||
if (write) { write_acv++; } else { read_acv++; }
|
||||
return new DtbAcvFault;
|
||||
uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) |
|
||||
MM_STAT_ACV_MASK);
|
||||
return new DtbAcvFault(req->vaddr, req->flags, flags);
|
||||
}
|
||||
|
||||
req->paddr = req->vaddr & PAddrImplMask;
|
||||
|
@ -574,12 +530,14 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
|
|||
|
||||
if (!pte) {
|
||||
// page fault
|
||||
fault(req, (write ? MM_STAT_WR_MASK : 0) |
|
||||
MM_STAT_DTB_MISS_MASK);
|
||||
if (write) { write_misses++; } else { read_misses++; }
|
||||
uint64_t flags = (write ? MM_STAT_WR_MASK : 0) |
|
||||
MM_STAT_DTB_MISS_MASK;
|
||||
return (req->flags & VPTE) ?
|
||||
(Fault)(new PDtbMissFault) :
|
||||
(Fault)(new NDtbMissFault);
|
||||
(Fault)(new PDtbMissFault(req->vaddr, req->flags,
|
||||
flags)) :
|
||||
(Fault)(new NDtbMissFault(req->vaddr, req->flags,
|
||||
flags));
|
||||
}
|
||||
|
||||
req->paddr = (pte->ppn << AlphaISA::PageShift) +
|
||||
|
@ -588,29 +546,29 @@ AlphaDTB::translate(MemReqPtr &req, bool write) const
|
|||
if (write) {
|
||||
if (!(pte->xwe & MODE2MASK(mode))) {
|
||||
// declare the instruction access fault
|
||||
fault(req, MM_STAT_WR_MASK |
|
||||
MM_STAT_ACV_MASK |
|
||||
(pte->fonw ? MM_STAT_FONW_MASK : 0));
|
||||
write_acv++;
|
||||
return new DtbPageFault;
|
||||
uint64_t flags = MM_STAT_WR_MASK |
|
||||
MM_STAT_ACV_MASK |
|
||||
(pte->fonw ? MM_STAT_FONW_MASK : 0);
|
||||
return new DtbPageFault(req->vaddr, req->flags, flags);
|
||||
}
|
||||
if (pte->fonw) {
|
||||
fault(req, MM_STAT_WR_MASK |
|
||||
MM_STAT_FONW_MASK);
|
||||
write_acv++;
|
||||
return new DtbPageFault;
|
||||
uint64_t flags = MM_STAT_WR_MASK |
|
||||
MM_STAT_FONW_MASK;
|
||||
return new DtbPageFault(req->vaddr, req->flags, flags);
|
||||
}
|
||||
} else {
|
||||
if (!(pte->xre & MODE2MASK(mode))) {
|
||||
fault(req, MM_STAT_ACV_MASK |
|
||||
(pte->fonr ? MM_STAT_FONR_MASK : 0));
|
||||
read_acv++;
|
||||
return new DtbAcvFault;
|
||||
uint64_t flags = MM_STAT_ACV_MASK |
|
||||
(pte->fonr ? MM_STAT_FONR_MASK : 0);
|
||||
return new DtbAcvFault(req->vaddr, req->flags, flags);
|
||||
}
|
||||
if (pte->fonr) {
|
||||
fault(req, MM_STAT_FONR_MASK);
|
||||
read_acv++;
|
||||
return new DtbPageFault;
|
||||
uint64_t flags = MM_STAT_FONR_MASK;
|
||||
return new DtbPageFault(req->vaddr, req->flags, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,9 +88,6 @@ class AlphaITB : public AlphaTLB
|
|||
mutable Stats::Scalar<> acv;
|
||||
mutable Stats::Formula accesses;
|
||||
|
||||
protected:
|
||||
void fault(Addr pc, ExecContext *xc) const;
|
||||
|
||||
public:
|
||||
AlphaITB(const std::string &name, int size);
|
||||
virtual void regStats();
|
||||
|
@ -114,9 +111,6 @@ class AlphaDTB : public AlphaTLB
|
|||
Stats::Formula acv;
|
||||
Stats::Formula accesses;
|
||||
|
||||
protected:
|
||||
void fault(MemReqPtr &req, uint64_t flags) const;
|
||||
|
||||
public:
|
||||
AlphaDTB(const std::string &name, int size);
|
||||
virtual void regStats();
|
||||
|
|
Loading…
Reference in a new issue