The following command was run: ``` pre-commit run --all-files ``` This ensures all the files in the repository are formatted to pass our checks. Change-Id: Ia2fe3529a50ad925d1076a612d60a4280adc40de Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/62572 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com> Maintainer: Jason Lowe-Power <power.jg@gmail.com> Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
244 lines
7.6 KiB
C++
244 lines
7.6 KiB
C++
// -*- mode:c++ -*-
|
|
|
|
// Copyright (c) 2007 MIPS Technologies, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met: redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer;
|
|
// redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution;
|
|
// neither the name of the copyright holders nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Coprocessor instructions
|
|
//
|
|
|
|
//Outputs to decoder.hh
|
|
output header {{
|
|
class CP0Control : public MipsStaticInst
|
|
{
|
|
protected:
|
|
using MipsStaticInst::MipsStaticInst;
|
|
|
|
std::string generateDisassembly(
|
|
Addr pc, const loader::SymbolTable *symtab) const override;
|
|
};
|
|
class CP0TLB : public MipsStaticInst
|
|
{
|
|
protected:
|
|
using MipsStaticInst::MipsStaticInst;
|
|
|
|
std::string generateDisassembly(
|
|
Addr pc, const loader::SymbolTable *symtab) const override;
|
|
};
|
|
|
|
|
|
class CP1Control : public MipsStaticInst
|
|
{
|
|
protected:
|
|
using MipsStaticInst::MipsStaticInst;
|
|
|
|
std::string generateDisassembly(
|
|
Addr pc, const loader::SymbolTable *symtab) const override;
|
|
};
|
|
}};
|
|
|
|
// Basic instruction class execute method template.
|
|
def template CP0Execute {{
|
|
Fault %(class_name)s::execute(
|
|
ExecContext *xc, Trace::InstRecord *traceData) const
|
|
{
|
|
Fault fault = NoFault;
|
|
%(op_decl)s;
|
|
%(op_rd)s;
|
|
|
|
if (isCoprocessorEnabled(xc, 0)) {
|
|
%(code)s;
|
|
|
|
if(fault == NoFault)
|
|
{
|
|
%(op_wb)s;
|
|
}
|
|
} else {
|
|
fault = std::make_shared<CoprocessorUnusableFault>(0);
|
|
}
|
|
return fault;
|
|
}
|
|
}};
|
|
|
|
def template CP1Execute {{
|
|
Fault %(class_name)s::execute(
|
|
ExecContext *xc, Trace::InstRecord *traceData) const
|
|
{
|
|
Fault fault = NoFault;
|
|
%(op_decl)s;
|
|
%(op_rd)s;
|
|
|
|
if (isCoprocessorEnabled(xc, 1)) {
|
|
%(code)s;
|
|
} else {
|
|
fault = std::make_shared<CoprocessorUnusableFault>(1);
|
|
}
|
|
|
|
if(fault == NoFault)
|
|
{
|
|
%(op_wb)s;
|
|
}
|
|
return fault;
|
|
}
|
|
}};
|
|
// Basic instruction class execute method template.
|
|
def template ControlTLBExecute {{
|
|
Fault %(class_name)s::execute(
|
|
ExecContext *xc, Trace::InstRecord *traceData) const
|
|
{
|
|
Fault fault = NoFault;
|
|
%(op_decl)s;
|
|
%(op_rd)s;
|
|
|
|
if (FullSystem) {
|
|
if (isCoprocessor0Enabled(xc)) {
|
|
if(isMMUTLB(xc)){
|
|
%(code)s;
|
|
} else {
|
|
fault = std::make_shared<ReservedInstructionFault>();
|
|
}
|
|
} else {
|
|
fault = std::make_shared<CoprocessorUnusableFault>(0);
|
|
}
|
|
} else { // Syscall Emulation Mode - No TLB Instructions
|
|
fault = std::make_shared<ReservedInstructionFault>();
|
|
}
|
|
|
|
if (fault == NoFault) {
|
|
%(op_wb)s;
|
|
}
|
|
return fault;
|
|
}
|
|
}};
|
|
|
|
//Outputs to decoder.cc
|
|
output decoder {{
|
|
std::string
|
|
CP0Control::generateDisassembly(
|
|
Addr pc, const loader::SymbolTable *symtab) const
|
|
{
|
|
std::stringstream ss;
|
|
ccprintf(ss, "%-10s r%d, %d, %d", mnemonic, RT, RD, SEL);
|
|
return ss.str();
|
|
}
|
|
std::string
|
|
CP0TLB::generateDisassembly(
|
|
Addr pc, const loader::SymbolTable *symtab) const
|
|
{
|
|
std::stringstream ss;
|
|
ccprintf(ss, "%-10s r%d, %d, %d", mnemonic, RT, RD, SEL);
|
|
return ss.str();
|
|
}
|
|
std::string
|
|
CP1Control::generateDisassembly(
|
|
Addr pc, const loader::SymbolTable *symtab) const
|
|
{
|
|
std::stringstream ss;
|
|
ccprintf(ss, "%-10s r%d, f%d", mnemonic, RT, FS);
|
|
return ss.str();
|
|
}
|
|
}};
|
|
|
|
output header {{
|
|
bool isCoprocessorEnabled(ExecContext *xc, unsigned cop_num);
|
|
|
|
bool isMMUTLB(ExecContext *xc);
|
|
|
|
}};
|
|
|
|
output exec {{
|
|
bool
|
|
isCoprocessorEnabled(ExecContext *xc, unsigned cop_num)
|
|
{
|
|
if (!FullSystem)
|
|
return true;
|
|
|
|
RegVal Stat = xc->readMiscReg(misc_reg::Status);
|
|
if (cop_num == 0) {
|
|
RegVal Dbg = xc->readMiscReg(misc_reg::Debug);
|
|
// In Stat, EXL, ERL or CU0 set, CP0 accessible
|
|
// In Dbg, DM bit set, CP0 accessible
|
|
// In Stat, KSU = 0, kernel mode is base mode
|
|
return (Stat & 0x10000006) ||
|
|
(Dbg & 0x40000000) ||
|
|
!(Stat & 0x00000018);
|
|
} else if (cop_num < 4) {
|
|
return Stat & (0x10000000 << cop_num); // CU is reset
|
|
} else {
|
|
panic("Invalid Coprocessor Number Specified");
|
|
}
|
|
}
|
|
|
|
bool inline
|
|
isCoprocessor0Enabled(ExecContext *xc)
|
|
{
|
|
if (FullSystem) {
|
|
RegVal Stat = xc->readMiscReg(misc_reg::Status);
|
|
RegVal Dbg = xc->readMiscReg(misc_reg::Debug);
|
|
// In Stat, EXL, ERL or CU0 set, CP0 accessible
|
|
// In Dbg, DM bit set, CP0 accessible
|
|
// In Stat KSU = 0, kernel mode is base mode
|
|
return (Stat & 0x10000006) || (Dbg & 0x40000000) ||
|
|
!(Stat & 0x00000018);
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool
|
|
isMMUTLB(ExecContext *xc)
|
|
{
|
|
RegVal Config = xc->readMiscReg(misc_reg::Config);
|
|
return FullSystem && (Config & 0x380) == 0x80;
|
|
}
|
|
}};
|
|
|
|
def format CP0Control(code, *flags) {{
|
|
flags += ('IsNonSpeculative', )
|
|
iop = InstObjParams(name, Name, 'CP0Control', code, flags)
|
|
header_output = BasicDeclare.subst(iop)
|
|
decoder_output = BasicConstructor.subst(iop)
|
|
decode_block = BasicDecode.subst(iop)
|
|
exec_output = CP0Execute.subst(iop)
|
|
}};
|
|
def format CP0TLB(code, *flags) {{
|
|
flags += ('IsNonSpeculative', )
|
|
iop = InstObjParams(name, Name, 'CP0Control', code, flags)
|
|
header_output = BasicDeclare.subst(iop)
|
|
decoder_output = BasicConstructor.subst(iop)
|
|
decode_block = BasicDecode.subst(iop)
|
|
exec_output = ControlTLBExecute.subst(iop)
|
|
}};
|
|
def format CP1Control(code, *flags) {{
|
|
flags += ('IsNonSpeculative', )
|
|
iop = InstObjParams(name, Name, 'CP1Control', code, flags)
|
|
header_output = BasicDeclare.subst(iop)
|
|
decoder_output = BasicConstructor.subst(iop)
|
|
decode_block = BasicDecode.subst(iop)
|
|
exec_output = CP1Execute.subst(iop)
|
|
}};
|