branch.isa revision 2649:2fb859a457a2
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////////////////////////////////////////////////////////////////////
30//
31// Control transfer instructions
32//
33
34output header {{
35
36    /**
37     * Base class for instructions whose disassembly is not purely a
38     * function of the machine instruction (i.e., it depends on the
39     * PC).  This class overrides the disassemble() method to check
40     * the PC and symbol table values before re-using a cached
41     * disassembly string.  This is necessary for branches and jumps,
42     * where the disassembly string includes the target address (which
43     * may depend on the PC and/or symbol table).
44     */
45    class PCDependentDisassembly : public AlphaStaticInst
46    {
47      protected:
48        /// Cached program counter from last disassembly
49        mutable Addr cachedPC;
50        /// Cached symbol table pointer from last disassembly
51        mutable const SymbolTable *cachedSymtab;
52
53        /// Constructor
54        PCDependentDisassembly(const char *mnem, ExtMachInst _machInst,
55                               OpClass __opClass)
56            : AlphaStaticInst(mnem, _machInst, __opClass),
57              cachedPC(0), cachedSymtab(0)
58        {
59        }
60
61        const std::string &
62        disassemble(Addr pc, const SymbolTable *symtab) const;
63    };
64
65    /**
66     * Base class for branches (PC-relative control transfers),
67     * conditional or unconditional.
68     */
69    class Branch : public PCDependentDisassembly
70    {
71      protected:
72        /// Displacement to target address (signed).
73        int32_t disp;
74
75        /// Constructor.
76        Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
77            : PCDependentDisassembly(mnem, _machInst, __opClass),
78              disp(BRDISP << 2)
79        {
80        }
81
82        Addr branchTarget(Addr branchPC) const;
83
84        std::string
85        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
86    };
87
88    /**
89     * Base class for jumps (register-indirect control transfers).  In
90     * the Alpha ISA, these are always unconditional.
91     */
92    class Jump : public PCDependentDisassembly
93    {
94      protected:
95
96        /// Displacement to target address (signed).
97        int32_t disp;
98
99      public:
100        /// Constructor
101        Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
102            : PCDependentDisassembly(mnem, _machInst, __opClass),
103              disp(BRDISP)
104        {
105        }
106
107        Addr branchTarget(ExecContext *xc) const;
108
109        std::string
110        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
111    };
112}};
113
114output decoder {{
115    Addr
116    Branch::branchTarget(Addr branchPC) const
117    {
118        return branchPC + 4 + disp;
119    }
120
121    Addr
122    Jump::branchTarget(ExecContext *xc) const
123    {
124        Addr NPC = xc->readPC() + 4;
125        uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
126        return (Rb & ~3) | (NPC & 1);
127    }
128
129    const std::string &
130    PCDependentDisassembly::disassemble(Addr pc,
131                                        const SymbolTable *symtab) const
132    {
133        if (!cachedDisassembly ||
134            pc != cachedPC || symtab != cachedSymtab)
135        {
136            if (cachedDisassembly)
137                delete cachedDisassembly;
138
139            cachedDisassembly =
140                new std::string(generateDisassembly(pc, symtab));
141            cachedPC = pc;
142            cachedSymtab = symtab;
143        }
144
145        return *cachedDisassembly;
146    }
147
148    std::string
149    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
150    {
151        std::stringstream ss;
152
153        ccprintf(ss, "%-10s ", mnemonic);
154
155        // There's only one register arg (RA), but it could be
156        // either a source (the condition for conditional
157        // branches) or a destination (the link reg for
158        // unconditional branches)
159        if (_numSrcRegs > 0) {
160            printReg(ss, _srcRegIdx[0]);
161            ss << ",";
162        }
163        else if (_numDestRegs > 0) {
164            printReg(ss, _destRegIdx[0]);
165            ss << ",";
166        }
167
168#ifdef SS_COMPATIBLE_DISASSEMBLY
169        if (_numSrcRegs == 0 && _numDestRegs == 0) {
170            printReg(ss, 31);
171            ss << ",";
172        }
173#endif
174
175        Addr target = pc + 4 + disp;
176
177        std::string str;
178        if (symtab && symtab->findSymbol(target, str))
179            ss << str;
180        else
181            ccprintf(ss, "0x%x", target);
182
183        return ss.str();
184    }
185
186    std::string
187    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
188    {
189        std::stringstream ss;
190
191        ccprintf(ss, "%-10s ", mnemonic);
192
193#ifdef SS_COMPATIBLE_DISASSEMBLY
194        if (_numDestRegs == 0) {
195            printReg(ss, 31);
196            ss << ",";
197        }
198#endif
199
200        if (_numDestRegs > 0) {
201            printReg(ss, _destRegIdx[0]);
202            ss << ",";
203        }
204
205        ccprintf(ss, "(r%d)", RB);
206
207        return ss.str();
208    }
209}};
210
211def template JumpOrBranchDecode {{
212    return (RA == 31)
213        ? (StaticInst *)new %(class_name)s(machInst)
214        : (StaticInst *)new %(class_name)sAndLink(machInst);
215}};
216
217def format CondBranch(code) {{
218    code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n';
219    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
220                        ('IsDirectControl', 'IsCondControl'))
221    header_output = BasicDeclare.subst(iop)
222    decoder_output = BasicConstructor.subst(iop)
223    decode_block = BasicDecode.subst(iop)
224    exec_output = BasicExecute.subst(iop)
225}};
226
227let {{
228def UncondCtrlBase(name, Name, base_class, npc_expr, flags):
229    # Declare basic control transfer w/o link (i.e. link reg is R31)
230    nolink_code = 'NPC = %s;\n' % npc_expr
231    nolink_iop = InstObjParams(name, Name, base_class,
232                               CodeBlock(nolink_code), flags)
233    header_output = BasicDeclare.subst(nolink_iop)
234    decoder_output = BasicConstructor.subst(nolink_iop)
235    exec_output = BasicExecute.subst(nolink_iop)
236
237    # Generate declaration of '*AndLink' version, append to decls
238    link_code = 'Ra = NPC & ~3;\n' + nolink_code
239    link_iop = InstObjParams(name, Name + 'AndLink', base_class,
240                             CodeBlock(link_code), flags)
241    header_output += BasicDeclare.subst(link_iop)
242    decoder_output += BasicConstructor.subst(link_iop)
243    exec_output += BasicExecute.subst(link_iop)
244
245    # need to use link_iop for the decode template since it is expecting
246    # the shorter version of class_name (w/o "AndLink")
247
248    return (header_output, decoder_output,
249            JumpOrBranchDecode.subst(nolink_iop), exec_output)
250}};
251
252def format UncondBranch(*flags) {{
253    flags += ('IsUncondControl', 'IsDirectControl')
254    (header_output, decoder_output, decode_block, exec_output) = \
255        UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
256}};
257
258def format Jump(*flags) {{
259    flags += ('IsUncondControl', 'IsIndirectControl')
260    (header_output, decoder_output, decode_block, exec_output) = \
261        UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
262}};
263
264
265