blob: a58f0e4b25f0cc9977f7dd2727f5dc56058554b3 [file] [log] [blame]
// -*- mode:c++ -*-
// Copyright (c) 2009 The University of Edinburgh
// Copyright (c) 2021 IBM Corporation
// 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.
////////////////////////////////////////////////////////////////////
//
// Memory-format instructions
//
def template LoadStoreDeclare {{
/**
* Static instruction class for "%(mnemonic)s".
*/
class %(class_name)s : public %(base_class)s
{
private:
%(reg_idx_arr_decl)s;
public:
/// Constructor.
%(class_name)s(ExtMachInst machInst);
Fault execute(ExecContext *, trace::InstRecord *) const override;
Fault initiateAcc(ExecContext *, trace::InstRecord *) const override;
Fault completeAcc(PacketPtr, ExecContext *,
trace::InstRecord *) const override;
};
}};
def template LoadStoreConstructor {{
%(class_name)s::%(class_name)s(ExtMachInst machInst)
: %(base_class)s("%(mnemonic)s", machInst, %(op_class)s)
{
%(set_reg_idx_arr)s;
%(constructor)s;
}
}};
def template LoadExecute {{
Fault %(class_name)s::execute(ExecContext *xc,
trace::InstRecord *traceData) const
{
Addr EA;
Fault fault = NoFault;
Msr msr = xc->tcBase()->getReg(int_reg::Msr);
%(op_decl)s;
%(op_rd)s;
%(ea_code)s;
if (fault == NoFault) {
fault = msr.le ?
readMemAtomicLE(xc, traceData, EA, Mem, memAccessFlags) :
readMemAtomicBE(xc, traceData, EA, Mem, memAccessFlags);
%(memacc_code)s;
}
if (fault == NoFault) {
%(update_code)s;
%(op_wb)s;
}
return fault;
}
}};
def template LoadInitiateAcc {{
Fault %(class_name)s::initiateAcc(ExecContext *xc,
trace::InstRecord *traceData) const
{
Addr EA;
Fault fault = NoFault;
%(op_src_decl)s;
%(op_rd)s;
%(ea_code)s;
if (fault == NoFault) {
fault = initiateMemRead(xc, traceData, EA, Mem, memAccessFlags);
}
return fault;
}
}};
def template LoadCompleteAcc {{
Fault %(class_name)s::completeAcc(PacketPtr pkt,
ExecContext *xc,
trace::InstRecord *traceData) const
{
[[maybe_unused]] Addr EA;
Fault fault = NoFault;
Msr msr = xc->tcBase()->getReg(int_reg::Msr);
%(op_decl)s;
EA = pkt->req->getVaddr();
%(op_rd)s;
if (msr.le)
getMemLE(pkt, Mem, traceData);
else
getMemBE(pkt, Mem, traceData);
if (fault == NoFault) {
%(memacc_code)s;
}
if (fault == NoFault) {
%(update_code)s;
%(op_wb)s;
}
return fault;
}
}};
def template StoreExecute {{
Fault %(class_name)s::execute(ExecContext *xc,
trace::InstRecord *traceData) const
{
Addr EA;
Fault fault = NoFault;
Msr msr = xc->tcBase()->getReg(int_reg::Msr);
%(op_decl)s;
%(op_rd)s;
%(ea_code)s;
if (fault == NoFault) {
%(memacc_code)s;
}
if (fault == NoFault) {
fault = msr.le ?
writeMemAtomicLE(xc, traceData, Mem, EA, memAccessFlags,
NULL) :
writeMemAtomicBE(xc, traceData, Mem, EA, memAccessFlags,
NULL);
}
if (fault == NoFault) {
%(update_code)s;
%(op_wb)s;
}
return fault;
}
}};
def template StoreInitiateAcc {{
Fault %(class_name)s::initiateAcc(ExecContext *xc,
trace::InstRecord *traceData) const
{
Addr EA;
Fault fault = NoFault;
Msr msr = xc->tcBase()->getReg(int_reg::Msr);
%(op_decl)s;
%(op_rd)s;
%(ea_code)s;
if (fault == NoFault) {
%(memacc_code)s;
}
if (fault == NoFault) {
fault = msr.le ?
writeMemTimingLE(xc, traceData, Mem, EA, memAccessFlags,
NULL) :
writeMemTimingBE(xc, traceData, Mem, EA, memAccessFlags,
NULL);
}
return fault;
}
}};
def template StoreCompleteAcc {{
Fault %(class_name)s::completeAcc(PacketPtr pkt, ExecContext *xc,
trace::InstRecord *traceData) const
{
[[maybe_unused]] Addr EA;
Fault fault = NoFault;
%(op_decl)s;
EA = pkt->req->getVaddr();
%(op_rd)s;
// Need to write back any potential address register update
if (fault == NoFault) {
%(update_code)s;
%(op_wb)s;
}
return fault;
}
}};
// The generic memory operation generator. This is called when two versions
// of an instruction are needed - when Ra == 0 and otherwise. This is so
// that instructions can use the value 0 when Ra == 0 but avoid having a
// dependence on Ra.
let {{
def GenMemOp(name, Name, memacc_code, update_code, ea_code, ea_code_ra0, base,
load_or_store, mem_flags = [], inst_flags = []):
# First the version where Ra is non-zero
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code,
memacc_code, update_code,
mem_flags, inst_flags,
base_class = base,
decode_template = CheckRaDecode,
exec_template_base = load_or_store)
# Now another version where Ra == 0
(header_output_ra0, decoder_output_ra0, _, exec_output_ra0) = \
LoadStoreBase(name, Name + 'RaZero', ea_code_ra0,
memacc_code, update_code,
mem_flags, inst_flags,
base_class = base,
exec_template_base = load_or_store)
# Finally, add to the other outputs
header_output += header_output_ra0
decoder_output += decoder_output_ra0
exec_output += exec_output_ra0
return (header_output, decoder_output, decode_block, exec_output)
}};
def format LoadIndexOp(memacc_code, update_code = {{ }},
ea_code = {{ EA = Ra + Rb; }},
ea_code_ra0 = {{ EA = Rb; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
GenMemOp(name, Name, memacc_code, update_code, ea_code, ea_code_ra0,
'MemIndexOp', 'Load', mem_flags, inst_flags)
}};
def format StoreIndexOp(memacc_code, update_code = {{ }},
ea_code = {{ EA = Ra + Rb; }},
ea_code_ra0 = {{ EA = Rb; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
GenMemOp(name, Name, memacc_code, update_code, ea_code, ea_code_ra0,
'MemIndexOp', 'Store', mem_flags, inst_flags)
}};
def format LoadIndexUpdateOp(memacc_code, ea_code = {{ EA = Ra + Rb; }},
mem_flags = [], inst_flags = []) {{
# Add in the update code
update_code = 'Ra = EA;'
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, update_code,
mem_flags, inst_flags,
base_class = 'MemIndexOp',
decode_template = CheckRaRtDecode,
exec_template_base = 'Load')
}};
def format StoreIndexUpdateOp(memacc_code, ea_code = {{ EA = Ra + Rb; }},
mem_flags = [], inst_flags = []) {{
# Add in the update code
update_code = 'Ra = EA;'
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, update_code,
mem_flags, inst_flags,
base_class = 'MemIndexOp',
decode_template = CheckRaZeroDecode,
exec_template_base = 'Store')
}};
def format LoadDispOp(memacc_code, ea_code = {{ EA = Ra + d; }},
ea_code_ra0 = {{ EA = d; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
GenMemOp(name, Name, memacc_code, '', ea_code, ea_code_ra0,
'MemDispOp', 'Load', mem_flags, inst_flags)
}};
def format StoreDispOp(memacc_code, ea_code = {{ EA = Ra + d; }},
ea_code_ra0 = {{ EA = d; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
GenMemOp(name, Name, memacc_code, '', ea_code, ea_code_ra0,
'MemDispOp', 'Store', mem_flags, inst_flags)
}};
def format LoadDispShiftOp(memacc_code,
ea_code = {{ EA = Ra + (ds << 2); }},
ea_code_ra0 = {{ EA = (ds << 2); }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
GenMemOp(name, Name, memacc_code, '', ea_code, ea_code_ra0,
'MemDispShiftOp', 'Load', mem_flags, inst_flags)
}};
def format StoreDispShiftOp(memacc_code,
ea_code = {{ EA = Ra + (ds << 2); }},
ea_code_ra0 = {{ EA = (ds << 2); }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
GenMemOp(name, Name, memacc_code, '', ea_code, ea_code_ra0,
'MemDispShiftOp', 'Store', mem_flags, inst_flags)
}};
def format LoadDispUpdateOp(memacc_code, ea_code = {{ EA = Ra + d; }},
mem_flags = [], inst_flags = []) {{
# Add in the update code
update_code = 'Ra = EA;'
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, update_code,
mem_flags, inst_flags,
base_class = 'MemDispOp',
decode_template = CheckRaRtDecode,
exec_template_base = 'Load')
}};
def format StoreDispUpdateOp(memacc_code, ea_code = {{ EA = Ra + d; }},
mem_flags = [], inst_flags = []) {{
# Add in the update code
update_code = 'Ra = EA;'
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, update_code,
mem_flags, inst_flags,
base_class = 'MemDispOp',
decode_template = CheckRaZeroDecode,
exec_template_base = 'Store')
}};
def format LoadDispShiftUpdateOp(memacc_code,
ea_code = {{ EA = Ra + (ds << 2); }},
mem_flags = [], inst_flags = []) {{
# Add in the update code
update_code = 'Ra = EA;'
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, update_code,
mem_flags, inst_flags,
base_class = 'MemDispShiftOp',
decode_template = CheckRaRtDecode,
exec_template_base = 'Load')
}};
def format StoreDispShiftUpdateOp(memacc_code,
ea_code = {{ EA = Ra + (ds << 2); }},
mem_flags = [], inst_flags = []) {{
# Add in the update code
update_code = 'Ra = EA;'
# Generate the class
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, update_code,
mem_flags, inst_flags,
base_class = 'MemDispShiftOp',
decode_template = CheckRaZeroDecode,
exec_template_base = 'Store')
}};