static_inst.cc revision 6712
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/cprintf.hh"
33#include "base/loader/symtab.hh"
34
35namespace ArmISA
36{
37// Shift Rm by an immediate value
38int32_t
39ArmStaticInst::shift_rm_imm(uint32_t base, uint32_t shamt,
40                            uint32_t type, uint32_t cfval) const
41{
42    assert(shamt < 32);
43    ArmShiftType shiftType;
44    shiftType = (ArmShiftType)type;
45
46    switch (shiftType)
47    {
48      case LSL:
49        return base << shamt;
50      case LSR:
51        if (shamt == 0)
52            return 0;
53        else
54            return base >> shamt;
55      case ASR:
56        if (shamt == 0)
57            return (int32_t)base >> 31;
58        else
59            return (int32_t)base >> shamt;
60      case ROR:
61        if (shamt == 0)
62            return (cfval << 31) | (base >> 1); // RRX
63        else
64            return (base << (32 - shamt)) | (base >> shamt);
65      default:
66        ccprintf(std::cerr, "Unhandled shift type\n");
67        exit(1);
68        break;
69    }
70    return 0;
71}
72
73// Shift Rm by Rs
74int32_t
75ArmStaticInst::shift_rm_rs(uint32_t base, uint32_t shamt,
76                           uint32_t type, uint32_t cfval) const
77{
78    enum ArmShiftType shiftType;
79    shiftType = (enum ArmShiftType) type;
80
81    switch (shiftType)
82    {
83      case LSL:
84        if (shamt >= 32)
85            return 0;
86        else
87            return base << shamt;
88      case LSR:
89        if (shamt >= 32)
90            return 0;
91        else
92            return base >> shamt;
93      case ASR:
94        if (shamt >= 32)
95            return (int32_t)base >> 31;
96        else
97            return (int32_t)base >> shamt;
98      case ROR:
99        shamt = shamt & 0x1f;
100        if (shamt == 0)
101            return base;
102        else
103            return (base << (32 - shamt)) | (base >> shamt);
104      default:
105        ccprintf(std::cerr, "Unhandled shift type\n");
106        exit(1);
107        break;
108    }
109    return 0;
110}
111
112
113// Generate C for a shift by immediate
114bool
115ArmStaticInst::shift_carry_imm(uint32_t base, uint32_t shamt,
116                               uint32_t type, uint32_t cfval) const
117{
118    enum ArmShiftType shiftType;
119    shiftType = (enum ArmShiftType) type;
120
121    switch (shiftType)
122    {
123      case LSL:
124        if (shamt == 0)
125            return cfval;
126        else
127            return (base >> (32 - shamt)) & 1;
128      case LSR:
129        if (shamt == 0)
130            return (base >> 31);
131        else
132            return (base >> (shamt - 1)) & 1;
133      case ASR:
134        if (shamt == 0)
135            return (base >> 31);
136        else
137            return (base >> (shamt - 1)) & 1;
138      case ROR:
139        shamt = shamt & 0x1f;
140        if (shamt == 0)
141            return (base & 1); // RRX
142        else
143            return (base >> (shamt - 1)) & 1;
144      default:
145        ccprintf(std::cerr, "Unhandled shift type\n");
146        exit(1);
147        break;
148    }
149    return 0;
150}
151
152
153// Generate C for a shift by Rs
154bool
155ArmStaticInst::shift_carry_rs(uint32_t base, uint32_t shamt,
156                              uint32_t type, uint32_t cfval) const
157{
158    enum ArmShiftType shiftType;
159    shiftType = (enum ArmShiftType) type;
160
161    if (shamt == 0)
162        return cfval;
163
164    switch (shiftType)
165    {
166      case LSL:
167        if (shamt > 32)
168            return 0;
169        else
170            return (base >> (32 - shamt)) & 1;
171      case LSR:
172        if (shamt > 32)
173            return 0;
174        else
175            return (base >> (shamt - 1)) & 1;
176      case ASR:
177        if (shamt > 32)
178            shamt = 32;
179        return (base >> (shamt - 1)) & 1;
180      case ROR:
181        shamt = shamt & 0x1f;
182        if (shamt == 0)
183            shamt = 32;
184        return (base >> (shamt - 1)) & 1;
185      default:
186        ccprintf(std::cerr, "Unhandled shift type\n");
187        exit(1);
188        break;
189    }
190    return 0;
191}
192
193
194// Generate the appropriate carry bit for an addition operation
195bool
196ArmStaticInst::arm_add_carry(int32_t result, int32_t lhs, int32_t rhs) const
197{
198    return findCarry(32, result, lhs, rhs);
199}
200
201// Generate the appropriate carry bit for a subtraction operation
202bool
203ArmStaticInst::arm_sub_carry(int32_t result, int32_t lhs, int32_t rhs) const
204{
205    return findCarry(32, result, lhs, ~rhs);
206}
207
208bool
209ArmStaticInst::arm_add_overflow(int32_t result, int32_t lhs, int32_t rhs) const
210{
211    return findOverflow(32, result, lhs, rhs);
212}
213
214bool
215ArmStaticInst::arm_sub_overflow(int32_t result, int32_t lhs, int32_t rhs) const
216{
217    return findOverflow(32, result, lhs, ~rhs);
218}
219
220void
221ArmStaticInst::printReg(std::ostream &os, int reg) const
222{
223    if (reg < FP_Base_DepTag) {
224        switch (reg) {
225          case PCReg:
226            ccprintf(os, "pc");
227            break;
228          case StackPointerReg:
229            ccprintf(os, "sp");
230            break;
231          case FramePointerReg:
232            ccprintf(os, "fp");
233            break;
234          case ReturnAddressReg:
235            ccprintf(os, "lr");
236            break;
237          default:
238            ccprintf(os, "r%d", reg);
239            break;
240        }
241    } else if (reg < Ctrl_Base_DepTag) {
242        ccprintf(os, "f%d", reg - FP_Base_DepTag);
243    } else {
244        reg -= Ctrl_Base_DepTag;
245        assert(reg < NUM_MISCREGS);
246        ccprintf(os, "%s", ArmISA::miscRegName[reg]);
247    }
248}
249
250void
251ArmStaticInst::printMnemonic(std::ostream &os,
252                             const std::string &suffix,
253                             bool withPred) const
254{
255    os << "  " << mnemonic;
256    if (withPred) {
257        unsigned condCode = machInst.condCode;
258        switch (condCode) {
259          case COND_EQ:
260            os << "eq";
261            break;
262          case COND_NE:
263            os << "ne";
264            break;
265          case COND_CS:
266            os << "cs";
267            break;
268          case COND_CC:
269            os << "cc";
270            break;
271          case COND_MI:
272            os << "mi";
273            break;
274          case COND_PL:
275            os << "pl";
276            break;
277          case COND_VS:
278            os << "vs";
279            break;
280          case COND_VC:
281            os << "vc";
282            break;
283          case COND_HI:
284            os << "hi";
285            break;
286          case COND_LS:
287            os << "ls";
288            break;
289          case COND_GE:
290            os << "ge";
291            break;
292          case COND_LT:
293            os << "lt";
294            break;
295          case COND_GT:
296            os << "gt";
297            break;
298          case COND_LE:
299            os << "le";
300            break;
301          case COND_AL:
302            // This one is implicit.
303            break;
304          case COND_NV:
305            os << "nv";
306            break;
307          default:
308            panic("Unrecognized condition code %d.\n", condCode);
309        }
310        os << suffix << "   ";
311    }
312}
313
314void
315ArmStaticInst::printMemSymbol(std::ostream &os,
316                              const SymbolTable *symtab,
317                              const std::string &prefix,
318                              const Addr addr,
319                              const std::string &suffix) const
320{
321    Addr symbolAddr;
322    std::string symbol;
323    if (symtab && symtab->findNearestSymbol(addr, symbol, symbolAddr)) {
324        ccprintf(os, "%s%s", prefix, symbol);
325        if (symbolAddr != addr)
326            ccprintf(os, "+%d", addr - symbolAddr);
327        ccprintf(os, suffix);
328    }
329}
330
331void
332ArmStaticInst::printShiftOperand(std::ostream &os) const
333{
334    printReg(os, machInst.rm);
335
336    bool immShift = (machInst.opcode4 == 0);
337    bool done = false;
338    unsigned shiftAmt = (machInst.shiftSize);
339    ArmShiftType type = (ArmShiftType)(uint32_t)machInst.shift;
340
341    if ((type == LSR || type == ASR) && immShift && shiftAmt == 0)
342        shiftAmt = 32;
343
344    switch (type) {
345      case LSL:
346        if (immShift && shiftAmt == 0) {
347            done = true;
348            break;
349        }
350        os << ", LSL";
351        break;
352      case LSR:
353        os << ", LSR";
354        break;
355      case ASR:
356        os << ", ASR";
357        break;
358      case ROR:
359        if (immShift && shiftAmt == 0) {
360            os << ", RRX";
361            done = true;
362            break;
363        }
364        os << ", ROR";
365        break;
366      default:
367        panic("Tried to disassemble unrecognized shift type.\n");
368    }
369    if (!done) {
370        os << " ";
371        if (immShift)
372            os << "#" << shiftAmt;
373        else
374            printReg(os, machInst.rs);
375    }
376}
377
378void
379ArmStaticInst::printDataInst(std::ostream &os, bool withImm) const
380{
381    printMnemonic(os, machInst.sField ? "s" : "");
382    //XXX It would be nice if the decoder figured this all out for us.
383    unsigned opcode = machInst.opcode;
384    bool firstOp = true;
385
386    // Destination
387    // Cmp, cmn, teq, and tst don't have one.
388    if (opcode < 8 || opcode > 0xb) {
389        firstOp = false;
390        printReg(os, machInst.rd);
391    }
392
393    // Source 1.
394    // Mov and Movn don't have one of these.
395    if (opcode != 0xd && opcode != 0xf) {
396        if (!firstOp)
397            os << ", ";
398        firstOp = false;
399        printReg(os, machInst.rn);
400    }
401
402    if (!firstOp)
403        os << ", ";
404    if (withImm) {
405        unsigned rotate = machInst.rotate * 2;
406        uint32_t imm = machInst.imm;
407        ccprintf(os, "#%#x", (imm << (32 - rotate)) | (imm >> rotate));
408    } else {
409        printShiftOperand(os);
410    }
411}
412
413std::string
414ArmStaticInst::generateDisassembly(Addr pc,
415                                   const SymbolTable *symtab) const
416{
417    std::stringstream ss;
418    printMnemonic(ss);
419    return ss.str();
420}
421}
422