branch.isa revision 9552:460cf901acba
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(const AlphaISA::PCState &branchPC) const;
85
86        /// Explicitly import the otherwise hidden branchTarget
87        using StaticInst::branchTarget;
88
89        std::string
90        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
91    };
92
93    /**
94     * Base class for jumps (register-indirect control transfers).  In
95     * the Alpha ISA, these are always unconditional.
96     */
97    class Jump : public PCDependentDisassembly
98    {
99      protected:
100
101        /// Displacement to target address (signed).
102        int32_t disp;
103
104      public:
105        /// Constructor
106        Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
107            : PCDependentDisassembly(mnem, _machInst, __opClass),
108              disp(BRDISP)
109        {
110        }
111
112        AlphaISA::PCState branchTarget(ThreadContext *tc) const;
113
114        /// Explicitly import the otherwise hidden branchTarget
115        using StaticInst::branchTarget;
116
117        std::string
118        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
119    };
120}};
121
122output decoder {{
123    AlphaISA::PCState
124    Branch::branchTarget(const AlphaISA::PCState &branchPC) const
125    {
126        return branchPC.pc() + 4 + disp;
127    }
128
129    AlphaISA::PCState
130    Jump::branchTarget(ThreadContext *tc) const
131    {
132        PCState pc = tc->pcState();
133        uint64_t Rb = tc->readIntReg(_srcRegIdx[0]);
134        pc.set((Rb & ~3) | (pc.pc() & 1));
135        return pc;
136    }
137
138    const std::string &
139    PCDependentDisassembly::disassemble(Addr pc,
140                                        const SymbolTable *symtab) const
141    {
142        if (!cachedDisassembly ||
143            pc != cachedPC || symtab != cachedSymtab)
144        {
145            if (cachedDisassembly)
146                delete cachedDisassembly;
147
148            cachedDisassembly =
149                new std::string(generateDisassembly(pc, symtab));
150            cachedPC = pc;
151            cachedSymtab = symtab;
152        }
153
154        return *cachedDisassembly;
155    }
156
157    std::string
158    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
159    {
160        std::stringstream ss;
161
162        ccprintf(ss, "%-10s ", mnemonic);
163
164        // There's only one register arg (RA), but it could be
165        // either a source (the condition for conditional
166        // branches) or a destination (the link reg for
167        // unconditional branches)
168        if (_numSrcRegs > 0) {
169            printReg(ss, _srcRegIdx[0]);
170            ss << ",";
171        }
172        else if (_numDestRegs > 0) {
173            printReg(ss, _destRegIdx[0]);
174            ss << ",";
175        }
176
177#ifdef SS_COMPATIBLE_DISASSEMBLY
178        if (_numSrcRegs == 0 && _numDestRegs == 0) {
179            printReg(ss, 31);
180            ss << ",";
181        }
182#endif
183
184        Addr target = pc + 4 + disp;
185
186        std::string str;
187        if (symtab && symtab->findSymbol(target, str))
188            ss << str;
189        else
190            ccprintf(ss, "0x%x", target);
191
192        return ss.str();
193    }
194
195    std::string
196    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
197    {
198        std::stringstream ss;
199
200        ccprintf(ss, "%-10s ", mnemonic);
201
202#ifdef SS_COMPATIBLE_DISASSEMBLY
203        if (_numDestRegs == 0) {
204            printReg(ss, 31);
205            ss << ",";
206        }
207#endif
208
209        if (_numDestRegs > 0) {
210            printReg(ss, _destRegIdx[0]);
211            ss << ",";
212        }
213
214        ccprintf(ss, "(r%d)", RB);
215
216        return ss.str();
217    }
218}};
219
220def template JumpOrBranchDecode {{
221    return (RA == 31)
222        ? (StaticInst *)new %(class_name)s(machInst)
223        : (StaticInst *)new %(class_name)sAndLink(machInst);
224}};
225
226def format CondBranch(code) {{
227    code = '''
228        bool cond;
229        %(code)s;
230        if (cond)
231            NPC = NPC + disp;
232        else
233            NPC = NPC;
234    ''' % { "code" : code }
235    iop = InstObjParams(name, Name, 'Branch', code,
236                        ('IsDirectControl', 'IsCondControl'))
237    header_output = BasicDeclare.subst(iop)
238    decoder_output = BasicConstructor.subst(iop)
239    decode_block = BasicDecode.subst(iop)
240    exec_output = BasicExecute.subst(iop)
241}};
242
243let {{
244def UncondCtrlBase(name, Name, base_class, npc_expr, flags):
245    # Declare basic control transfer w/o link (i.e. link reg is R31)
246    nolink_code = 'NPC = %s;\n' % npc_expr
247    nolink_iop = InstObjParams(name, Name, base_class,
248                               nolink_code, flags)
249    header_output = BasicDeclare.subst(nolink_iop)
250    decoder_output = BasicConstructor.subst(nolink_iop)
251    exec_output = BasicExecute.subst(nolink_iop)
252
253    # Generate declaration of '*AndLink' version, append to decls
254    link_code = 'Ra = NPC & ~3;\n' + nolink_code
255    link_iop = InstObjParams(name, Name + 'AndLink', base_class,
256                             link_code, flags)
257    header_output += BasicDeclare.subst(link_iop)
258    decoder_output += BasicConstructor.subst(link_iop)
259    exec_output += BasicExecute.subst(link_iop)
260
261    # need to use link_iop for the decode template since it is expecting
262    # the shorter version of class_name (w/o "AndLink")
263
264    return (header_output, decoder_output,
265            JumpOrBranchDecode.subst(nolink_iop), exec_output)
266}};
267
268def format UncondBranch(*flags) {{
269    flags += ('IsUncondControl', 'IsDirectControl')
270    (header_output, decoder_output, decode_block, exec_output) = \
271        UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
272}};
273
274def format Jump(*flags) {{
275    flags += ('IsUncondControl', 'IsIndirectControl')
276    (header_output, decoder_output, decode_block, exec_output) = \
277        UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
278}};
279
280
281