branch.isa revision 7720:65d338a8dba4
1// -*- mode:c++ -*-
2
3// Copyright (c) 2007 MIPS Technologies, Inc.
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: Korey Sewell
30
31////////////////////////////////////////////////////////////////////
32//
33// Control transfer instructions
34//
35
36output header {{
37
38#include <iostream>
39    using namespace std;
40
41    /**
42     * Base class for instructions whose disassembly is not purely a
43     * function of the machine instruction (i.e., it depends on the
44     * PC).  This class overrides the disassemble() method to check
45     * the PC and symbol table values before re-using a cached
46     * disassembly string.  This is necessary for branches and jumps,
47     * where the disassembly string includes the target address (which
48     * may depend on the PC and/or symbol table).
49     */
50    class PCDependentDisassembly : public MipsStaticInst
51    {
52      protected:
53        /// Cached program counter from last disassembly
54        mutable Addr cachedPC;
55
56        /// Cached symbol table pointer from last disassembly
57        mutable const SymbolTable *cachedSymtab;
58
59        /// Constructor
60        PCDependentDisassembly(const char *mnem, MachInst _machInst,
61                               OpClass __opClass)
62            : MipsStaticInst(mnem, _machInst, __opClass),
63              cachedPC(0), cachedSymtab(0)
64        {
65        }
66
67        const std::string &
68        disassemble(Addr pc, const SymbolTable *symtab) const;
69    };
70
71    /**
72     * Base class for branches (PC-relative control transfers),
73     * conditional or unconditional.
74     */
75    class Branch : public PCDependentDisassembly
76    {
77      protected:
78        /// target address (signed) Displacement .
79        int32_t disp;
80
81        /// Constructor.
82        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
83            : PCDependentDisassembly(mnem, _machInst, __opClass),
84              disp(OFFSET << 2)
85        {
86            //If Bit 17 is 1 then Sign Extend
87            if ( (disp & 0x00020000) > 0  ) {
88                disp |= 0xFFFE0000;
89            }
90        }
91
92        MipsISA::PCState branchTarget(const MipsISA::PCState &branchPC) const;
93
94        std::string
95        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
96    };
97
98    /**
99     * Base class for jumps (register-indirect control transfers).  In
100     * the Mips ISA, these are always unconditional.
101     */
102    class Jump : public PCDependentDisassembly
103    {
104      protected:
105
106        /// Displacement to target address (signed).
107        int32_t disp;
108
109        uint32_t target;
110
111      public:
112        /// Constructor
113        Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
114            : PCDependentDisassembly(mnem, _machInst, __opClass),
115              disp(JMPTARG << 2)
116        {
117        }
118
119        MipsISA::PCState branchTarget(ThreadContext *tc) const;
120
121        std::string
122        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
123    };
124}};
125
126output decoder {{
127    MipsISA::PCState
128    Branch::branchTarget(const MipsISA::PCState &branchPC) const
129    {
130        MipsISA::PCState target = branchPC;
131        target.advance();
132        target.npc(branchPC.pc() + sizeof(MachInst) + disp);
133        target.nnpc(target.npc() + sizeof(MachInst));
134        return target;
135    }
136
137    MipsISA::PCState
138    Jump::branchTarget(ThreadContext *tc) const
139    {
140        MipsISA::PCState target = tc->pcState();
141        Addr pc = target.pc();
142        target.advance();
143        target.npc((pc & 0xF0000000) | disp);
144        target.nnpc(target.npc() + sizeof(MachInst));
145        return target;
146    }
147
148    const std::string &
149    PCDependentDisassembly::disassemble(Addr pc,
150                                        const SymbolTable *symtab) const
151    {
152        if (!cachedDisassembly ||
153            pc != cachedPC || symtab != cachedSymtab)
154        {
155            if (cachedDisassembly)
156                delete cachedDisassembly;
157
158            cachedDisassembly =
159                new std::string(generateDisassembly(pc, symtab));
160            cachedPC = pc;
161            cachedSymtab = symtab;
162        }
163
164        return *cachedDisassembly;
165    }
166
167    std::string
168    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
169    {
170        std::stringstream ss;
171
172        ccprintf(ss, "%-10s ", mnemonic);
173
174        // There's only one register arg (RA), but it could be
175        // either a source (the condition for conditional
176        // branches) or a destination (the link reg for
177        // unconditional branches)
178        if (_numSrcRegs == 1) {
179            printReg(ss, _srcRegIdx[0]);
180            ss << ", ";
181        } else if(_numSrcRegs == 2) {
182            printReg(ss, _srcRegIdx[0]);
183            ss << ", ";
184            printReg(ss, _srcRegIdx[1]);
185            ss << ", ";
186        }
187
188        Addr target = pc + 4 + disp;
189
190        std::string str;
191        if (symtab && symtab->findSymbol(target, str))
192            ss << str;
193        else
194            ccprintf(ss, "0x%x", target);
195
196        return ss.str();
197    }
198
199    std::string
200    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
201    {
202        std::stringstream ss;
203
204        ccprintf(ss, "%-10s ", mnemonic);
205
206        if ( strcmp(mnemonic,"jal") == 0 ) {
207            Addr npc = pc + 4;
208            ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp);
209        } else if (_numSrcRegs == 0) {
210            std::string str;
211            if (symtab && symtab->findSymbol(disp, str))
212                ss << str;
213            else
214                ccprintf(ss, "0x%x", disp);
215        } else if (_numSrcRegs == 1) {
216             printReg(ss, _srcRegIdx[0]);
217        } else if(_numSrcRegs == 2) {
218            printReg(ss, _srcRegIdx[0]);
219            ss << ", ";
220            printReg(ss, _srcRegIdx[1]);
221        }
222
223        return ss.str();
224    }
225}};
226
227def format Branch(code, *opt_flags) {{
228    not_taken_code = ''
229
230    #Build Instruction Flags
231    #Use Link & Likely Flags to Add Link/Condition Code
232    inst_flags = ('IsDirectControl', )
233    for x in opt_flags:
234        if x == 'Link':
235            code += 'R31 = pc.nnpc();\n'
236        elif x == 'Likely':
237            not_taken_code = 'pc.advance();'
238            inst_flags += ('IsCondDelaySlot', )
239        else:
240            inst_flags += (x, )
241
242    #Take into account uncond. branch instruction
243    if 'cond = 1' in code:
244         inst_flags += ('IsUncondControl', )
245    else:
246         inst_flags += ('IsCondControl', )
247
248    #Condition code
249    code = '''
250    bool cond;
251    MipsISA::PCState pc = PCS;
252    %(code)s
253    if (cond) {
254        pc.nnpc(pc.npc() + disp);
255    } else {
256        %(not_taken_code)s
257    }
258    PCS = pc;
259    ''' % { "code" : code, "not_taken_code" : not_taken_code }
260
261    iop = InstObjParams(name, Name, 'Branch', code, inst_flags)
262    header_output = BasicDeclare.subst(iop)
263    decoder_output = BasicConstructor.subst(iop)
264    decode_block = BasicDecode.subst(iop)
265    exec_output = BasicExecute.subst(iop)
266}};
267
268def format DspBranch(code, *opt_flags) {{
269    not_taken_code = ''
270
271    #Build Instruction Flags
272    #Use Link & Likely Flags to Add Link/Condition Code
273    inst_flags = ('IsDirectControl', )
274    for x in opt_flags:
275        if x == 'Link':
276            code += 'R32 = pc.nnpc();'
277        elif x == 'Likely':
278            not_taken_code = 'pc.advance();'
279            inst_flags += ('IsCondDelaySlot', )
280        else:
281            inst_flags += (x, )
282
283    #Take into account uncond. branch instruction
284    if 'cond = 1' in code:
285         inst_flags += ('IsUncondControl', )
286    else:
287         inst_flags += ('IsCondControl', )
288
289    #Condition code
290    code = '''
291    MipsISA::PCState pc = PCS;
292    bool cond;
293    uint32_t dspctl = DSPControl;
294    %(code)s
295    if (cond) {
296        pc.nnpc(pc.npc() + disp);
297    } else {
298        %(not_taken_code)s
299    }
300    PCS = pc;
301    ''' % { "code" : code, "not_taken_code" : not_taken_code }
302
303    iop = InstObjParams(name, Name, 'Branch', code, inst_flags)
304    header_output = BasicDeclare.subst(iop)
305    decoder_output = BasicConstructor.subst(iop)
306    decode_block = BasicDecode.subst(iop)
307    exec_output = BasicExecute.subst(iop)
308}};
309
310def format Jump(code, *opt_flags) {{
311    #Build Instruction Flags
312    #Use Link Flag to Add Link Code
313    inst_flags = ('IsIndirectControl', 'IsUncondControl')
314    for x in opt_flags:
315        if x == 'Link':
316            code = '''
317            R31 = pc.nnpc();
318            ''' + code
319        elif x == 'ClearHazards':
320            code += '/* Code Needed to Clear Execute & Inst Hazards */\n'
321        else:
322            inst_flags += (x, )
323
324    code = '''
325    MipsISA::PCState pc = PCS;
326    ''' + code
327
328    iop = InstObjParams(name, Name, 'Jump', code, inst_flags)
329    header_output = BasicDeclare.subst(iop)
330    decoder_output = BasicConstructor.subst(iop)
331    decode_block = BasicDecode.subst(iop)
332    exec_output = BasicExecute.subst(iop)
333}};
334
335
336
337
338