static_inst.cc revision 6268
1/* Copyright (c) 2007-2008 The Florida State University
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met: redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer;
8 * redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution;
11 * neither the name of the copyright holders nor the names of its
12 * contributors may be used to endorse or promote products derived from
13 * this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * Authors: Stephen Hines
28 */
29
30#include "arch/arm/insts/static_inst.hh"
31#include "base/condcodes.hh"
32#include "base/loader/symtab.hh"
33
34namespace ArmISA
35{
36// Shift Rm by an immediate value
37int32_t
38ArmStaticInst::shift_rm_imm(uint32_t base, uint32_t shamt,
39                            uint32_t type, uint32_t cfval) const
40{
41    assert(shamt < 32);
42    ArmShiftType shiftType;
43    shiftType = (ArmShiftType)type;
44
45    switch (shiftType)
46    {
47      case LSL:
48        return base << shamt;
49      case LSR:
50        if (shamt == 0)
51            return 0;
52        else
53            return base >> shamt;
54      case ASR:
55        if (shamt == 0)
56            return (int32_t)base >> 31;
57        else
58            return (int32_t)base >> shamt;
59      case ROR:
60        if (shamt == 0)
61            return (cfval << 31) | (base >> 1); // RRX
62        else
63            return (base << (32 - shamt)) | (base >> shamt);
64      default:
65        fprintf(stderr, "Unhandled shift type\n");
66        exit(1);
67        break;
68    }
69    return 0;
70}
71
72// Shift Rm by Rs
73int32_t
74ArmStaticInst::shift_rm_rs(uint32_t base, uint32_t shamt,
75                           uint32_t type, uint32_t cfval) const
76{
77    enum ArmShiftType shiftType;
78    shiftType = (enum ArmShiftType) type;
79
80    switch (shiftType)
81    {
82      case LSL:
83        if (shamt >= 32)
84            return 0;
85        else
86            return base << shamt;
87      case LSR:
88        if (shamt >= 32)
89            return 0;
90        else
91            return base >> shamt;
92      case ASR:
93        if (shamt >= 32)
94            return (int32_t)base >> 31;
95        else
96            return (int32_t)base >> shamt;
97      case ROR:
98        shamt = shamt & 0x1f;
99        if (shamt == 0)
100            return base;
101        else
102            return (base << (32 - shamt)) | (base >> shamt);
103      default:
104        fprintf(stderr, "Unhandled shift type\n");
105        exit(1);
106        break;
107    }
108    return 0;
109}
110
111
112// Generate C for a shift by immediate
113bool
114ArmStaticInst::shift_carry_imm(uint32_t base, uint32_t shamt,
115                               uint32_t type, uint32_t cfval) const
116{
117    enum ArmShiftType shiftType;
118    shiftType = (enum ArmShiftType) type;
119
120    switch (shiftType)
121    {
122      case LSL:
123        if (shamt == 0)
124            return cfval;
125        else
126            return (base >> (32 - shamt)) & 1;
127      case LSR:
128        if (shamt == 0)
129            return (base >> 31);
130        else
131            return (base >> (shamt - 1)) & 1;
132      case ASR:
133        if (shamt == 0)
134            return (base >> 31);
135        else
136            return (base >> (shamt - 1)) & 1;
137      case ROR:
138        shamt = shamt & 0x1f;
139        if (shamt == 0)
140            return (base & 1); // RRX
141        else
142            return (base >> (shamt - 1)) & 1;
143      default:
144        fprintf(stderr, "Unhandled shift type\n");
145        exit(1);
146        break;
147    }
148    return 0;
149}
150
151
152// Generate C for a shift by Rs
153bool
154ArmStaticInst::shift_carry_rs(uint32_t base, uint32_t shamt,
155                              uint32_t type, uint32_t cfval) const
156{
157    enum ArmShiftType shiftType;
158    shiftType = (enum ArmShiftType) type;
159
160    if (shamt == 0)
161        return cfval;
162
163    switch (shiftType)
164    {
165      case LSL:
166        if (shamt > 32)
167            return 0;
168        else
169            return (base >> (32 - shamt)) & 1;
170      case LSR:
171        if (shamt > 32)
172            return 0;
173        else
174            return (base >> (shamt - 1)) & 1;
175      case ASR:
176        if (shamt > 32)
177            shamt = 32;
178        return (base >> (shamt - 1)) & 1;
179      case ROR:
180        shamt = shamt & 0x1f;
181        if (shamt == 0)
182            shamt = 32;
183        return (base >> (shamt - 1)) & 1;
184      default:
185        fprintf(stderr, "Unhandled shift type\n");
186        exit(1);
187        break;
188    }
189    return 0;
190}
191
192
193// Generate the appropriate carry bit for an addition operation
194bool
195ArmStaticInst::arm_add_carry(int32_t result, int32_t lhs, int32_t rhs) const
196{
197    return findCarry(32, result, lhs, rhs);
198}
199
200// Generate the appropriate carry bit for a subtraction operation
201bool
202ArmStaticInst::arm_sub_carry(int32_t result, int32_t lhs, int32_t rhs) const
203{
204    return findCarry(32, result, lhs, ~rhs);
205}
206
207bool
208ArmStaticInst::arm_add_overflow(int32_t result, int32_t lhs, int32_t rhs) const
209{
210    return findOverflow(32, result, lhs, rhs);
211}
212
213bool
214ArmStaticInst::arm_sub_overflow(int32_t result, int32_t lhs, int32_t rhs) const
215{
216    return findOverflow(32, result, lhs, ~rhs);
217}
218
219void
220ArmStaticInst::printReg(std::ostream &os, int reg) const
221{
222    if (reg < FP_Base_DepTag) {
223        switch (reg) {
224          case PCReg:
225            ccprintf(os, "pc");
226            break;
227          case StackPointerReg:
228            ccprintf(os, "sp");
229            break;
230          case FramePointerReg:
231            ccprintf(os, "fp");
232            break;
233          case ReturnAddressReg:
234            ccprintf(os, "lr");
235            break;
236          default:
237            ccprintf(os, "r%d", reg);
238            break;
239        }
240    } else if (reg < Ctrl_Base_DepTag) {
241        ccprintf(os, "f%d", reg - FP_Base_DepTag);
242    } else {
243        reg -= Ctrl_Base_DepTag;
244        assert(reg < NUM_MISCREGS);
245        ccprintf(os, "%s", ArmISA::miscRegName[reg]);
246    }
247}
248
249void
250ArmStaticInst::printMnemonic(std::ostream &os,
251                             const std::string &suffix,
252                             bool withPred) const
253{
254    os << "  " << mnemonic;
255    if (withPred) {
256        unsigned condCode = machInst.condCode;
257        switch (condCode) {
258          case COND_EQ:
259            os << "eq";
260            break;
261          case COND_NE:
262            os << "ne";
263            break;
264          case COND_CS:
265            os << "cs";
266            break;
267          case COND_CC:
268            os << "cc";
269            break;
270          case COND_MI:
271            os << "mi";
272            break;
273          case COND_PL:
274            os << "pl";
275            break;
276          case COND_VS:
277            os << "vs";
278            break;
279          case COND_VC:
280            os << "vc";
281            break;
282          case COND_HI:
283            os << "hi";
284            break;
285          case COND_LS:
286            os << "ls";
287            break;
288          case COND_GE:
289            os << "ge";
290            break;
291          case COND_LT:
292            os << "lt";
293            break;
294          case COND_GT:
295            os << "gt";
296            break;
297          case COND_LE:
298            os << "le";
299            break;
300          case COND_AL:
301            // This one is implicit.
302            break;
303          case COND_NV:
304            os << "nv";
305            break;
306          default:
307            panic("Unrecognized condition code %d.\n", condCode);
308        }
309        os << suffix << "   ";
310    }
311}
312
313void
314ArmStaticInst::printMemSymbol(std::ostream &os,
315                              const SymbolTable *symtab,
316                              const std::string &prefix,
317                              const Addr addr,
318                              const std::string &suffix) const
319{
320    Addr symbolAddr;
321    std::string symbol;
322    if (symtab && symtab->findNearestSymbol(addr, symbol, symbolAddr)) {
323        ccprintf(os, "%s%s", prefix, symbol);
324        if (symbolAddr != addr)
325            ccprintf(os, "+%d", addr - symbolAddr);
326        ccprintf(os, suffix);
327    }
328}
329
330void
331ArmStaticInst::printShiftOperand(std::ostream &os) const
332{
333    // Shifter operand
334    if (bits((uint32_t)machInst, 25)) {
335        // Immediate form
336        unsigned rotate = machInst.rotate * 2;
337        uint32_t imm = machInst.imm;
338        ccprintf(os, "#%#x", (imm << (32 - rotate)) | (imm >> rotate));
339    } else {
340        // Register form
341        printReg(os, machInst.rm);
342
343        bool immShift = (machInst.opcode4 == 0);
344        bool done = false;
345        unsigned shiftAmt = (machInst.shiftSize);
346        ArmShiftType type = (ArmShiftType)(uint32_t)machInst.shift;
347
348        if ((type == LSR || type == ASR) && immShift && shiftAmt == 0)
349            shiftAmt = 32;
350
351        switch (type) {
352          case LSL:
353            if (immShift && shiftAmt == 0) {
354                done = true;
355                break;
356            }
357            os << ", LSL";
358            break;
359          case LSR:
360            os << ", LSR";
361            break;
362          case ASR:
363            os << ", ASR";
364            break;
365          case ROR:
366            if (immShift && shiftAmt == 0) {
367                os << ", RRX";
368                done = true;
369                break;
370            }
371            os << ", ROR";
372            break;
373          default:
374            panic("Tried to disassemble unrecognized shift type.\n");
375        }
376        if (!done) {
377            os << " ";
378            if (immShift)
379                os << "#" << shiftAmt;
380            else
381                printReg(os, machInst.rs);
382        }
383    }
384}
385
386void
387ArmStaticInst::printDataInst(std::ostream &os) const
388{
389    printMnemonic(os, machInst.sField ? "s" : "");
390    //XXX It would be nice if the decoder figured this all out for us.
391    unsigned opcode = machInst.opcode;
392    bool firstOp = true;
393
394    // Destination
395    // Cmp, cmn, teq, and tst don't have one.
396    if (opcode < 8 || opcode > 0xb) {
397        firstOp = false;
398        printReg(os, machInst.rd);
399    }
400
401    // Source 1.
402    // Mov and Movn don't have one of these.
403    if (opcode != 0xd && opcode != 0xf) {
404        if (!firstOp)
405            os << ", ";
406        firstOp = false;
407        printReg(os, machInst.rn);
408    }
409
410    if (!firstOp)
411        os << ", ";
412    printShiftOperand(os);
413}
414
415std::string
416ArmStaticInst::generateDisassembly(Addr pc,
417                                   const SymbolTable *symtab) const
418{
419    std::stringstream ss;
420    printMnemonic(ss);
421    return ss.str();
422}
423}
424