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