1// -*- mode:c++ -*-
2
3// Copyright (c) 2003-2005 The Regents of The University of Michigan
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met: redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer;
10// redistributions in binary form must reproduce the above copyright
11// notice, this list of conditions and the following disclaimer in the
12// documentation and/or other materials provided with the distribution;
13// neither the name of the copyright holders nor the names of its
14// contributors may be used to endorse or promote products derived from
15// this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29// Authors: Steve Reinhardt
30
31////////////////////////////////////////////////////////////////////
32//
33// Control transfer instructions
34//
35
36output header {{
37
38    /**
39     * Base class for instructions whose disassembly is not purely a
40     * function of the machine instruction (i.e., it depends on the
41     * PC).  This class overrides the disassemble() method to check
42     * the PC and symbol table values before re-using a cached
43     * disassembly string.  This is necessary for branches and jumps,
44     * where the disassembly string includes the target address (which
45     * may depend on the PC and/or symbol table).
46     */
47    class PCDependentDisassembly : public AlphaStaticInst
48    {
49      protected:
50        /// Cached program counter from last disassembly
51        mutable Addr cachedPC;
52        /// Cached symbol table pointer from last disassembly
53        mutable const SymbolTable *cachedSymtab;
54
55        /// Constructor
56        PCDependentDisassembly(const char *mnem, ExtMachInst _machInst,
57                               OpClass __opClass)
58            : AlphaStaticInst(mnem, _machInst, __opClass),
59              cachedPC(0), cachedSymtab(0)
60        {
61        }
62
63        const std::string &
64        disassemble(Addr pc, const SymbolTable *symtab) const;
65    };
66
67    /**
68     * Base class for branches (PC-relative control transfers),
69     * conditional or unconditional.
70     */
71    class Branch : public PCDependentDisassembly
72    {
73      protected:
74        /// Displacement to target address (signed).
75        int32_t disp;
76
77        /// Constructor.
78        Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
79            : PCDependentDisassembly(mnem, _machInst, __opClass),
80              disp(BRDISP << 2)
81        {
82        }
83
84        AlphaISA::PCState branchTarget(
85                const AlphaISA::PCState &branchPC) const override;
86
87        /// Explicitly import the otherwise hidden branchTarget
88        using StaticInst::branchTarget;
89
90        std::string generateDisassembly(
91                Addr pc, const SymbolTable *symtab) const override;
92    };
93
94    /**
95     * Base class for jumps (register-indirect control transfers).  In
96     * the Alpha ISA, these are always unconditional.
97     */
98    class Jump : public PCDependentDisassembly
99    {
100      protected:
101
102        /// Displacement to target address (signed).
103        int32_t disp;
104
105      public:
106        /// Constructor
107        Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
108            : PCDependentDisassembly(mnem, _machInst, __opClass),
109              disp(BRDISP)
110        {
111        }
112
113        AlphaISA::PCState branchTarget(ThreadContext *tc) const override;
114
115        /// Explicitly import the otherwise hidden branchTarget
116        using StaticInst::branchTarget;
117
118        std::string generateDisassembly(
119                Addr pc, const SymbolTable *symtab) const override;
120    };
121}};
122
123output decoder {{
124    AlphaISA::PCState
125    Branch::branchTarget(const AlphaISA::PCState &branchPC) const
126    {
127        return branchPC.pc() + 4 + disp;
128    }
129
130    AlphaISA::PCState
131    Jump::branchTarget(ThreadContext *tc) const
132    {
133        PCState pc = tc->pcState();
134        uint64_t Rb = tc->readIntReg(_srcRegIdx[0].index());
135        pc.set((Rb & ~3) | (pc.pc() & 1));
136        return pc;
137    }
138
139    const std::string &
140    PCDependentDisassembly::disassemble(Addr pc,
141                                        const SymbolTable *symtab) const
142    {
143        if (!cachedDisassembly ||
144            pc != cachedPC || symtab != cachedSymtab)
145        {
146            if (cachedDisassembly)
147                delete cachedDisassembly;
148
149            cachedDisassembly =
150                new std::string(generateDisassembly(pc, symtab));
151            cachedPC = pc;
152            cachedSymtab = symtab;
153        }
154
155        return *cachedDisassembly;
156    }
157
158    std::string
159    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
160    {
161        std::stringstream ss;
162
163        ccprintf(ss, "%-10s ", mnemonic);
164
165        // There's only one register arg (RA), but it could be
166        // either a source (the condition for conditional
167        // branches) or a destination (the link reg for
168        // unconditional branches)
169        if (_numSrcRegs > 0) {
170            printReg(ss, _srcRegIdx[0]);
171            ss << ",";
172        }
173        else if (_numDestRegs > 0) {
174            printReg(ss, _destRegIdx[0]);
175            ss << ",";
176        }
177
178#ifdef SS_COMPATIBLE_DISASSEMBLY
179        if (_numSrcRegs == 0 && _numDestRegs == 0) {
180            printReg(ss, 31);
181            ss << ",";
182        }
183#endif
184
185        Addr target = pc + 4 + disp;
186
187        std::string str;
188        if (symtab && symtab->findSymbol(target, str))
189            ss << str;
190        else
191            ccprintf(ss, "0x%x", target);
192
193        return ss.str();
194    }
195
196    std::string
197    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
198    {
199        std::stringstream ss;
200
201        ccprintf(ss, "%-10s ", mnemonic);
202
203#ifdef SS_COMPATIBLE_DISASSEMBLY
204        if (_numDestRegs == 0) {
205            printReg(ss, 31);
206            ss << ",";
207        }
208#endif
209
210        if (_numDestRegs > 0) {
211            printReg(ss, _destRegIdx[0]);
212            ss << ",";
213        }
214
215        ccprintf(ss, "(r%d)", RB);
216
217        return ss.str();
218    }
219}};
220
221def template JumpOrBranchDecode {{
222    return (RA == 31)
223        ? (StaticInst *)new %(class_name)s(machInst)
224        : (StaticInst *)new %(class_name)sAndLink(machInst);
225}};
226
227def format CondBranch(code) {{
228    code = '''
229        bool cond;
230        %(code)s;
231        if (cond)
232            NPC = NPC + disp;
233        else
234            NPC = NPC;
235    ''' % { "code" : code }
236    iop = InstObjParams(name, Name, 'Branch', code,
237                        ('IsDirectControl', 'IsCondControl'))
238    header_output = BasicDeclare.subst(iop)
239    decoder_output = BasicConstructor.subst(iop)
240    decode_block = BasicDecode.subst(iop)
241    exec_output = BasicExecute.subst(iop)
242}};
243
244let {{
245def UncondCtrlBase(name, Name, base_class, npc_expr, flags):
246    # Declare basic control transfer w/o link (i.e. link reg is R31)
247    nolink_code = 'NPC = %s;\n' % npc_expr
248    nolink_iop = InstObjParams(name, Name, base_class,
249                               nolink_code, flags)
250    header_output = BasicDeclare.subst(nolink_iop)
251    decoder_output = BasicConstructor.subst(nolink_iop)
252    exec_output = BasicExecute.subst(nolink_iop)
253
254    # Generate declaration of '*AndLink' version, append to decls
255    link_code = 'Ra = NPC & ~3;\n' + nolink_code
256    link_iop = InstObjParams(name, Name + 'AndLink', base_class,
257                             link_code, flags)
258    header_output += BasicDeclare.subst(link_iop)
259    decoder_output += BasicConstructor.subst(link_iop)
260    exec_output += BasicExecute.subst(link_iop)
261
262    # need to use link_iop for the decode template since it is expecting
263    # the shorter version of class_name (w/o "AndLink")
264
265    return (header_output, decoder_output,
266            JumpOrBranchDecode.subst(nolink_iop), exec_output)
267}};
268
269def format UncondBranch(*flags) {{
270    flags += ('IsUncondControl', 'IsDirectControl')
271    (header_output, decoder_output, decode_block, exec_output) = \
272        UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
273}};
274
275def format Jump(*flags) {{
276    flags += ('IsUncondControl', 'IsIndirectControl')
277    (header_output, decoder_output, decode_block, exec_output) = \
278        UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
279}};
280
281
282