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(
93                const MipsISA::PCState &branchPC) const override;
94
95        /// Explicitly import the otherwise hidden branchTarget
96        using StaticInst::branchTarget;
97
98        std::string generateDisassembly(
99                Addr pc, const SymbolTable *symtab) const override;
100    };
101
102    /**
103     * Base class for jumps (register-indirect control transfers).  In
104     * the Mips ISA, these are always unconditional.
105     */
106    class Jump : public PCDependentDisassembly
107    {
108      protected:
109
110        /// Displacement to target address (signed).
111        int32_t disp;
112
113        uint32_t target;
114
115      public:
116        /// Constructor
117        Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
118            : PCDependentDisassembly(mnem, _machInst, __opClass),
119              disp(JMPTARG << 2)
120        {
121        }
122
123        MipsISA::PCState branchTarget(ThreadContext *tc) const override;
124
125        /// Explicitly import the otherwise hidden branchTarget
126        using StaticInst::branchTarget;
127
128        std::string generateDisassembly(
129                Addr pc, const SymbolTable *symtab) const override;
130    };
131}};
132
133output decoder {{
134    MipsISA::PCState
135    Branch::branchTarget(const MipsISA::PCState &branchPC) const
136    {
137        MipsISA::PCState target = branchPC;
138        target.advance();
139        target.npc(branchPC.pc() + sizeof(MachInst) + disp);
140        target.nnpc(target.npc() + sizeof(MachInst));
141        return target;
142    }
143
144    MipsISA::PCState
145    Jump::branchTarget(ThreadContext *tc) const
146    {
147        MipsISA::PCState target = tc->pcState();
148        Addr pc = target.pc();
149        target.advance();
150        target.npc((pc & 0xF0000000) | disp);
151        target.nnpc(target.npc() + sizeof(MachInst));
152        return target;
153    }
154
155    const std::string &
156    PCDependentDisassembly::disassemble(Addr pc,
157                                        const SymbolTable *symtab) const
158    {
159        if (!cachedDisassembly ||
160            pc != cachedPC || symtab != cachedSymtab)
161        {
162            if (cachedDisassembly)
163                delete cachedDisassembly;
164
165            cachedDisassembly =
166                new std::string(generateDisassembly(pc, symtab));
167            cachedPC = pc;
168            cachedSymtab = symtab;
169        }
170
171        return *cachedDisassembly;
172    }
173
174    std::string
175    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
176    {
177        std::stringstream ss;
178
179        ccprintf(ss, "%-10s ", mnemonic);
180
181        // There's only one register arg (RA), but it could be
182        // either a source (the condition for conditional
183        // branches) or a destination (the link reg for
184        // unconditional branches)
185        if (_numSrcRegs == 1) {
186            printReg(ss, _srcRegIdx[0]);
187            ss << ", ";
188        } else if(_numSrcRegs == 2) {
189            printReg(ss, _srcRegIdx[0]);
190            ss << ", ";
191            printReg(ss, _srcRegIdx[1]);
192            ss << ", ";
193        }
194
195        Addr target = pc + 4 + disp;
196
197        std::string str;
198        if (symtab && symtab->findSymbol(target, str))
199            ss << str;
200        else
201            ccprintf(ss, "0x%x", target);
202
203        return ss.str();
204    }
205
206    std::string
207    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
208    {
209        std::stringstream ss;
210
211        ccprintf(ss, "%-10s ", mnemonic);
212
213        if ( strcmp(mnemonic,"jal") == 0 ) {
214            Addr npc = pc + 4;
215            ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp);
216        } else if (_numSrcRegs == 0) {
217            std::string str;
218            if (symtab && symtab->findSymbol(disp, str))
219                ss << str;
220            else
221                ccprintf(ss, "0x%x", disp);
222        } else if (_numSrcRegs == 1) {
223             printReg(ss, _srcRegIdx[0]);
224        } else if(_numSrcRegs == 2) {
225            printReg(ss, _srcRegIdx[0]);
226            ss << ", ";
227            printReg(ss, _srcRegIdx[1]);
228        }
229
230        return ss.str();
231    }
232}};
233
234def format Branch(code, *opt_flags) {{
235    not_taken_code = 'NNPC = NNPC; NPC = NPC;'
236
237    #Build Instruction Flags
238    #Use Link & Likely Flags to Add Link/Condition Code
239    inst_flags = ('IsDirectControl', )
240    for x in opt_flags:
241        if x == 'Link':
242            code += 'R31 = NNPC;\n'
243        elif x == 'Likely':
244            not_taken_code = 'NNPC = NPC; NPC = PC;'
245            inst_flags += ('IsCondDelaySlot', )
246        else:
247            inst_flags += (x, )
248
249    #Take into account uncond. branch instruction
250    if 'cond = 1' in code:
251         inst_flags += ('IsUncondControl', )
252    else:
253         inst_flags += ('IsCondControl', )
254
255    #Condition code
256    code = '''
257    bool cond;
258    %(code)s
259    if (cond) {
260        NNPC = NPC + disp;
261    } else {
262        %(not_taken_code)s
263    }
264    ''' % { "code" : code, "not_taken_code" : not_taken_code }
265
266    iop = InstObjParams(name, Name, 'Branch', code, inst_flags)
267    header_output = BasicDeclare.subst(iop)
268    decoder_output = BasicConstructor.subst(iop)
269    decode_block = BasicDecode.subst(iop)
270    exec_output = BasicExecute.subst(iop)
271}};
272
273def format DspBranch(code, *opt_flags) {{
274    not_taken_code = 'NNPC = NNPC; NPC = NPC;'
275
276    #Build Instruction Flags
277    #Use Link & Likely Flags to Add Link/Condition Code
278    inst_flags = ('IsDirectControl', )
279    for x in opt_flags:
280        if x == 'Link':
281            code += 'R32 = NNPC;'
282        elif x == 'Likely':
283            not_taken_code = 'NNPC = NPC, NPC = PC;'
284            inst_flags += ('IsCondDelaySlot', )
285        else:
286            inst_flags += (x, )
287
288    #Take into account uncond. branch instruction
289    if 'cond = 1' in code:
290         inst_flags += ('IsUncondControl', )
291    else:
292         inst_flags += ('IsCondControl', )
293
294    #Condition code
295    code = '''
296    bool cond;
297    uint32_t dspctl = DSPControl;
298    %(code)s
299    if (cond) {
300        NNPC = NPC + disp;
301    } else {
302        %(not_taken_code)s
303    }
304    ''' % { "code" : code, "not_taken_code" : not_taken_code }
305
306    iop = InstObjParams(name, Name, 'Branch', code, inst_flags)
307    header_output = BasicDeclare.subst(iop)
308    decoder_output = BasicConstructor.subst(iop)
309    decode_block = BasicDecode.subst(iop)
310    exec_output = BasicExecute.subst(iop)
311}};
312
313def format Jump(code, *opt_flags) {{
314    #Build Instruction Flags
315    #Use Link Flag to Add Link Code
316    inst_flags = ('IsIndirectControl', 'IsUncondControl')
317    for x in opt_flags:
318        if x == 'Link':
319            code = '''
320            R31 = NNPC;
321            ''' + code
322        elif x == 'ClearHazards':
323            code += '/* Code Needed to Clear Execute & Inst Hazards */\n'
324        else:
325            inst_flags += (x, )
326
327    iop = InstObjParams(name, Name, 'Jump', code, inst_flags)
328    header_output = BasicDeclare.subst(iop)
329    decoder_output = BasicConstructor.subst(iop)
330    decode_block = BasicDecode.subst(iop)
331    exec_output = BasicExecute.subst(iop)
332}};
333
334
335
336
337