summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/SConscript64
-rw-r--r--src/cpu/base_dyn_inst.hh43
-rw-r--r--src/cpu/checker/SConsopts4
-rw-r--r--src/cpu/checker/cpu.hh27
-rw-r--r--src/cpu/exec_context.cc40
-rw-r--r--src/cpu/exec_context.hh278
-rw-r--r--src/cpu/inorder/SConsopts5
-rw-r--r--src/cpu/inorder/inorder_dyn_inst.cc5
-rw-r--r--src/cpu/inorder/inorder_dyn_inst.hh46
-rw-r--r--src/cpu/minor/SConsopts5
-rw-r--r--src/cpu/minor/exec_context.hh25
-rw-r--r--src/cpu/nocpu/SConsopts2
-rw-r--r--src/cpu/o3/SConsopts5
-rw-r--r--src/cpu/o3/dyn_inst.hh15
-rw-r--r--src/cpu/ozone/SConsopts8
-rw-r--r--src/cpu/simple/SConsopts10
-rw-r--r--src/cpu/simple/base.hh30
-rw-r--r--src/cpu/simple_thread.cc16
-rw-r--r--src/cpu/static_inst.hh38
19 files changed, 389 insertions, 277 deletions
diff --git a/src/cpu/SConscript b/src/cpu/SConscript
index 1ea92114a..5d9a48716 100644
--- a/src/cpu/SConscript
+++ b/src/cpu/SConscript
@@ -35,71 +35,8 @@ if env['TARGET_ISA'] == 'null':
Source('intr_control_noisa.cc')
Return()
-#################################################################
-#
-# Generate StaticInst execute() method signatures.
-#
-# There must be one signature for each CPU model compiled in.
-# Since the set of compiled-in models is flexible, we generate a
-# header containing the appropriate set of signatures on the fly.
-#
-#################################################################
-
-# Template for execute() signature.
-exec_sig_template = '''
-virtual Fault execute(%(type)s *xc, Trace::InstRecord *traceData) const = 0;
-virtual Fault eaComp(%(type)s *xc, Trace::InstRecord *traceData) const
-{ panic("eaComp not defined!"); M5_DUMMY_RETURN };
-virtual Fault initiateAcc(%(type)s *xc, Trace::InstRecord *traceData) const
-{ panic("initiateAcc not defined!"); M5_DUMMY_RETURN };
-virtual Fault completeAcc(Packet *pkt, %(type)s *xc,
- Trace::InstRecord *traceData) const
-{ panic("completeAcc not defined!"); M5_DUMMY_RETURN };
-'''
-
-mem_ini_sig_template = '''
-virtual Fault eaComp(%(type)s *xc, Trace::InstRecord *traceData) const
-{ panic("eaComp not defined!"); M5_DUMMY_RETURN };
-virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); M5_DUMMY_RETURN };
-'''
-
-mem_comp_sig_template = '''
-virtual Fault completeAcc(uint8_t *data, %s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); return NoFault; M5_DUMMY_RETURN };
-'''
-
-# Generate a temporary CPU list, including the CheckerCPU if
-# it's enabled. This isn't used for anything else other than StaticInst
-# headers.
-temp_cpu_list = env['CPU_MODELS'][:]
-temp_cpu_list.append('CheckerCPU')
SimObject('CheckerCPU.py')
-# Generate header.
-def gen_cpu_exec_signatures(target, source, env):
- f = open(str(target[0]), 'w')
- print >> f, '''
-#ifndef __CPU_STATIC_INST_EXEC_SIGS_HH__
-#define __CPU_STATIC_INST_EXEC_SIGS_HH__
-'''
- for cpu in temp_cpu_list:
- xc_type = CpuModel.dict[cpu].strings['CPU_exec_context']
- print >> f, exec_sig_template % { 'type' : xc_type }
- print >> f, '''
-#endif // __CPU_STATIC_INST_EXEC_SIGS_HH__
-'''
-
-# Generate string that gets printed when header is rebuilt
-def gen_sigs_string(target, source, env):
- return " [GENERATE] static_inst_exec_sigs.hh: " \
- + ', '.join(temp_cpu_list)
-
-# Add command to generate header to environment.
-env.Command('static_inst_exec_sigs.hh', (),
- Action(gen_cpu_exec_signatures, gen_sigs_string,
- varlist = temp_cpu_list))
-
-env.Depends('static_inst_exec_sigs.hh', Value(env['CPU_MODELS']))
-
SimObject('BaseCPU.py')
SimObject('FuncUnit.py')
SimObject('ExeTracer.py')
@@ -112,6 +49,7 @@ Source('activity.cc')
Source('base.cc')
Source('cpuevent.cc')
Source('exetrace.cc')
+Source('exec_context.cc')
Source('func_unit.cc')
Source('inteltrace.cc')
Source('intr_control.cc')
diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh
index 08e16d330..9346b69cc 100644
--- a/src/cpu/base_dyn_inst.hh
+++ b/src/cpu/base_dyn_inst.hh
@@ -56,6 +56,7 @@
#include "config/the_isa.hh"
#include "cpu/checker/cpu.hh"
#include "cpu/o3/comm.hh"
+#include "cpu/exec_context.hh"
#include "cpu/exetrace.hh"
#include "cpu/inst_seq.hh"
#include "cpu/op_class.hh"
@@ -73,7 +74,7 @@
*/
template <class Impl>
-class BaseDynInst : public RefCounted
+class BaseDynInst : public ExecContext, public RefCounted
{
public:
// Typedef for the CPU.
@@ -82,10 +83,6 @@ class BaseDynInst : public RefCounted
// Logical register index type.
typedef TheISA::RegIndex RegIndex;
- // Integer register type.
- typedef TheISA::IntReg IntReg;
- // Floating point register type.
- typedef TheISA::FloatReg FloatReg;
// The DynInstPtr type.
typedef typename Impl::DynInstPtr DynInstPtr;
@@ -634,43 +631,25 @@ class BaseDynInst : public RefCounted
}
/** Records an integer register being set to a value. */
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
+ void setIntRegOperand(const StaticInst *si, int idx, IntReg val)
{
setResult<uint64_t>(val);
}
/** Records a CC register being set to a value. */
- void setCCRegOperand(const StaticInst *si, int idx, uint64_t val)
+ void setCCRegOperand(const StaticInst *si, int idx, CCReg val)
{
setResult<uint64_t>(val);
}
/** Records an fp register being set to a value. */
- void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
- int width)
- {
- if (width == 32 || width == 64) {
- setResult<double>(val);
- } else {
- panic("Unsupported width!");
- }
- }
-
- /** Records an fp register being set to a value. */
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
{
setResult<double>(val);
}
/** Records an fp register being set to an integer value. */
- void setFloatRegOperandBits(const StaticInst *si, int idx, uint64_t val,
- int width)
- {
- setResult<uint64_t>(val);
- }
-
- /** Records an fp register being set to an integer value. */
- void setFloatRegOperandBits(const StaticInst *si, int idx, uint64_t val)
+ void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val)
{
setResult<uint64_t>(val);
}
@@ -802,10 +781,10 @@ class BaseDynInst : public RefCounted
bool isSquashedInROB() const { return status[SquashedInROB]; }
/** Read the PC state of this instruction. */
- const TheISA::PCState pcState() const { return pc; }
+ TheISA::PCState pcState() const { return pc; }
/** Set the PC state of this instruction. */
- const void pcState(const TheISA::PCState &val) { pc = val; }
+ void pcState(const TheISA::PCState &val) { pc = val; }
/** Read the PC of this instruction. */
const Addr instAddr() const { return pc.instAddr(); }
@@ -844,10 +823,10 @@ class BaseDynInst : public RefCounted
public:
/** Sets the effective address. */
- void setEA(Addr &ea) { instEffAddr = ea; instFlags[EACalcDone] = true; }
+ void setEA(Addr ea) { instEffAddr = ea; instFlags[EACalcDone] = true; }
/** Returns the effective address. */
- const Addr &getEA() const { return instEffAddr; }
+ Addr getEA() const { return instEffAddr; }
/** Returns whether or not the eff. addr. calculation has been completed. */
bool doneEACalc() { return instFlags[EACalcDone]; }
@@ -869,11 +848,11 @@ class BaseDynInst : public RefCounted
public:
/** Returns the number of consecutive store conditional failures. */
- unsigned readStCondFailures()
+ unsigned int readStCondFailures() const
{ return thread->storeCondFailures; }
/** Sets the number of consecutive store conditional failures. */
- void setStCondFailures(unsigned sc_failures)
+ void setStCondFailures(unsigned int sc_failures)
{ thread->storeCondFailures = sc_failures; }
};
diff --git a/src/cpu/checker/SConsopts b/src/cpu/checker/SConsopts
index 94d8e0e9f..5d676ba1b 100644
--- a/src/cpu/checker/SConsopts
+++ b/src/cpu/checker/SConsopts
@@ -30,6 +30,4 @@
Import('*')
-CpuModel('CheckerCPU', 'checker_cpu_exec.cc',
- '#include "cpu/checker/cpu.hh"',
- { 'CPU_exec_context': 'CheckerCPU' })
+CpuModel('CheckerCPU')
diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh
index 9f4c4d58c..bf71dc30e 100644
--- a/src/cpu/checker/cpu.hh
+++ b/src/cpu/checker/cpu.hh
@@ -52,6 +52,7 @@
#include "base/statistics.hh"
#include "cpu/base.hh"
#include "cpu/base_dyn_inst.hh"
+#include "cpu/exec_context.hh"
#include "cpu/pc_event.hh"
#include "cpu/simple_thread.hh"
#include "cpu/static_inst.hh"
@@ -86,7 +87,7 @@ class Request;
* checker to be able to correctly verify instructions, even with
* external accesses to the ThreadContext that change state.
*/
-class CheckerCPU : public BaseCPU
+class CheckerCPU : public BaseCPU, public ExecContext
{
protected:
typedef TheISA::MachInst MachInst;
@@ -194,7 +195,7 @@ class CheckerCPU : public BaseCPU
// These functions are only used in CPU models that split
// effective address computation from the actual memory access.
void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); }
- Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); }
+ Addr getEA() const { panic("SimpleCPU::getEA() not implemented\n"); }
// The register accessor methods provide the index of the
// instruction's operand (e.g., 0 or 1), not the architectural
@@ -207,7 +208,7 @@ class CheckerCPU : public BaseCPU
// storage (which is pretty hard to imagine they would have reason
// to do).
- uint64_t readIntRegOperand(const StaticInst *si, int idx)
+ IntReg readIntRegOperand(const StaticInst *si, int idx)
{
return thread->readIntReg(si->srcRegIdx(idx));
}
@@ -224,7 +225,7 @@ class CheckerCPU : public BaseCPU
return thread->readFloatRegBits(reg_idx);
}
- uint64_t readCCRegOperand(const StaticInst *si, int idx)
+ CCReg readCCRegOperand(const StaticInst *si, int idx)
{
int reg_idx = si->srcRegIdx(idx) - TheISA::CC_Reg_Base;
return thread->readCCReg(reg_idx);
@@ -238,7 +239,7 @@ class CheckerCPU : public BaseCPU
result.push(instRes);
}
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
+ void setIntRegOperand(const StaticInst *si, int idx, IntReg val)
{
thread->setIntReg(si->destRegIdx(idx), val);
setResult<uint64_t>(val);
@@ -259,7 +260,7 @@ class CheckerCPU : public BaseCPU
setResult<uint64_t>(val);
}
- void setCCRegOperand(const StaticInst *si, int idx, uint64_t val)
+ void setCCRegOperand(const StaticInst *si, int idx, CCReg val)
{
int reg_idx = si->destRegIdx(idx) - TheISA::CC_Reg_Base;
thread->setCCReg(reg_idx, val);
@@ -272,7 +273,7 @@ class CheckerCPU : public BaseCPU
thread->setPredicate(val);
}
- TheISA::PCState pcState() { return thread->pcState(); }
+ TheISA::PCState pcState() const { return thread->pcState(); }
void pcState(const TheISA::PCState &val)
{
DPRINTF(Checker, "Changing PC to %s, old PC %s.\n",
@@ -322,13 +323,13 @@ class CheckerCPU : public BaseCPU
}
#if THE_ISA == MIPS_ISA
- uint64_t readRegOtherThread(int misc_reg)
+ MiscReg readRegOtherThread(int misc_reg, ThreadID tid)
{
panic("MIPS MT not defined for CheckerCPU.\n");
return 0;
}
- void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val)
+ void setRegOtherThread(int misc_reg, MiscReg val, ThreadID tid)
{
panic("MIPS MT not defined for CheckerCPU.\n");
}
@@ -362,7 +363,11 @@ class CheckerCPU : public BaseCPU
Fault writeMem(uint8_t *data, unsigned size,
Addr addr, unsigned flags, uint64_t *res);
- void setStCondFailures(unsigned sc_failures)
+ unsigned int readStCondFailures() const {
+ return thread->readStCondFailures();
+ }
+
+ void setStCondFailures(unsigned int sc_failures)
{}
/////////////////////////////////////////////////////
@@ -371,7 +376,7 @@ class CheckerCPU : public BaseCPU
void wakeup() { }
// Assume that the normal CPU's call to syscall was successful.
// The checker's state would have already been updated by the syscall.
- void syscall(uint64_t callnum) { }
+ void syscall(int64_t callnum) { }
void handleError()
{
diff --git a/src/cpu/exec_context.cc b/src/cpu/exec_context.cc
new file mode 100644
index 000000000..0dde0dc71
--- /dev/null
+++ b/src/cpu/exec_context.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#include "cpu/exec_context.hh"
diff --git a/src/cpu/exec_context.hh b/src/cpu/exec_context.hh
index 2f4d26976..c93f7f32b 100644
--- a/src/cpu/exec_context.hh
+++ b/src/cpu/exec_context.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2014 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -26,104 +38,228 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
+ * Andreas Sandberg
*/
-#error "Cannot include this file"
+#ifndef __CPU_EXEC_CONTEXT_HH__
+#define __CPU_EXEC_CONTEXT_HH__
+
+#include "arch/registers.hh"
+#include "base/types.hh"
+#include "config/the_isa.hh"
+#include "cpu/static_inst_fwd.hh"
+#include "cpu/translation.hh"
+#include "sim/fault_fwd.hh"
/**
- * The ExecContext is not a usable class. It is simply here for
- * documentation purposes. It shows the interface that is used by the
- * ISA to access and change CPU state.
+ * The ExecContext is an abstract base class the provides the
+ * interface used by the ISA to manipulate the state of the CPU model.
+ *
+ * Register accessor methods in this class typically provide the index
+ * of the instruction's operand (e.g., 0 or 1), not the architectural
+ * register index, to simplify the implementation of register
+ * renaming. The architectural register index can be found by
+ * indexing into the instruction's own operand index table.
+ *
+ * @note The methods in this class typically take a raw pointer to the
+ * StaticInst is provided instead of a ref-counted StaticInstPtr to
+ * reduce overhead as an argument. This is fine as long as the
+ * implementation doesn't copy the pointer into any long-term storage
+ * (which is pretty hard to imagine they would have reason to do).
*/
class ExecContext {
- // The register accessor methods provide the index of the
- // instruction's operand (e.g., 0 or 1), not the architectural
- // register index, to simplify the implementation of register
- // renaming. We find the architectural register index by indexing
- // into the instruction's own operand index table. Note that a
- // raw pointer to the StaticInst is provided instead of a
- // ref-counted StaticInstPtr to reduce overhead. This is fine as
- // long as these methods don't copy the pointer into any long-term
- // storage (which is pretty hard to imagine they would have reason
- // to do).
+ public:
+ typedef TheISA::IntReg IntReg;
+ typedef TheISA::PCState PCState;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ typedef TheISA::MiscReg MiscReg;
+
+ typedef TheISA::CCReg CCReg;
+
+ public:
+ /**
+ * @{
+ * @name Integer Register Interfaces
+ *
+ */
/** Reads an integer register. */
- uint64_t readIntRegOperand(const StaticInst *si, int idx);
+ virtual IntReg readIntRegOperand(const StaticInst *si, int idx) = 0;
+
+ /** Sets an integer register to a value. */
+ virtual void setIntRegOperand(const StaticInst *si,
+ int idx, IntReg val) = 0;
+
+ /** @} */
+
+
+ /**
+ * @{
+ * @name Floating Point Register Interfaces
+ */
/** Reads a floating point register of single register width. */
- FloatReg readFloatRegOperand(const StaticInst *si, int idx);
+ virtual FloatReg readFloatRegOperand(const StaticInst *si, int idx) = 0;
/** Reads a floating point register in its binary format, instead
* of by value. */
- FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx);
-
- /** Sets an integer register to a value. */
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val);
+ virtual FloatRegBits readFloatRegOperandBits(const StaticInst *si,
+ int idx) = 0;
/** Sets a floating point register of single width to a value. */
- void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val);
+ virtual void setFloatRegOperand(const StaticInst *si,
+ int idx, FloatReg val) = 0;
/** Sets the bits of a floating point register of single width
* to a binary value. */
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- FloatRegBits val);
-
- /** Reads the PC. */
- uint64_t readPC();
- /** Reads the NextPC. */
- uint64_t readNextPC();
- /** Reads the Next-NextPC. Only for architectures like SPARC or MIPS. */
- uint64_t readNextNPC();
-
- /** Sets the PC. */
- void setPC(uint64_t val);
- /** Sets the NextPC. */
- void setNextPC(uint64_t val);
- /** Sets the Next-NextPC. Only for architectures like SPARC or MIPS. */
- void setNextNPC(uint64_t val);
-
- /** Reads a miscellaneous register. */
- MiscReg readMiscRegNoEffect(int misc_reg);
-
- /** Reads a miscellaneous register, handling any architectural
- * side effects due to reading that register. */
- MiscReg readMiscReg(int misc_reg);
-
- /** Sets a miscellaneous register. */
- void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
-
- /** Sets a miscellaneous register, handling any architectural
- * side effects due to writing that register. */
- void setMiscReg(int misc_reg, const MiscReg &val);
-
- /** Records the effective address of the instruction. Only valid
- * for memory ops. */
- void setEA(Addr EA);
- /** Returns the effective address of the instruction. Only valid
- * for memory ops. */
- Addr getEA();
+ virtual void setFloatRegOperandBits(const StaticInst *si,
+ int idx, FloatRegBits val) = 0;
- /** Returns a pointer to the ThreadContext. */
- ThreadContext *tcBase();
+ /** @} */
+
+ /**
+ * @{
+ * @name Condition Code Registers
+ */
+ virtual CCReg readCCRegOperand(const StaticInst *si, int idx) = 0;
+ virtual void setCCRegOperand(const StaticInst *si, int idx, CCReg val) = 0;
+ /** @} */
+
+ /**
+ * @{
+ * @name Misc Register Interfaces
+ */
+ virtual MiscReg readMiscRegOperand(const StaticInst *si, int idx) = 0;
+ virtual void setMiscRegOperand(const StaticInst *si,
+ int idx, const MiscReg &val) = 0;
+
+ /**
+ * Reads a miscellaneous register, handling any architectural
+ * side effects due to reading that register.
+ */
+ virtual MiscReg readMiscReg(int misc_reg) = 0;
+
+ /**
+ * Sets a miscellaneous register, handling any architectural
+ * side effects due to writing that register.
+ */
+ virtual void setMiscReg(int misc_reg, const MiscReg &val) = 0;
+
+ /** @} */
+
+ /**
+ * @{
+ * @name PC Control
+ */
+ virtual PCState pcState() const = 0;
+ virtual void pcState(const PCState &val) = 0;
+ /** @} */
+
+ /**
+ * @{
+ * @name Memory Interface
+ */
+ /**
+ * Record the effective address of the instruction.
+ *
+ * @note Only valid for memory ops.
+ */
+ virtual void setEA(Addr EA) = 0;
+ /**
+ * Get the effective address of the instruction.
+ *
+ * @note Only valid for memory ops.
+ */
+ virtual Addr getEA() const = 0;
+
+ virtual Fault readMem(Addr addr, uint8_t *data, unsigned int size,
+ unsigned int flags) = 0;
+
+ virtual Fault writeMem(uint8_t *data, unsigned int size, Addr addr,
+ unsigned int flags, uint64_t *res) = 0;
+
+ /**
+ * Sets the number of consecutive store conditional failures.
+ */
+ virtual void setStCondFailures(unsigned int sc_failures) = 0;
+
+ /**
+ * Returns the number of consecutive store conditional failures.
+ */
+ virtual unsigned int readStCondFailures() const = 0;
- Fault readMem(Addr addr, uint8_t *data, unsigned size, unsigned flags);
+ /** @} */
- Fault writeMem(uint8_t *data, unsigned size,
- Addr addr, unsigned flags, uint64_t *res);
+ /**
+ * @{
+ * @name SysCall Emulation Interfaces
+ */
+
+ /**
+ * Executes a syscall specified by the callnum.
+ */
+ virtual void syscall(int64_t callnum) = 0;
+
+ /** @} */
+
+ /** Returns a pointer to the ThreadContext. */
+ virtual ThreadContext *tcBase() = 0;
+
+ /**
+ * @{
+ * @name Alpha-Specific Interfaces
+ */
- /** Somewhat Alpha-specific function that handles returning from
- * an error or interrupt. */
- Fault hwrei();
+ /**
+ * Somewhat Alpha-specific function that handles returning from an
+ * error or interrupt.
+ */
+ virtual Fault hwrei() = 0;
/**
* Check for special simulator handling of specific PAL calls. If
* return value is false, actual PAL call will be suppressed.
*/
- bool simPalCheck(int palFunc);
+ virtual bool simPalCheck(int palFunc) = 0;
+
+ /** @} */
+
+ /**
+ * @{
+ * @name ARM-Specific Interfaces
+ */
+
+ virtual bool readPredicate() = 0;
+ virtual void setPredicate(bool val) = 0;
+
+ /** @} */
+
+ /**
+ * @{
+ * @name X86-Specific Interfaces
+ */
+
+ /**
+ * Invalidate a page in the DTLB <i>and</i> ITLB.
+ */
+ virtual void demapPage(Addr vaddr, uint64_t asn) = 0;
- /** Executes a syscall specified by the callnum. */
- void syscall(int64_t callnum);
+ /** @} */
- /** Finish a DTB address translation. */
- void finishTranslation(WholeTranslationState *state);
+ /**
+ * @{
+ * @name MIPS-Specific Interfaces
+ */
+
+#if THE_ISA == MIPS_ISA
+ virtual MiscReg readRegOtherThread(int regIdx,
+ ThreadID tid = InvalidThreadID) = 0;
+ virtual void setRegOtherThread(int regIdx, MiscReg val,
+ ThreadID tid = InvalidThreadID) = 0;
+#endif
+
+ /** @} */
};
+
+#endif // __CPU_EXEC_CONTEXT_HH__
diff --git a/src/cpu/inorder/SConsopts b/src/cpu/inorder/SConsopts
index 709051407..f6b8917c6 100644
--- a/src/cpu/inorder/SConsopts
+++ b/src/cpu/inorder/SConsopts
@@ -30,7 +30,4 @@
Import('*')
-CpuModel('InOrderCPU', 'inorder_cpu_exec.cc',
- '#include "cpu/inorder/inorder_dyn_inst.hh"',
- { 'CPU_exec_context': 'InOrderDynInst' },
- default=True)
+CpuModel('InOrderCPU', default=True)
diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc
index 86dbdf97c..d0d308f7a 100644
--- a/src/cpu/inorder/inorder_dyn_inst.cc
+++ b/src/cpu/inorder/inorder_dyn_inst.cc
@@ -469,7 +469,7 @@ InOrderDynInst::setMiscRegOperand(const StaticInst *si, int idx,
}
MiscReg
-InOrderDynInst::readRegOtherThread(unsigned reg_idx, ThreadID tid)
+InOrderDynInst::readRegOtherThread(int reg_idx, ThreadID tid)
{
if (tid == -1) {
tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
@@ -544,8 +544,7 @@ InOrderDynInst::setMiscReg(int misc_reg, const MiscReg &val)
}
void
-InOrderDynInst::setRegOtherThread(unsigned reg_idx, const MiscReg &val,
- ThreadID tid)
+InOrderDynInst::setRegOtherThread(int reg_idx, MiscReg val, ThreadID tid)
{
if (tid == InvalidThreadID) {
tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh
index 578fd604a..759da4b04 100644
--- a/src/cpu/inorder/inorder_dyn_inst.hh
+++ b/src/cpu/inorder/inorder_dyn_inst.hh
@@ -45,6 +45,7 @@
#include "base/trace.hh"
#include "base/types.hh"
#include "config/the_isa.hh"
+#include "cpu/exec_context.hh"
#include "cpu/inorder/inorder_trace.hh"
#include "cpu/inorder/pipeline_traits.hh"
#include "cpu/inorder/resource.hh"
@@ -73,7 +74,7 @@
class ResourceRequest;
class Packet;
-class InOrderDynInst : public RefCounted
+class InOrderDynInst : public ExecContext, public RefCounted
{
public:
// Binary machine instruction type.
@@ -543,7 +544,7 @@ class InOrderDynInst : public RefCounted
//
////////////////////////////////////////////////////////////
/** Read the PC of this instruction. */
- const TheISA::PCState &pcState() const { return pc; }
+ TheISA::PCState pcState() const { return pc; }
/** Sets the PC of this instruction. */
void pcState(const TheISA::PCState &_pc) { pc = _pc; }
@@ -649,10 +650,10 @@ class InOrderDynInst : public RefCounted
{ return memAddr; }
/** Sets the effective address. */
- void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; }
+ void setEA(Addr ea) { instEffAddr = ea; eaCalcDone = true; }
/** Returns the effective address. */
- const Addr &getEA() const { return instEffAddr; }
+ Addr getEA() const { return instEffAddr; }
/** Returns whether or not the eff. addr. calculation has been completed.*/
bool doneEACalc() { return eaCalcDone; }
@@ -854,7 +855,10 @@ class InOrderDynInst : public RefCounted
* language (which is why the name isnt readIntSrc(...)) Note: That
* the source reg. value is set using the setSrcReg() function.
*/
- IntReg readIntRegOperand(const StaticInst *si, int idx, ThreadID tid = 0);
+ IntReg readIntRegOperand(const StaticInst *si, int idx, ThreadID tid);
+ IntReg readIntRegOperand(const StaticInst *si, int idx) {
+ return readIntRegOperand(si, idx, 0);
+ }
FloatReg readFloatRegOperand(const StaticInst *si, int idx);
TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx);
MiscReg readMiscReg(int misc_reg);
@@ -899,24 +903,21 @@ class InOrderDynInst : public RefCounted
void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val);
void setFloatRegOperandBits(const StaticInst *si, int idx,
TheISA::FloatRegBits val);
- void setCCRegOperand(const StaticInst *si, int idx, CCReg val);
void setMiscReg(int misc_reg, const MiscReg &val);
void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
void setMiscRegOperand(const StaticInst *si, int idx, const MiscReg &val);
void setMiscRegOperandNoEffect(const StaticInst *si, int idx,
const MiscReg &val);
- virtual uint64_t readRegOtherThread(unsigned idx,
- ThreadID tid = InvalidThreadID);
- virtual void setRegOtherThread(unsigned idx, const uint64_t &val,
- ThreadID tid = InvalidThreadID);
+ MiscReg readRegOtherThread(int idx, ThreadID tid);
+ void setRegOtherThread(int idx, MiscReg val, ThreadID tid);
/** Returns the number of consecutive store conditional failures. */
- unsigned readStCondFailures()
+ unsigned int readStCondFailures() const
{ return thread->storeCondFailures; }
/** Sets the number of consecutive store conditional failures. */
- void setStCondFailures(unsigned sc_failures)
+ void setStCondFailures(unsigned int sc_failures)
{ thread->storeCondFailures = sc_failures; }
//////////////////////////////////////////////////////////////
@@ -1063,6 +1064,27 @@ class InOrderDynInst : public RefCounted
void dump(std::string &outstring);
//inline int curCount() { return curCount(); }
+
+
+ CCReg readCCRegOperand(const StaticInst *si, int idx) {
+ panic("readCCRegOperand unimplemented");
+ }
+
+ void setCCRegOperand(const StaticInst *si, int idx, CCReg val) {
+ panic("setCCRegOperand unimplemented");
+ }
+
+ void setPredicate(bool val) {
+ panic("setPredicate unimplemented");
+ }
+
+ bool readPredicate() {
+ panic("readPredicate unimplemented");
+ }
+
+ void demapPage(Addr vaddr, uint64_t asn) {
+ panic("demapPage unimplemented");
+ }
};
diff --git a/src/cpu/minor/SConsopts b/src/cpu/minor/SConsopts
index 68c420779..b74e15730 100644
--- a/src/cpu/minor/SConsopts
+++ b/src/cpu/minor/SConsopts
@@ -39,7 +39,4 @@
Import('*')
-CpuModel('MinorCPU', 'minor_cpu_exec.cc',
- '#include "cpu/minor/exec_context.hh"',
- { 'CPU_exec_context': 'Minor::ExecContext' },
- default=True)
+CpuModel('MinorCPU', default=True)
diff --git a/src/cpu/minor/exec_context.hh b/src/cpu/minor/exec_context.hh
index df909a95c..f1143498e 100644
--- a/src/cpu/minor/exec_context.hh
+++ b/src/cpu/minor/exec_context.hh
@@ -53,6 +53,7 @@
#ifndef __CPU_MINOR_EXEC_CONTEXT_HH__
#define __CPU_MINOR_EXEC_CONTEXT_HH__
+#include "cpu/exec_context.hh"
#include "cpu/minor/execute.hh"
#include "cpu/minor/pipeline.hh"
#include "cpu/base.hh"
@@ -69,7 +70,7 @@ class Execute;
* separates that interface from other classes such as Pipeline, MinorCPU
* and DynMinorInst and makes it easier to see what state is accessed by it.
*/
-class ExecContext
+class ExecContext : public ::ExecContext
{
public:
MinorCPU &cpu;
@@ -119,7 +120,7 @@ class ExecContext
return NoFault;
}
- uint64_t
+ IntReg
readIntRegOperand(const StaticInst *si, int idx)
{
return thread.readIntReg(si->srcRegIdx(idx));
@@ -140,7 +141,7 @@ class ExecContext
}
void
- setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
+ setIntRegOperand(const StaticInst *si, int idx, IntReg val)
{
thread.setIntReg(si->destRegIdx(idx), val);
}
@@ -174,7 +175,7 @@ class ExecContext
}
TheISA::PCState
- pcState()
+ pcState() const
{
return thread.pcState();
}
@@ -250,12 +251,8 @@ class ExecContext
ThreadContext *tcBase() { return thread.getTC(); }
/* @todo, should make stCondFailures persistent somewhere */
- unsigned int readStCondFailures() { return 0; }
- unsigned int
- setStCondFailures(unsigned int st_cond_failures)
- {
- return 0;
- }
+ unsigned int readStCondFailures() const { return 0; }
+ void setStCondFailures(unsigned int st_cond_failures) {}
int contextId() { return thread.contextId(); }
/* ISA-specific (or at least currently ISA singleton) functions */
@@ -295,7 +292,7 @@ class ExecContext
}
/* ALPHA/POWER: Effective address storage */
- void setEA(Addr &ea)
+ void setEA(Addr ea)
{
inst->ea = ea;
}
@@ -303,14 +300,14 @@ class ExecContext
BaseCPU *getCpuPtr() { return &cpu; }
/* POWER: Effective address storage */
- Addr getEA()
+ Addr getEA() const
{
return inst->ea;
}
/* MIPS: other thread register reading/writing */
uint64_t
- readRegOtherThread(unsigned idx, ThreadID tid = InvalidThreadID)
+ readRegOtherThread(int idx, ThreadID tid = InvalidThreadID)
{
SimpleThread *other_thread = (tid == InvalidThreadID
? &thread : cpu.threads[tid]);
@@ -327,7 +324,7 @@ class ExecContext
}
void
- setRegOtherThread(unsigned idx, const TheISA::MiscReg &val,
+ setRegOtherThread(int idx, const TheISA::MiscReg &val,
ThreadID tid = InvalidThreadID)
{
SimpleThread *other_thread = (tid == InvalidThreadID
diff --git a/src/cpu/nocpu/SConsopts b/src/cpu/nocpu/SConsopts
index 0baef0a82..40bf503ea 100644
--- a/src/cpu/nocpu/SConsopts
+++ b/src/cpu/nocpu/SConsopts
@@ -1,4 +1,4 @@
Import('*')
-CpuModel('no', '', '', { '': '' })
+CpuModel('no')
diff --git a/src/cpu/o3/SConsopts b/src/cpu/o3/SConsopts
index b780f6b2a..dfee888e5 100644
--- a/src/cpu/o3/SConsopts
+++ b/src/cpu/o3/SConsopts
@@ -30,7 +30,4 @@
Import('*')
-CpuModel('O3CPU', 'o3_cpu_exec.cc',
- '#include "cpu/o3/isa_specific.hh"',
- { 'CPU_exec_context': 'O3DynInst' },
- default=True)
+CpuModel('O3CPU', default=True)
diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh
index 76bd8b291..52ea1101a 100644
--- a/src/cpu/o3/dyn_inst.hh
+++ b/src/cpu/o3/dyn_inst.hh
@@ -71,9 +71,8 @@ class BaseO3DynInst : public BaseDynInst<Impl>
typedef TheISA::IntReg IntReg;
typedef TheISA::FloatReg FloatReg;
typedef TheISA::FloatRegBits FloatRegBits;
-#ifdef ISA_HAS_CC_REGS
typedef TheISA::CCReg CCReg;
-#endif
+
/** Misc register index type. */
typedef TheISA::MiscReg MiscReg;
@@ -250,7 +249,7 @@ class BaseO3DynInst : public BaseDynInst<Impl>
// storage (which is pretty hard to imagine they would have reason
// to do).
- uint64_t readIntRegOperand(const StaticInst *si, int idx)
+ IntReg readIntRegOperand(const StaticInst *si, int idx)
{
return this->cpu->readIntReg(this->_srcRegIdx[idx]);
}
@@ -265,7 +264,7 @@ class BaseO3DynInst : public BaseDynInst<Impl>
return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
}
- uint64_t readCCRegOperand(const StaticInst *si, int idx)
+ CCReg readCCRegOperand(const StaticInst *si, int idx)
{
return this->cpu->readCCReg(this->_srcRegIdx[idx]);
}
@@ -273,7 +272,7 @@ class BaseO3DynInst : public BaseDynInst<Impl>
/** @todo: Make results into arrays so they can handle multiple dest
* registers.
*/
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
+ void setIntRegOperand(const StaticInst *si, int idx, IntReg val)
{
this->cpu->setIntReg(this->_destRegIdx[idx], val);
BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
@@ -292,20 +291,20 @@ class BaseO3DynInst : public BaseDynInst<Impl>
BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
}
- void setCCRegOperand(const StaticInst *si, int idx, uint64_t val)
+ void setCCRegOperand(const StaticInst *si, int idx, CCReg val)
{
this->cpu->setCCReg(this->_destRegIdx[idx], val);
BaseDynInst<Impl>::setCCRegOperand(si, idx, val);
}
#if THE_ISA == MIPS_ISA
- uint64_t readRegOtherThread(int misc_reg)
+ MiscReg readRegOtherThread(int misc_reg, ThreadID tid)
{
panic("MIPS MT not defined for O3 CPU.\n");
return 0;
}
- void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val)
+ void setRegOtherThread(int misc_reg, MiscReg val, ThreadID tid)
{
panic("MIPS MT not defined for O3 CPU.\n");
}
diff --git a/src/cpu/ozone/SConsopts b/src/cpu/ozone/SConsopts
index adfda63a9..c1ee00ec3 100644
--- a/src/cpu/ozone/SConsopts
+++ b/src/cpu/ozone/SConsopts
@@ -30,10 +30,6 @@
Import('*')
-CpuModel('OzoneSimpleCPU', 'ozone_simple_exec.cc',
- '#include "cpu/ozone/dyn_inst.hh"',
- { 'CPU_exec_context': 'OzoneDynInst<SimpleImpl>' })
-CpuModel('OzoneCPU', 'ozone_exec.cc',
- '#include "cpu/ozone/dyn_inst.hh"',
- { 'CPU_exec_context': 'OzoneDynInst<OzoneImpl>' })
+CpuModel('OzoneSimpleCPU')
+CpuModel('OzoneCPU')
diff --git a/src/cpu/simple/SConsopts b/src/cpu/simple/SConsopts
index ab84144af..9c99a818f 100644
--- a/src/cpu/simple/SConsopts
+++ b/src/cpu/simple/SConsopts
@@ -30,11 +30,5 @@
Import('*')
-CpuModel('AtomicSimpleCPU', 'atomic_simple_cpu_exec.cc',
- '#include "cpu/simple/atomic.hh"',
- { 'CPU_exec_context': 'AtomicSimpleCPU' },
- default=True)
-CpuModel('TimingSimpleCPU', 'timing_simple_cpu_exec.cc',
- '#include "cpu/simple/timing.hh"',
- { 'CPU_exec_context': 'TimingSimpleCPU' },
- default=True)
+CpuModel('AtomicSimpleCPU', default=True)
+CpuModel('TimingSimpleCPU', default=True)
diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh
index 47034c300..3755a94a9 100644
--- a/src/cpu/simple/base.hh
+++ b/src/cpu/simple/base.hh
@@ -50,6 +50,7 @@
#include "config/the_isa.hh"
#include "cpu/base.hh"
#include "cpu/checker/cpu.hh"
+#include "cpu/exec_context.hh"
#include "cpu/pc_event.hh"
#include "cpu/simple_thread.hh"
#include "cpu/static_inst.hh"
@@ -79,7 +80,7 @@ namespace Trace {
struct BaseSimpleCPUParams;
class BPredUnit;
-class BaseSimpleCPU : public BaseCPU
+class BaseSimpleCPU : public BaseCPU, public ExecContext
{
protected:
typedef TheISA::MiscReg MiscReg;
@@ -293,8 +294,7 @@ class BaseSimpleCPU : public BaseCPU
// These functions are only used in CPU models that split
// effective address computation from the actual memory access.
void setEA(Addr EA) { panic("BaseSimpleCPU::setEA() not implemented\n"); }
- Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n");
- M5_DUMMY_RETURN}
+ Addr getEA() const { panic("BaseSimpleCPU::getEA() not implemented\n"); }
// The register accessor methods provide the index of the
// instruction's operand (e.g., 0 or 1), not the architectural
@@ -307,7 +307,7 @@ class BaseSimpleCPU : public BaseCPU
// storage (which is pretty hard to imagine they would have reason
// to do).
- uint64_t readIntRegOperand(const StaticInst *si, int idx)
+ IntReg readIntRegOperand(const StaticInst *si, int idx)
{
numIntRegReads++;
return thread->readIntReg(si->srcRegIdx(idx));
@@ -334,7 +334,7 @@ class BaseSimpleCPU : public BaseCPU
return thread->readCCReg(reg_idx);
}
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
+ void setIntRegOperand(const StaticInst *si, int idx, IntReg val)
{
numIntRegWrites++;
thread->setIntReg(si->destRegIdx(idx), val);
@@ -370,7 +370,7 @@ class BaseSimpleCPU : public BaseCPU
traceData->setPredicate(val);
}
}
- TheISA::PCState pcState() { return thread->pcState(); }
+ TheISA::PCState pcState() const { return thread->pcState(); }
void pcState(const TheISA::PCState &val) { thread->pcState(val); }
Addr instAddr() { return thread->instAddr(); }
Addr nextInstAddr() { return thread->nextInstAddr(); }
@@ -423,26 +423,26 @@ class BaseSimpleCPU : public BaseCPU
thread->demapDataPage(vaddr, asn);
}
- unsigned readStCondFailures() {
+ unsigned int readStCondFailures() const {
return thread->readStCondFailures();
}
- void setStCondFailures(unsigned sc_failures) {
+ void setStCondFailures(unsigned int sc_failures) {
thread->setStCondFailures(sc_failures);
}
- MiscReg readRegOtherThread(int regIdx, ThreadID tid = InvalidThreadID)
- {
+ MiscReg readRegOtherThread(int regIdx, ThreadID tid = InvalidThreadID)
+ {
panic("Simple CPU models do not support multithreaded "
"register access.\n");
- }
+ }
- void setRegOtherThread(int regIdx, const MiscReg &val,
- ThreadID tid = InvalidThreadID)
- {
+ void setRegOtherThread(int regIdx, MiscReg val,
+ ThreadID tid = InvalidThreadID)
+ {
panic("Simple CPU models do not support multithreaded "
"register access.\n");
- }
+ }
//Fault CacheOp(uint8_t Op, Addr EA);
diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc
index de01124e0..4e2e70e63 100644
--- a/src/cpu/simple_thread.cc
+++ b/src/cpu/simple_thread.cc
@@ -50,6 +50,7 @@
#include "mem/fs_translating_port_proxy.hh"
#include "mem/se_translating_port_proxy.hh"
#include "params/BaseCPU.hh"
+#include "sim/faults.hh"
#include "sim/full_system.hh"
#include "sim/process.hh"
#include "sim/serialize.hh"
@@ -213,3 +214,18 @@ SimpleThread::copyArchRegs(ThreadContext *src_tc)
TheISA::copyRegs(src_tc, tc);
}
+// The following methods are defined in src/arch/alpha/ev5.cc for
+// Alpha.
+#if THE_ISA != ALPHA_ISA
+Fault
+SimpleThread::hwrei()
+{
+ return NoFault;
+}
+
+bool
+SimpleThread::simPalCheck(int palFunc)
+{
+ return true;
+}
+#endif
diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh
index 375b7d0ba..c4dd3a6b5 100644
--- a/src/cpu/static_inst.hh
+++ b/src/cpu/static_inst.hh
@@ -50,19 +50,7 @@
// forward declarations
class Packet;
-struct O3CPUImpl;
-template <class Impl> class BaseO3DynInst;
-typedef BaseO3DynInst<O3CPUImpl> O3DynInst;
-class InOrderDynInst;
-
-class CheckerCPU;
-class AtomicSimpleCPU;
-class TimingSimpleCPU;
-class InorderCPU;
-namespace Minor
-{
- class ExecContext;
-};
+class ExecContext;
class SymbolTable;
@@ -267,11 +255,25 @@ class StaticInst : public RefCounted, public StaticInstFlags
public:
virtual ~StaticInst();
-/**
- * The execute() signatures are auto-generated by scons based on the
- * set of CPU models we are compiling in today.
- */
-#include "cpu/static_inst_exec_sigs.hh"
+ virtual Fault execute(ExecContext *xc,
+ Trace::InstRecord *traceData) const = 0;
+ virtual Fault eaComp(ExecContext *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("eaComp not defined!");
+ }
+
+ virtual Fault initiateAcc(ExecContext *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("initiateAcc not defined!");
+ }
+
+ virtual Fault completeAcc(Packet *pkt, ExecContext *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("completeAcc not defined!");
+ }
virtual void advancePC(TheISA::PCState &pcState) const = 0;