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