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