| // -*- 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') |
| }}; |