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