arch-power: Add doubleword multiply-add instructions
[gem5.git] / src / arch / power / insts / integer.cc
1 /*
2 * Copyright (c) 2009 The University of Edinburgh
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "arch/power/insts/integer.hh"
30
31 using namespace PowerISA;
32
33 std::string
34 IntOp::generateDisassembly(Addr pc, const Loader::SymbolTable *symtab) const
35 {
36 std::stringstream ss;
37 bool printDest = true;
38 bool printSrcs = true;
39 bool printSecondSrc = true;
40
41 // Generate the correct mnemonic
42 std::string myMnemonic(mnemonic);
43
44 // Special cases
45 if (!myMnemonic.compare("or") && srcRegIdx(0) == srcRegIdx(1)) {
46 myMnemonic = "mr";
47 printSecondSrc = false;
48 } else if (!myMnemonic.compare("mtcrf") ||
49 !myMnemonic.compare("mtxer") ||
50 !myMnemonic.compare("mtlr") ||
51 !myMnemonic.compare("mtctr") ||
52 !myMnemonic.compare("cmpi") ||
53 !myMnemonic.compare("mttar")) {
54 printDest = false;
55 } else if (!myMnemonic.compare("mfcr") ||
56 !myMnemonic.compare("mfxer") ||
57 !myMnemonic.compare("mflr") ||
58 !myMnemonic.compare("mfctr") ||
59 !myMnemonic.compare("mftar")) {
60 printSrcs = false;
61 }
62
63 // Additional characters depending on isa bits being set
64 if (oeSet) myMnemonic = myMnemonic + "o";
65 if (rcSet) myMnemonic = myMnemonic + ".";
66 ccprintf(ss, "%-10s ", myMnemonic);
67
68 // Print the first destination only
69 if (_numDestRegs > 0 && printDest) {
70 printReg(ss, destRegIdx(0));
71 }
72
73 // Print the (possibly) two source registers
74 if (_numSrcRegs > 0 && printSrcs) {
75 if (_numDestRegs > 0 && printDest) {
76 ss << ", ";
77 }
78 printReg(ss, srcRegIdx(0));
79 if (_numSrcRegs > 1 && printSecondSrc) {
80 ss << ", ";
81 printReg(ss, srcRegIdx(1));
82 }
83 }
84
85 return ss.str();
86 }
87
88
89 std::string
90 IntImmOp::generateDisassembly(Addr pc, const Loader::SymbolTable *symtab) const
91 {
92 std::stringstream ss;
93
94 ccprintf(ss, "%-10s ", mnemonic);
95
96 // Print the first destination only
97 if (_numDestRegs > 0) {
98 printReg(ss, destRegIdx(0));
99 }
100
101 // Print the source register
102 if (_numSrcRegs > 0) {
103 if (_numDestRegs > 0) {
104 ss << ", ";
105 }
106 printReg(ss, srcRegIdx(0));
107 }
108
109 // Print the immediate value last
110 ss << ", " << (int32_t)imm;
111
112 return ss.str();
113 }
114
115
116 std::string
117 IntArithOp::generateDisassembly(
118 Addr pc, const Loader::SymbolTable *symtab) const
119 {
120 std::stringstream ss;
121 bool printSecondSrc = true;
122 bool printThirdSrc = false;
123
124 // Generate the correct mnemonic
125 std::string myMnemonic(mnemonic);
126
127 // Special cases
128 if (!myMnemonic.compare("addme") ||
129 !myMnemonic.compare("addze") ||
130 !myMnemonic.compare("subfme") ||
131 !myMnemonic.compare("subfze") ||
132 !myMnemonic.compare("neg")){
133 printSecondSrc = false;
134 } else if (!myMnemonic.compare("maddhd") ||
135 !myMnemonic.compare("maddhdu") ||
136 !myMnemonic.compare("maddld")) {
137 printThirdSrc = true;
138 }
139
140 // Additional characters depending on isa bits being set
141 if (oeSet) myMnemonic = myMnemonic + "o";
142 if (rcSet) myMnemonic = myMnemonic + ".";
143 ccprintf(ss, "%-10s ", myMnemonic);
144
145 // Print the first destination only
146 if (_numDestRegs > 0) {
147 printReg(ss, destRegIdx(0));
148 }
149
150 // Print the first source register
151 if (_numSrcRegs > 0) {
152 if (_numDestRegs > 0) {
153 ss << ", ";
154 }
155 printReg(ss, srcRegIdx(0));
156
157 // Print the second source register
158 if (_numSrcRegs > 1 && printSecondSrc) {
159 ss << ", ";
160 printReg(ss, srcRegIdx(1));
161
162 // Print the third source register
163 if (_numSrcRegs > 2 && printThirdSrc) {
164 ss << ", ";
165 printReg(ss, srcRegIdx(2));
166 }
167 }
168 }
169
170 return ss.str();
171 }
172
173
174 std::string
175 IntImmArithOp::generateDisassembly(
176 Addr pc, const Loader::SymbolTable *symtab) const
177 {
178 std::stringstream ss;
179 bool negateSimm = false;
180
181 // Generate the correct mnemonic
182 std::string myMnemonic(mnemonic);
183
184 // Special cases
185 if (!myMnemonic.compare("addi")) {
186 if (_numSrcRegs == 0) {
187 myMnemonic = "li";
188 } else if (simm < 0) {
189 myMnemonic = "subi";
190 negateSimm = true;
191 }
192 } else if (!myMnemonic.compare("addis")) {
193 if (_numSrcRegs == 0) {
194 myMnemonic = "lis";
195 } else if (simm < 0) {
196 myMnemonic = "subis";
197 negateSimm = true;
198 }
199 } else if (!myMnemonic.compare("addic") && simm < 0) {
200 myMnemonic = "subic";
201 negateSimm = true;
202 } else if (!myMnemonic.compare("addic_")) {
203 if (simm < 0) {
204 myMnemonic = "subic.";
205 negateSimm = true;
206 } else {
207 myMnemonic = "addic.";
208 }
209 }
210
211 ccprintf(ss, "%-10s ", myMnemonic);
212
213 // Print the first destination only
214 if (_numDestRegs > 0) {
215 printReg(ss, destRegIdx(0));
216 }
217
218 // Print the source register
219 if (_numSrcRegs > 0) {
220 if (_numDestRegs > 0) {
221 ss << ", ";
222 }
223 printReg(ss, srcRegIdx(0));
224 }
225
226 // Print the immediate value
227 if (negateSimm) {
228 ss << ", " << -simm;
229 } else {
230 ss << ", " << simm;
231 }
232
233 return ss.str();
234 }
235
236
237 std::string
238 IntDispArithOp::generateDisassembly(
239 Addr pc, const Loader::SymbolTable *symtab) const
240 {
241 std::stringstream ss;
242 bool printSrcs = true;
243 bool printDisp = true;
244 bool negateDisp = false;
245
246 // Generate the correct mnemonic
247 std::string myMnemonic(mnemonic);
248
249 // Special cases
250 if (!myMnemonic.compare("addpcis")) {
251 printSrcs = false;
252 if (disp == 0) {
253 myMnemonic = "lnia";
254 printDisp = false;
255 } else if (disp < 0) {
256 myMnemonic = "subpcis";
257 negateDisp = true;
258 }
259 }
260
261 ccprintf(ss, "%-10s ", myMnemonic);
262
263 // Print the first destination only
264 if (_numDestRegs > 0) {
265 printReg(ss, destRegIdx(0));
266 }
267
268 // Print the source register
269 if (_numSrcRegs > 0 && printSrcs) {
270 if (_numDestRegs > 0) {
271 ss << ", ";
272 }
273 printReg(ss, srcRegIdx(0));
274 }
275
276 // Print the displacement
277 if (printDisp) {
278 if (negateDisp) {
279 ss << ", " << -disp;
280 } else {
281 ss << ", " << disp;
282 }
283 }
284
285 return ss.str();
286 }
287
288
289 std::string
290 IntShiftOp::generateDisassembly(
291 Addr pc, const Loader::SymbolTable *symtab) const
292 {
293 std::stringstream ss;
294
295 ccprintf(ss, "%-10s ", mnemonic);
296
297 // Print the first destination only
298 if (_numDestRegs > 0) {
299 printReg(ss, destRegIdx(0));
300 }
301
302 // Print the first source register
303 if (_numSrcRegs > 0) {
304 if (_numDestRegs > 0) {
305 ss << ", ";
306 }
307 printReg(ss, srcRegIdx(0));
308 }
309
310 // Print the shift
311 ss << ", " << sh;
312
313 return ss.str();
314 }
315
316
317 std::string
318 IntRotateOp::generateDisassembly(
319 Addr pc, const Loader::SymbolTable *symtab) const
320 {
321 std::stringstream ss;
322
323 ccprintf(ss, "%-10s ", mnemonic);
324
325 // Print the first destination only
326 if (_numDestRegs > 0) {
327 printReg(ss, destRegIdx(0));
328 }
329
330 // Print the first source register
331 if (_numSrcRegs > 0) {
332 if (_numDestRegs > 0) {
333 ss << ", ";
334 }
335 printReg(ss, srcRegIdx(0));
336 }
337
338 // Print the shift, mask begin and mask end
339 ss << ", " << sh << ", " << mb << ", " << me;
340
341 return ss.str();
342 }