branch.isa revision 2100
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 branches (PC-relative control transfers),
65     * conditional or unconditional.
66     */
67    class BranchLikely : public PCDependentDisassembly
68    {
69      protected:
70        /// target address (signed) Displacement .
71        int32_t targetOffset;
72
73        /// Constructor.
74        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
75            : PCDependentDisassembly(mnem, _machInst, __opClass),
76              targetOffset(OFFSET << 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 Mips ISA, these are always unconditional.
89     */
90    class Jump : public PCDependentDisassembly
91    {
92      protected:
93
94        /// Displacement to target address (signed).
95        int32_t disp;
96
97      public:
98        /// Constructor
99        Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
100            : PCDependentDisassembly(mnem, _machInst, __opClass),
101              disp(OFFSET)
102        {
103        }
104
105        Addr branchTarget(ExecContext *xc) const;
106
107        std::string
108        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
109    };
110}};
111
112output decoder {{
113    Addr
114    Branch::branchTarget(Addr branchPC) const
115    {
116        return branchPC + 4 + disp;
117    }
118
119    Addr
120    Jump::branchTarget(ExecContext *xc) const
121    {
122        Addr NPC = xc->readPC() + 4;
123        uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
124        return (Rb & ~3) | (NPC & 1);
125    }
126
127    const std::string &
128    PCDependentDisassembly::disassemble(Addr pc,
129                                        const SymbolTable *symtab) const
130    {
131        if (!cachedDisassembly ||
132            pc != cachedPC || symtab != cachedSymtab)
133        {
134            if (cachedDisassembly)
135                delete cachedDisassembly;
136
137            cachedDisassembly =
138                new std::string(generateDisassembly(pc, symtab));
139            cachedPC = pc;
140            cachedSymtab = symtab;
141        }
142
143        return *cachedDisassembly;
144    }
145
146    std::string
147    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
148    {
149        std::stringstream ss;
150
151        ccprintf(ss, "%-10s ", mnemonic);
152
153        // There's only one register arg (RA), but it could be
154        // either a source (the condition for conditional
155        // branches) or a destination (the link reg for
156        // unconditional branches)
157        if (_numSrcRegs > 0) {
158            printReg(ss, _srcRegIdx[0]);
159            ss << ",";
160        }
161        else if (_numDestRegs > 0) {
162            printReg(ss, _destRegIdx[0]);
163            ss << ",";
164        }
165
166#ifdef SS_COMPATIBLE_DISASSEMBLY
167        if (_numSrcRegs == 0 && _numDestRegs == 0) {
168            printReg(ss, 31);
169            ss << ",";
170        }
171#endif
172
173        Addr target = pc + 4 + disp;
174
175        std::string str;
176        if (symtab && symtab->findSymbol(target, str))
177            ss << str;
178        else
179            ccprintf(ss, "0x%x", target);
180
181        return ss.str();
182    }
183
184    std::string
185    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
186    {
187        std::stringstream ss;
188
189        ccprintf(ss, "%-10s ", mnemonic);
190
191#ifdef SS_COMPATIBLE_DISASSEMBLY
192        if (_numDestRegs == 0) {
193            printReg(ss, 31);
194            ss << ",";
195        }
196#endif
197
198        if (_numDestRegs > 0) {
199            printReg(ss, _destRegIdx[0]);
200            ss << ",";
201        }
202
203        ccprintf(ss, "(r%d)", RB);
204
205        return ss.str();
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) {{
216    code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n';
217    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
218                        ('IsDirectControl', 'IsCondControl'))
219    header_output = BasicDeclare.subst(iop)
220    decoder_output = BasicConstructor.subst(iop)
221    decode_block = BasicDecode.subst(iop)
222    exec_output = BasicExecute.subst(iop)
223}};
224
225
226def format BranchLikely(code) {{
227    code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n';
228    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
229                        ('IsDirectControl', 'IsCondControl'))
230    header_output = BasicDeclare.subst(iop)
231    decoder_output = BasicConstructor.subst(iop)
232    decode_block = BasicDecode.subst(iop)
233    exec_output = BasicExecute.subst(iop)
234}};
235
236
237def format UncondBranch(*flags) {{
238    flags += ('IsUncondControl', 'IsDirectControl')
239    (header_output, decoder_output, decode_block, exec_output) = \
240        UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
241}};
242
243def format Jump(*flags) {{
244    flags += ('IsUncondControl', 'IsIndirectControl')
245    (header_output, decoder_output, decode_block, exec_output) = \
246        UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
247}};
248
249
250