1 |
5 |
sergeykhbr |
/*
|
2 |
|
|
* Copyright 2018 Sergey Khabarov, sergeykhbr@gmail.com
|
3 |
|
|
*
|
4 |
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
5 |
|
|
* you may not use this file except in compliance with the License.
|
6 |
|
|
* You may obtain a copy of the License at
|
7 |
|
|
*
|
8 |
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
9 |
|
|
*
|
10 |
|
|
* Unless required by applicable law or agreed to in writing, software
|
11 |
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
12 |
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13 |
|
|
* See the License for the specific language governing permissions and
|
14 |
|
|
* limitations under the License.
|
15 |
|
|
*/
|
16 |
|
|
|
17 |
|
|
#include "api_utils.h"
|
18 |
|
|
#include "arm-isa.h"
|
19 |
|
|
#include "cpu_arm7_func.h"
|
20 |
|
|
|
21 |
|
|
namespace debugger {
|
22 |
|
|
|
23 |
|
|
static const uint64_t PREFETCH_OFFSET[InstrModes_Total] = {
|
24 |
|
|
8,
|
25 |
|
|
4
|
26 |
|
|
};
|
27 |
|
|
|
28 |
|
|
/** Data processing default behaviour can be re-implemeted: */
|
29 |
|
|
int ArmDataProcessingInstruction::exec_checked(Reg64Type *payload) {
|
30 |
|
|
DataProcessingType u;
|
31 |
|
|
u.value = payload->buf32[0];
|
32 |
|
|
uint32_t A = static_cast<uint32_t>(R[u.reg_bits.rn]);
|
33 |
|
|
uint32_t M;
|
34 |
|
|
uint32_t Res;
|
35 |
|
|
if (u.imm_bits.I) {
|
36 |
|
|
M = imm12(u.imm_bits);
|
37 |
|
|
} else {
|
38 |
|
|
M = static_cast<uint32_t>(R[u.reg_bits.rm]);
|
39 |
|
|
M = shift12(u.reg_bits, M, R[u.reg_bits.shift >> 1]);
|
40 |
|
|
}
|
41 |
|
|
if (do_operation(A, M, &Res)) {
|
42 |
|
|
R[u.reg_bits.rd] = Res;
|
43 |
|
|
}
|
44 |
|
|
if (is_flags_changed(u)) {
|
45 |
|
|
set_flags(A, M, Res);
|
46 |
|
|
}
|
47 |
|
|
return 4;
|
48 |
|
|
}
|
49 |
|
|
|
50 |
|
|
bool ArmDataProcessingInstruction::is_flags_changed(DataProcessingType u) {
|
51 |
|
|
return u.reg_bits.S && u.reg_bits.rd != Reg_pc;
|
52 |
|
|
}
|
53 |
|
|
|
54 |
|
|
void ArmDataProcessingInstruction::set_flags(uint32_t A, uint32_t M,
|
55 |
|
|
uint32_t Res) {
|
56 |
|
|
icpu_->setC(0);
|
57 |
|
|
icpu_->setZ(Res == 0);
|
58 |
|
|
icpu_->setN(Res >> 31);
|
59 |
|
|
}
|
60 |
|
|
|
61 |
|
|
/** @brief Subtruct specific instruction set
|
62 |
|
|
|
63 |
|
|
Specific flags computation with subtraction
|
64 |
|
|
*/
|
65 |
|
|
class ArmSubInstruction : public ArmDataProcessingInstruction {
|
66 |
|
|
public:
|
67 |
|
|
ArmSubInstruction(CpuCortex_Functional *icpu, const char *name,
|
68 |
|
|
const char *bits) : ArmDataProcessingInstruction(icpu, name, bits) {}
|
69 |
|
|
protected:
|
70 |
|
|
virtual bool is_inverted() = 0;
|
71 |
|
|
virtual bool with_carry() = 0;
|
72 |
|
|
virtual EOperationResult op_result() = 0;
|
73 |
|
|
|
74 |
|
|
virtual EOperationResult do_operation(uint32_t A, uint32_t M,
|
75 |
|
|
uint32_t *pRes) {
|
76 |
|
|
if (!is_inverted()) {
|
77 |
|
|
*pRes = A - M;
|
78 |
|
|
} else {
|
79 |
|
|
*pRes = M - A;
|
80 |
|
|
}
|
81 |
|
|
if (with_carry()) {
|
82 |
|
|
*pRes += (icpu_->getC() - 1);
|
83 |
|
|
}
|
84 |
|
|
return op_result();
|
85 |
|
|
}
|
86 |
|
|
|
87 |
|
|
virtual void set_flags(uint32_t A, uint32_t M, uint32_t Res) {
|
88 |
|
|
if (is_inverted()) {
|
89 |
|
|
uint32_t t1 = A;
|
90 |
|
|
A = M;
|
91 |
|
|
M = t1;
|
92 |
|
|
}
|
93 |
|
|
uint32_t C = !(((~A & M) | (M & Res) | (Res & ~A)) >> 31);
|
94 |
|
|
uint32_t V = ((A & ~M & ~Res) | (~A & M & Res)) >> 31;
|
95 |
|
|
icpu_->setC(C);
|
96 |
|
|
icpu_->setV(V);
|
97 |
|
|
icpu_->setZ(Res == 0);
|
98 |
|
|
icpu_->setN(Res >> 31);
|
99 |
|
|
}
|
100 |
|
|
};
|
101 |
|
|
|
102 |
|
|
/** @brief addictive specific instruction set
|
103 |
|
|
|
104 |
|
|
Specific flags computation with addition
|
105 |
|
|
*/
|
106 |
|
|
class ArmAddInstruction : public ArmDataProcessingInstruction {
|
107 |
|
|
public:
|
108 |
|
|
ArmAddInstruction(CpuCortex_Functional *icpu, const char *name,
|
109 |
|
|
const char *bits) : ArmDataProcessingInstruction(icpu, name, bits) {}
|
110 |
|
|
protected:
|
111 |
|
|
virtual EOperationResult op_result() = 0;
|
112 |
|
|
virtual bool with_carry() = 0;
|
113 |
|
|
|
114 |
|
|
virtual EOperationResult do_operation(uint32_t A, uint32_t M,
|
115 |
|
|
uint32_t *pRes) {
|
116 |
|
|
*pRes = A + M;
|
117 |
|
|
if (with_carry()) {
|
118 |
|
|
*pRes += icpu_->getC();
|
119 |
|
|
}
|
120 |
|
|
return op_result();
|
121 |
|
|
}
|
122 |
|
|
|
123 |
|
|
virtual void set_flags(uint32_t A, uint32_t M, uint32_t Res) {
|
124 |
|
|
uint32_t C = ((A & M) | (M & ~Res) | (A & ~Res)) >> 31;
|
125 |
|
|
uint32_t V = ((A & M & ~Res) | (~A & ~M & Res)) >> 31;
|
126 |
|
|
icpu_->setC(C);
|
127 |
|
|
icpu_->setV(V);
|
128 |
|
|
icpu_->setZ(Res == 0);
|
129 |
|
|
icpu_->setN(Res >> 31);
|
130 |
|
|
}
|
131 |
|
|
};
|
132 |
|
|
|
133 |
|
|
/** Single memory transfer: LDR, STR
|
134 |
|
|
*/
|
135 |
|
|
class SingleDataTransferInstruction : public ArmInstruction {
|
136 |
|
|
public:
|
137 |
|
|
SingleDataTransferInstruction(CpuCortex_Functional *icpu, const char *name,
|
138 |
|
|
const char *bits) : ArmInstruction(icpu, name, bits) {}
|
139 |
|
|
|
140 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
141 |
|
|
SingleDataTransferType u;
|
142 |
|
|
u.value = payload->buf32[0];
|
143 |
|
|
uint32_t opsz[2] = {4, 1};
|
144 |
|
|
uint64_t off = R[u.imm_bits.rn];
|
145 |
|
|
|
146 |
|
|
if (u.imm_bits.rn == Reg_pc) {
|
147 |
|
|
off += PREFETCH_OFFSET[icpu_->getInstrMode()];
|
148 |
|
|
if (u.imm_bits.rd == Reg_pc && !u.imm_bits.I
|
149 |
|
|
&& (u.imm_bits.imm & 0x1)) {
|
150 |
|
|
// DSB, ISB
|
151 |
|
|
return 4;
|
152 |
|
|
}
|
153 |
|
|
}
|
154 |
|
|
|
155 |
|
|
if (u.imm_bits.P) {
|
156 |
|
|
off += get_increment(u);
|
157 |
|
|
if (u.imm_bits.W) {
|
158 |
|
|
R[u.imm_bits.rn] = off;
|
159 |
|
|
}
|
160 |
|
|
}
|
161 |
|
|
|
162 |
|
|
trans_.addr = off;
|
163 |
|
|
trans_.wstrb = 0;
|
164 |
|
|
trans_.xsize = opsz[u.imm_bits.B];
|
165 |
|
|
if (u.imm_bits.L) {
|
166 |
|
|
trans_.action = MemAction_Read;
|
167 |
|
|
trans_.rpayload.b64[0] = 0;
|
168 |
|
|
} else {
|
169 |
|
|
trans_.action = MemAction_Write;
|
170 |
|
|
trans_.wstrb = (1 << trans_.xsize) - 1;
|
171 |
|
|
trans_.wpayload.b64[0] = R[u.imm_bits.rd];
|
172 |
|
|
}
|
173 |
|
|
icpu_->dma_memop(&trans_);
|
174 |
|
|
|
175 |
|
|
if (!u.imm_bits.P) {
|
176 |
|
|
off += get_increment(u);
|
177 |
|
|
R[u.imm_bits.rn] = off;
|
178 |
|
|
if (u.imm_bits.W) {
|
179 |
|
|
/** In the case of post-indexed addressing, the write back bit is
|
180 |
|
|
redundant and must be set to zero, since the old base value can be
|
181 |
|
|
retained by setting the offset to zero. Therefore post-indexed
|
182 |
|
|
data transfers always write back the modified base. The only use of
|
183 |
|
|
the W bit in a post-indexed data transfer is in privileged mode
|
184 |
|
|
code, where setting the W bit forces non-privileged mode for the
|
185 |
|
|
transfer, allowing the operating system to generate a user address
|
186 |
|
|
in a system where the memory management hardware makes suitable
|
187 |
|
|
use of this hardware.
|
188 |
|
|
*/
|
189 |
|
|
RISCV_error("Post-index LDR,STR with W=1", 0);
|
190 |
|
|
}
|
191 |
|
|
}
|
192 |
|
|
if (u.imm_bits.L) {
|
193 |
|
|
R[u.imm_bits.rd] = trans_.rpayload.b32[0];
|
194 |
|
|
if (u.imm_bits.rd == Reg_pc) {
|
195 |
|
|
icpu_->setBranch(R[u.imm_bits.rd]);
|
196 |
|
|
}
|
197 |
|
|
}
|
198 |
|
|
return 4;
|
199 |
|
|
}
|
200 |
|
|
|
201 |
|
|
protected:
|
202 |
|
|
virtual uint64_t get_increment(SingleDataTransferType u) {
|
203 |
|
|
uint64_t incr;
|
204 |
|
|
if (!u.imm_bits.I) {
|
205 |
|
|
incr = u.imm_bits.imm;
|
206 |
|
|
} else {
|
207 |
|
|
/**
|
208 |
|
|
@warning The register specified shift amounts
|
209 |
|
|
are not available in this instruction class.
|
210 |
|
|
*/
|
211 |
|
|
DataProcessingType u2;
|
212 |
|
|
u2.value = u.value;
|
213 |
|
|
incr = shift12(u2.reg_bits,
|
214 |
|
|
static_cast<uint32_t>(R[u.reg_bits.rm]),
|
215 |
|
|
0); // !! not available
|
216 |
|
|
}
|
217 |
|
|
if (!u.reg_bits.U) {
|
218 |
|
|
incr = (~incr) + 1;
|
219 |
|
|
}
|
220 |
|
|
return incr;
|
221 |
|
|
}
|
222 |
|
|
};
|
223 |
|
|
|
224 |
|
|
/** Block memory transfer: LDM, STM
|
225 |
|
|
*/
|
226 |
|
|
class BlockDataTransferInstruction : public ArmInstruction {
|
227 |
|
|
public:
|
228 |
|
|
BlockDataTransferInstruction(CpuCortex_Functional *icpu, const char *name,
|
229 |
|
|
const char *bits) : ArmInstruction(icpu, name, bits) {}
|
230 |
|
|
|
231 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
232 |
|
|
BlockDataTransferType u;
|
233 |
|
|
uint64_t adrincr[2] = {static_cast<uint64_t>(-4), 4};
|
234 |
|
|
u.value = payload->buf32[0];
|
235 |
|
|
uint32_t R15 = (u.bits.reglist >> 15) & 0x1;
|
236 |
|
|
int ridx;
|
237 |
|
|
// @todo Mode switching depending R15 value!!!!
|
238 |
|
|
|
239 |
|
|
trans_.addr = R[u.bits.rn];
|
240 |
|
|
trans_.xsize = 4;
|
241 |
|
|
trans_.wstrb = 0;
|
242 |
|
|
for (int i = 0; i < 16; i++) {
|
243 |
|
|
if (u.bits.L) {
|
244 |
|
|
ridx = 15 - i;
|
245 |
|
|
} else {
|
246 |
|
|
ridx = i;
|
247 |
|
|
}
|
248 |
|
|
if ((u.bits.reglist & (0x1 << ridx)) == 0) {
|
249 |
|
|
continue;
|
250 |
|
|
}
|
251 |
|
|
if (u.bits.L) {
|
252 |
|
|
trans_.action = MemAction_Read;
|
253 |
|
|
trans_.rpayload.b64[0] = 0;
|
254 |
|
|
} else {
|
255 |
|
|
trans_.action = MemAction_Write;
|
256 |
|
|
trans_.wstrb = (1 << trans_.xsize) - 1;
|
257 |
|
|
trans_.wpayload.b64[0] = R[ridx];
|
258 |
|
|
}
|
259 |
|
|
if (u.bits.P) {
|
260 |
|
|
trans_.addr += adrincr[u.bits.U];
|
261 |
|
|
if (u.bits.W) {
|
262 |
|
|
R[u.bits.rn] = trans_.addr;
|
263 |
|
|
}
|
264 |
|
|
}
|
265 |
|
|
|
266 |
|
|
icpu_->dma_memop(&trans_);
|
267 |
|
|
|
268 |
|
|
if (!u.bits.P) {
|
269 |
|
|
trans_.addr += adrincr[u.bits.U];
|
270 |
|
|
R[u.bits.rn] = trans_.addr;
|
271 |
|
|
}
|
272 |
|
|
|
273 |
|
|
if (u.bits.L) {
|
274 |
|
|
R[ridx] = trans_.rpayload.b32[0];
|
275 |
|
|
if (ridx == Reg_pc) {
|
276 |
|
|
icpu_->setBranch(R[ridx]);
|
277 |
|
|
}
|
278 |
|
|
}
|
279 |
|
|
}
|
280 |
|
|
|
281 |
|
|
if (!u.bits.P) {
|
282 |
|
|
if (u.bits.W) {
|
283 |
|
|
RISCV_error("Post-index LDM,STM with W=1", 0);
|
284 |
|
|
}
|
285 |
|
|
}
|
286 |
|
|
if (u.bits.S) {
|
287 |
|
|
// TODO: force user mode
|
288 |
|
|
}
|
289 |
|
|
return 4;
|
290 |
|
|
}
|
291 |
|
|
};
|
292 |
|
|
|
293 |
|
|
|
294 |
|
|
/** Halfword and Signed Data Transfer: LDRH/STRH/LDRSB/LDRSH
|
295 |
|
|
*/
|
296 |
|
|
class HWordSignedDataTransferInstruction : public ArmInstruction {
|
297 |
|
|
public:
|
298 |
|
|
HWordSignedDataTransferInstruction(CpuCortex_Functional *icpu,
|
299 |
|
|
const char *name, const char *bits)
|
300 |
|
|
: ArmInstruction(icpu, name, bits) {}
|
301 |
|
|
|
302 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
303 |
|
|
HWordSignedDataTransferType u;
|
304 |
|
|
u.value = payload->buf32[0];
|
305 |
|
|
uint32_t opsz[2] = {1, 2};
|
306 |
|
|
uint64_t off = R[u.bits.rn];
|
307 |
|
|
if (u.bits.rn == Reg_pc) {
|
308 |
|
|
off += PREFETCH_OFFSET[icpu_->getInstrMode()];
|
309 |
|
|
}
|
310 |
|
|
|
311 |
|
|
if (u.bits.P) {
|
312 |
|
|
off += get_increment(u);
|
313 |
|
|
}
|
314 |
|
|
|
315 |
|
|
trans_.addr = off;
|
316 |
|
|
trans_.xsize = opsz[u.bits.h];
|
317 |
|
|
trans_.wstrb = 0;
|
318 |
|
|
if (u.bits.L) {
|
319 |
|
|
trans_.action = MemAction_Read;
|
320 |
|
|
trans_.rpayload.b64[0] = 0;
|
321 |
|
|
} else {
|
322 |
|
|
trans_.action = MemAction_Write;
|
323 |
|
|
trans_.wstrb = (1 << trans_.xsize) - 1;
|
324 |
|
|
trans_.wpayload.b64[0] = R[u.bits.rd];
|
325 |
|
|
}
|
326 |
|
|
icpu_->dma_memop(&trans_);
|
327 |
|
|
|
328 |
|
|
if (u.bits.W) {
|
329 |
|
|
if (!u.bits.P) {
|
330 |
|
|
off += get_increment(u);
|
331 |
|
|
}
|
332 |
|
|
R[u.bits.rn] = off;
|
333 |
|
|
}
|
334 |
|
|
if (u.bits.L) {
|
335 |
|
|
if (u.bits.h) {
|
336 |
|
|
R[u.bits.rd] = trans_.rpayload.b16[0];
|
337 |
|
|
if (u.bits.s) {
|
338 |
|
|
R[u.bits.rd] |= EXT_SIGN_16;
|
339 |
|
|
}
|
340 |
|
|
} else {
|
341 |
|
|
R[u.bits.rd] = trans_.rpayload.b8[0];
|
342 |
|
|
if (u.bits.s) {
|
343 |
|
|
R[u.bits.rd] |= EXT_SIGN_8;
|
344 |
|
|
}
|
345 |
|
|
}
|
346 |
|
|
if (u.bits.rd == Reg_pc) {
|
347 |
|
|
icpu_->setBranch(R[u.bits.rd]);
|
348 |
|
|
}
|
349 |
|
|
}
|
350 |
|
|
return 4;
|
351 |
|
|
}
|
352 |
|
|
|
353 |
|
|
protected:
|
354 |
|
|
virtual uint64_t get_increment(HWordSignedDataTransferType u) {
|
355 |
|
|
uint64_t incr;
|
356 |
|
|
if (!u.bits.reg_imm) {
|
357 |
|
|
incr = (u.bits.imm_h << 4) | u.bits.rm;
|
358 |
|
|
} else {
|
359 |
|
|
incr = R[u.bits.rm];
|
360 |
|
|
}
|
361 |
|
|
if (!u.bits.U) {
|
362 |
|
|
incr = (~incr) + 1;
|
363 |
|
|
}
|
364 |
|
|
return incr;
|
365 |
|
|
}
|
366 |
|
|
};
|
367 |
|
|
|
368 |
|
|
/** Multiply common */
|
369 |
|
|
class MultiplyInstruction : public ArmInstruction {
|
370 |
|
|
public:
|
371 |
|
|
MultiplyInstruction(CpuCortex_Functional *icpu, const char *name,
|
372 |
|
|
const char *bits) : ArmInstruction(icpu, name, bits) {}
|
373 |
|
|
|
374 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
375 |
|
|
MulType u;
|
376 |
|
|
u.value = payload->buf32[0];
|
377 |
|
|
uint64_t res = R[u.bits.rm] * R[u.bits.rs];
|
378 |
|
|
if (u.bits.A) {
|
379 |
|
|
res += R[u.bits.rn];
|
380 |
|
|
}
|
381 |
|
|
R[u.bits.rd] = static_cast<uint32_t>(res);
|
382 |
|
|
if (u.bits.S) {
|
383 |
|
|
icpu_->setC(0); // set meaningless value
|
384 |
|
|
icpu_->setZ(R[u.bits.rd] == 0);
|
385 |
|
|
icpu_->setN(static_cast<uint32_t>(R[u.bits.rd]) >> 31);
|
386 |
|
|
}
|
387 |
|
|
return 4;
|
388 |
|
|
}
|
389 |
|
|
};
|
390 |
|
|
|
391 |
|
|
/** Multiply Long common. */
|
392 |
|
|
class MultiplyLongInstruction : public ArmInstruction {
|
393 |
|
|
public:
|
394 |
|
|
MultiplyLongInstruction(CpuCortex_Functional *icpu, const char *name,
|
395 |
|
|
const char *bits) : ArmInstruction(icpu, name, bits) {}
|
396 |
|
|
|
397 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
398 |
|
|
MulLongType u;
|
399 |
|
|
u.value = payload->buf32[0];
|
400 |
|
|
uint64_t res = 0;
|
401 |
|
|
if (u.bits.A) {
|
402 |
|
|
res = static_cast<uint64_t>(R[u.bits.rdhi]) << 32;
|
403 |
|
|
res |= R[u.bits.rdlo];
|
404 |
|
|
}
|
405 |
|
|
if (u.bits.S) {
|
406 |
|
|
int64_t a = static_cast<int32_t>(R[u.bits.rm]);
|
407 |
|
|
int64_t b = static_cast<int32_t>(R[u.bits.rs]);
|
408 |
|
|
res = static_cast<uint64_t>(static_cast<int64_t>(res) + a * b);
|
409 |
|
|
} else {
|
410 |
|
|
uint64_t a = R[u.bits.rm];
|
411 |
|
|
uint64_t b = R[u.bits.rs];
|
412 |
|
|
res = res + a * b;
|
413 |
|
|
}
|
414 |
|
|
R[u.bits.rdlo] = static_cast<uint32_t>(res);
|
415 |
|
|
R[u.bits.rdhi] = static_cast<uint32_t>(res >> 32);
|
416 |
|
|
if (u.bits.S) {
|
417 |
|
|
icpu_->setC(0); // set to meaningless value
|
418 |
|
|
icpu_->setV(0); // set to meaningless value
|
419 |
|
|
icpu_->setZ(res == 0);
|
420 |
|
|
icpu_->setN(static_cast<uint32_t>(res >> 63));
|
421 |
|
|
}
|
422 |
|
|
return 4;
|
423 |
|
|
}
|
424 |
|
|
};
|
425 |
|
|
|
426 |
|
|
|
427 |
|
|
/**
|
428 |
|
|
* @brief AND.
|
429 |
|
|
*/
|
430 |
|
|
static const char *AND_OPCODES[2] = {
|
431 |
|
|
"????0000000?????????????????????",
|
432 |
|
|
"????0010000?????????????????????"
|
433 |
|
|
};
|
434 |
|
|
|
435 |
|
|
class AND : public ArmDataProcessingInstruction {
|
436 |
|
|
public:
|
437 |
|
|
AND(CpuCortex_Functional *icpu, int opidx) :
|
438 |
|
|
ArmDataProcessingInstruction(icpu, "AND", AND_OPCODES[opidx]) {}
|
439 |
|
|
protected:
|
440 |
|
|
virtual EOperationResult do_operation(uint32_t A, uint32_t M,
|
441 |
|
|
uint32_t *pRes) {
|
442 |
|
|
*pRes = A & M;
|
443 |
|
|
return OP_Write;
|
444 |
|
|
}
|
445 |
|
|
};
|
446 |
|
|
|
447 |
|
|
/**
|
448 |
|
|
* @brief EOR.
|
449 |
|
|
*/
|
450 |
|
|
static const char *EOR_OPCODES[2] = {
|
451 |
|
|
"????0000001?????????????????????",
|
452 |
|
|
"????0010001?????????????????????"
|
453 |
|
|
};
|
454 |
|
|
|
455 |
|
|
class EOR : public ArmDataProcessingInstruction {
|
456 |
|
|
public:
|
457 |
|
|
EOR(CpuCortex_Functional *icpu, int opidx) :
|
458 |
|
|
ArmDataProcessingInstruction(icpu, "EOR", EOR_OPCODES[opidx]) {}
|
459 |
|
|
protected:
|
460 |
|
|
virtual EOperationResult do_operation(uint32_t A, uint32_t M,
|
461 |
|
|
uint32_t *pRes) {
|
462 |
|
|
*pRes = A ^ M;
|
463 |
|
|
return OP_Write;
|
464 |
|
|
}
|
465 |
|
|
};
|
466 |
|
|
|
467 |
|
|
/**
|
468 |
|
|
* @brief Subtruct.
|
469 |
|
|
*/
|
470 |
|
|
static const char *SUB_OPCODES[2] = {
|
471 |
|
|
"????0000010?????????????????????",
|
472 |
|
|
"????0010010?????????????????????"
|
473 |
|
|
};
|
474 |
|
|
|
475 |
|
|
class SUB : public ArmSubInstruction {
|
476 |
|
|
public:
|
477 |
|
|
SUB(CpuCortex_Functional *icpu, int opidx) :
|
478 |
|
|
ArmSubInstruction(icpu, "SUB", SUB_OPCODES[opidx]) {}
|
479 |
|
|
protected:
|
480 |
|
|
virtual bool is_inverted() { return false; }
|
481 |
|
|
virtual bool with_carry() { return false; }
|
482 |
|
|
virtual EOperationResult op_result() { return OP_Write; }
|
483 |
|
|
};
|
484 |
|
|
|
485 |
|
|
/**
|
486 |
|
|
* @brief Subtruct right.
|
487 |
|
|
*/
|
488 |
|
|
static const char *RSB_OPCODES[2] = {
|
489 |
|
|
"????0000011?????????????????????",
|
490 |
|
|
"????0010011?????????????????????"
|
491 |
|
|
};
|
492 |
|
|
|
493 |
|
|
class RSB : public ArmSubInstruction {
|
494 |
|
|
public:
|
495 |
|
|
RSB(CpuCortex_Functional *icpu, int opidx) :
|
496 |
|
|
ArmSubInstruction(icpu, "RSB", RSB_OPCODES[opidx]) {}
|
497 |
|
|
protected:
|
498 |
|
|
virtual bool is_inverted() { return true; }
|
499 |
|
|
virtual bool with_carry() { return false; }
|
500 |
|
|
virtual EOperationResult op_result() { return OP_Write; }
|
501 |
|
|
};
|
502 |
|
|
|
503 |
|
|
/**
|
504 |
|
|
* @brief Addition.
|
505 |
|
|
*/
|
506 |
|
|
static const char *ADD_OPCODES[2] = {
|
507 |
|
|
"????0000100?????????????????????",
|
508 |
|
|
"????0010100?????????????????????"
|
509 |
|
|
};
|
510 |
|
|
|
511 |
|
|
class ADD : public ArmAddInstruction {
|
512 |
|
|
public:
|
513 |
|
|
ADD(CpuCortex_Functional *icpu, int opidx) :
|
514 |
|
|
ArmAddInstruction(icpu, "ADD", ADD_OPCODES[opidx]) {}
|
515 |
|
|
protected:
|
516 |
|
|
virtual EOperationResult op_result() { return OP_Write; }
|
517 |
|
|
virtual bool with_carry() { return false; }
|
518 |
|
|
};
|
519 |
|
|
|
520 |
|
|
/**
|
521 |
|
|
* @brief Addition with carry bit.
|
522 |
|
|
*/
|
523 |
|
|
static const char *ADC_OPCODES[2] = {
|
524 |
|
|
"????0000101?????????????????????",
|
525 |
|
|
"????0010101?????????????????????"
|
526 |
|
|
};
|
527 |
|
|
|
528 |
|
|
class ADC : public ArmAddInstruction {
|
529 |
|
|
public:
|
530 |
|
|
ADC(CpuCortex_Functional *icpu, int opidx) :
|
531 |
|
|
ArmAddInstruction(icpu, "ADC", ADC_OPCODES[opidx]) {}
|
532 |
|
|
protected:
|
533 |
|
|
virtual EOperationResult op_result() { return OP_Write; }
|
534 |
|
|
virtual bool with_carry() { return true; }
|
535 |
|
|
};
|
536 |
|
|
|
537 |
|
|
/**
|
538 |
|
|
* @brief Subtruct with carry bit: Op1 - Op2 + C - 1 !!!!!!.
|
539 |
|
|
*/
|
540 |
|
|
static const char *SBC_OPCODES[2] = {
|
541 |
|
|
"????0000110?????????????????????",
|
542 |
|
|
"????0010110?????????????????????"
|
543 |
|
|
};
|
544 |
|
|
|
545 |
|
|
class SBC : public ArmSubInstruction {
|
546 |
|
|
public:
|
547 |
|
|
SBC(CpuCortex_Functional *icpu, int opidx) :
|
548 |
|
|
ArmSubInstruction(icpu, "SBC", SBC_OPCODES[opidx]) {}
|
549 |
|
|
protected:
|
550 |
|
|
virtual bool is_inverted() { return false; }
|
551 |
|
|
virtual bool with_carry() { return true; }
|
552 |
|
|
virtual EOperationResult op_result() { return OP_Write; }
|
553 |
|
|
};
|
554 |
|
|
|
555 |
|
|
/**
|
556 |
|
|
* @brief Subtruct right with carry bit: Op2 - Op1 + C - 1 !!!!.
|
557 |
|
|
*/
|
558 |
|
|
static const char *RSC_OPCODES[2] = {
|
559 |
|
|
"????0000111?????????????????????",
|
560 |
|
|
"????0010111?????????????????????"
|
561 |
|
|
};
|
562 |
|
|
|
563 |
|
|
class RSC : public ArmSubInstruction {
|
564 |
|
|
public:
|
565 |
|
|
RSC(CpuCortex_Functional *icpu, int opidx) :
|
566 |
|
|
ArmSubInstruction(icpu, "RSC", RSC_OPCODES[opidx]) {}
|
567 |
|
|
protected:
|
568 |
|
|
virtual bool is_inverted() { return true; }
|
569 |
|
|
virtual bool with_carry() { return true; }
|
570 |
|
|
virtual EOperationResult op_result() { return OP_Write; }
|
571 |
|
|
};
|
572 |
|
|
|
573 |
|
|
/**
|
574 |
|
|
* @brief Set condition codes on Op1 AND Op2.
|
575 |
|
|
* S-flag must be set otherwise it can be MOVW instruction
|
576 |
|
|
*/
|
577 |
|
|
static const char *TST_OPCODES[2] = {
|
578 |
|
|
"????00010001????????????????????",
|
579 |
|
|
"????00110001????????????????????"
|
580 |
|
|
};
|
581 |
|
|
|
582 |
|
|
class TST : public ArmDataProcessingInstruction {
|
583 |
|
|
public:
|
584 |
|
|
TST(CpuCortex_Functional *icpu, int opidx) :
|
585 |
|
|
ArmDataProcessingInstruction(icpu, "TST", TST_OPCODES[opidx]) {}
|
586 |
|
|
protected:
|
587 |
|
|
virtual EOperationResult do_operation(uint32_t A, uint32_t M,
|
588 |
|
|
uint32_t *pRes) {
|
589 |
|
|
*pRes = A & M;
|
590 |
|
|
return OP_Drop;
|
591 |
|
|
}
|
592 |
|
|
};
|
593 |
|
|
|
594 |
|
|
/**
|
595 |
|
|
* @brief Set condition codes on Op1 EOR Op2.
|
596 |
|
|
*/
|
597 |
|
|
static const char *TEQ_OPCODES[2] = {
|
598 |
|
|
"????0001001?????????????????????",
|
599 |
|
|
"????0011001?????????????????????"
|
600 |
|
|
};
|
601 |
|
|
|
602 |
|
|
class TEQ : public ArmDataProcessingInstruction {
|
603 |
|
|
public:
|
604 |
|
|
TEQ(CpuCortex_Functional *icpu, int opidx) :
|
605 |
|
|
ArmDataProcessingInstruction(icpu, "TEQ", TEQ_OPCODES[opidx]) {}
|
606 |
|
|
protected:
|
607 |
|
|
virtual EOperationResult do_operation(uint32_t A, uint32_t M,
|
608 |
|
|
uint32_t *pRes) {
|
609 |
|
|
*pRes = A ^ M;
|
610 |
|
|
return OP_Drop;
|
611 |
|
|
}
|
612 |
|
|
};
|
613 |
|
|
|
614 |
|
|
/**
|
615 |
|
|
* @brief Set condition codes on Op1 - Op2.
|
616 |
|
|
*/
|
617 |
|
|
static const char *CMP_OPCODES[2] = {
|
618 |
|
|
"????0001010?????????????????????",
|
619 |
|
|
"????0011010?????????????????????"
|
620 |
|
|
};
|
621 |
|
|
|
622 |
|
|
class CMP : public ArmSubInstruction {
|
623 |
|
|
public:
|
624 |
|
|
CMP(CpuCortex_Functional *icpu, int opidx) :
|
625 |
|
|
ArmSubInstruction(icpu, "CMP", CMP_OPCODES[opidx]) {}
|
626 |
|
|
protected:
|
627 |
|
|
virtual bool is_inverted() { return false; }
|
628 |
|
|
virtual bool with_carry() { return false; }
|
629 |
|
|
virtual EOperationResult op_result() { return OP_Drop; }
|
630 |
|
|
};
|
631 |
|
|
|
632 |
|
|
/**
|
633 |
|
|
* @brief Set condition codes on Op1 + Op2.
|
634 |
|
|
*/
|
635 |
|
|
static const char *CMN_OPCODES[2] = {
|
636 |
|
|
"????0001011?????????????????????",
|
637 |
|
|
"????0011011?????????????????????"
|
638 |
|
|
};
|
639 |
|
|
|
640 |
|
|
class CMN : public ArmAddInstruction {
|
641 |
|
|
public:
|
642 |
|
|
CMN(CpuCortex_Functional *icpu, int opidx) :
|
643 |
|
|
ArmAddInstruction(icpu, "CMN", CMN_OPCODES[opidx]) {}
|
644 |
|
|
protected:
|
645 |
|
|
virtual bool with_carry() { return false; }
|
646 |
|
|
virtual EOperationResult op_result() { return OP_Drop; }
|
647 |
|
|
};
|
648 |
|
|
|
649 |
|
|
/**
|
650 |
|
|
* @brief OR
|
651 |
|
|
*/
|
652 |
|
|
static const char *ORR_OPCODES[2] = {
|
653 |
|
|
"????0001100?????????????????????",
|
654 |
|
|
"????0011100?????????????????????"
|
655 |
|
|
};
|
656 |
|
|
|
657 |
|
|
class ORR : public ArmDataProcessingInstruction {
|
658 |
|
|
public:
|
659 |
|
|
ORR(CpuCortex_Functional *icpu, int opidx) :
|
660 |
|
|
ArmDataProcessingInstruction(icpu, "ORR", ORR_OPCODES[opidx]) {}
|
661 |
|
|
protected:
|
662 |
|
|
virtual EOperationResult do_operation(uint32_t A, uint32_t M,
|
663 |
|
|
uint32_t *pRes) {
|
664 |
|
|
*pRes = A | M;
|
665 |
|
|
return OP_Write;
|
666 |
|
|
}
|
667 |
|
|
};
|
668 |
|
|
|
669 |
|
|
/**
|
670 |
|
|
* @brief Move data: Rd = Op2
|
671 |
|
|
*/
|
672 |
|
|
static const char *MOV_OPCODES[2] = {
|
673 |
|
|
"????0001101?????????????????????",
|
674 |
|
|
"????0011101?????????????????????"
|
675 |
|
|
};
|
676 |
|
|
|
677 |
|
|
class MOV : public ArmDataProcessingInstruction {
|
678 |
|
|
public:
|
679 |
|
|
MOV(CpuCortex_Functional *icpu, int opidx) :
|
680 |
|
|
ArmDataProcessingInstruction(icpu, "MOV", MOV_OPCODES[opidx]) {}
|
681 |
|
|
protected:
|
682 |
|
|
virtual EOperationResult do_operation(uint32_t A, uint32_t M,
|
683 |
|
|
uint32_t *pRes) {
|
684 |
|
|
*pRes = M;
|
685 |
|
|
return OP_Write;
|
686 |
|
|
}
|
687 |
|
|
};
|
688 |
|
|
|
689 |
|
|
/** Move Top writes an immediate value to the top halfword of the destination
|
690 |
|
|
register. It does not affect the contents of the bottom halfword. */
|
691 |
|
|
class MOVT : public ArmInstruction {
|
692 |
|
|
public:
|
693 |
|
|
MOVT(CpuCortex_Functional *icpu) :
|
694 |
|
|
ArmInstruction(icpu, "MOVT", "????00110100????????????????????") {}
|
695 |
|
|
protected:
|
696 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
697 |
|
|
DataProcessingType u;
|
698 |
|
|
u.value = payload->buf32[0];
|
699 |
|
|
uint32_t imm16 = (u.mov_bits.imm4 << 12) | u.mov_bits.imm12;
|
700 |
|
|
R[u.mov_bits.rd] &= ~0xFFFF0000;
|
701 |
|
|
R[u.mov_bits.rd] |= (imm16 << 16);
|
702 |
|
|
return 4;
|
703 |
|
|
}
|
704 |
|
|
};
|
705 |
|
|
|
706 |
|
|
/** This new variant of MOV (immediate) writes a 16-bit immediate
|
707 |
|
|
value to the destination register */
|
708 |
|
|
class MOVW : public ArmInstruction {
|
709 |
|
|
public:
|
710 |
|
|
MOVW(CpuCortex_Functional *icpu) :
|
711 |
|
|
ArmInstruction(icpu, "MOVW", "????00110000????????????????????") {}
|
712 |
|
|
protected:
|
713 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
714 |
|
|
DataProcessingType u;
|
715 |
|
|
u.value = payload->buf32[0];
|
716 |
|
|
uint32_t imm16 = (u.mov_bits.imm4 << 12) | u.mov_bits.imm12;
|
717 |
|
|
R[u.mov_bits.rd] &= ~0xFFFF;
|
718 |
|
|
R[u.mov_bits.rd] |= imm16;
|
719 |
|
|
return 4;
|
720 |
|
|
}
|
721 |
|
|
};
|
722 |
|
|
|
723 |
|
|
/** Rd:=Rm*Rs. */
|
724 |
|
|
class MUL : public MultiplyInstruction {
|
725 |
|
|
public:
|
726 |
|
|
MUL(CpuCortex_Functional *icpu) : MultiplyInstruction(icpu,
|
727 |
|
|
"MUL", "????0000000?????????????1001????") {}
|
728 |
|
|
};
|
729 |
|
|
|
730 |
|
|
/** Multiply and accumulate: Rd:=Rm*Rs+Rn */
|
731 |
|
|
class MLA : public MultiplyInstruction {
|
732 |
|
|
public:
|
733 |
|
|
MLA(CpuCortex_Functional *icpu) : MultiplyInstruction(icpu,
|
734 |
|
|
"MLA", "????0000001?????????????1001????") {}
|
735 |
|
|
};
|
736 |
|
|
|
737 |
|
|
/** Unsigned Multiply Long */
|
738 |
|
|
class UMULL : public MultiplyLongInstruction {
|
739 |
|
|
public:
|
740 |
|
|
UMULL(CpuCortex_Functional *icpu) : MultiplyLongInstruction(icpu,
|
741 |
|
|
"UMULL", "????0000100?????????????1001????") {}
|
742 |
|
|
};
|
743 |
|
|
|
744 |
|
|
/** Unsigned Multiply ^ Accumulate Long */
|
745 |
|
|
class UMLAL : public MultiplyLongInstruction {
|
746 |
|
|
public:
|
747 |
|
|
UMLAL(CpuCortex_Functional *icpu) : MultiplyLongInstruction(icpu,
|
748 |
|
|
"UMLAL", "????0000101?????????????1001????") {}
|
749 |
|
|
};
|
750 |
|
|
|
751 |
|
|
/** Signed Multiply Long */
|
752 |
|
|
class SMULL : public MultiplyLongInstruction {
|
753 |
|
|
public:
|
754 |
|
|
SMULL(CpuCortex_Functional *icpu) : MultiplyLongInstruction(icpu,
|
755 |
|
|
"SMULL", "????0000110?????????????1001????") {}
|
756 |
|
|
};
|
757 |
|
|
|
758 |
|
|
/** Signed Multiply ^ Accumulate Long */
|
759 |
|
|
class SMLAL : public MultiplyLongInstruction {
|
760 |
|
|
public:
|
761 |
|
|
SMLAL(CpuCortex_Functional *icpu) : MultiplyLongInstruction(icpu,
|
762 |
|
|
"SMLAL", "????0000111?????????????1001????") {}
|
763 |
|
|
};
|
764 |
|
|
|
765 |
|
|
/**
|
766 |
|
|
* @brief Bit clear: AND NOT
|
767 |
|
|
*/
|
768 |
|
|
static const char *BIC_OPCODES[2] = {
|
769 |
|
|
"????0001110?????????????????????",
|
770 |
|
|
"????0011110?????????????????????"
|
771 |
|
|
};
|
772 |
|
|
|
773 |
|
|
class BIC : public ArmDataProcessingInstruction {
|
774 |
|
|
public:
|
775 |
|
|
BIC(CpuCortex_Functional *icpu, int opidx) :
|
776 |
|
|
ArmDataProcessingInstruction(icpu, "BIC", BIC_OPCODES[opidx]) {}
|
777 |
|
|
protected:
|
778 |
|
|
virtual EOperationResult do_operation(uint32_t A, uint32_t M,
|
779 |
|
|
uint32_t *pRes) {
|
780 |
|
|
*pRes = A & ~M;
|
781 |
|
|
return OP_Write;
|
782 |
|
|
}
|
783 |
|
|
};
|
784 |
|
|
|
785 |
|
|
/**
|
786 |
|
|
* @brief Move inverted data: Rd = NOT Op2
|
787 |
|
|
*/
|
788 |
|
|
static const char *MVN_OPCODES[2] = {
|
789 |
|
|
"????0001111?????????????????????",
|
790 |
|
|
"????0011111?????????????????????"
|
791 |
|
|
};
|
792 |
|
|
|
793 |
|
|
class MVN : public ArmDataProcessingInstruction {
|
794 |
|
|
public:
|
795 |
|
|
MVN(CpuCortex_Functional *icpu, int opidx) :
|
796 |
|
|
ArmDataProcessingInstruction(icpu, "MVN", MVN_OPCODES[opidx]) {}
|
797 |
|
|
protected:
|
798 |
|
|
virtual EOperationResult do_operation(uint32_t A, uint32_t M,
|
799 |
|
|
uint32_t *pRes) {
|
800 |
|
|
*pRes = ~M;
|
801 |
|
|
return OP_Write;
|
802 |
|
|
}
|
803 |
|
|
};
|
804 |
|
|
|
805 |
|
|
/** Branch */
|
806 |
|
|
class B : public ArmInstruction {
|
807 |
|
|
public:
|
808 |
|
|
B(CpuCortex_Functional *icpu) :
|
809 |
|
|
ArmInstruction(icpu, "B", "????1010????????????????????????") {}
|
810 |
|
|
|
811 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
812 |
|
|
BranchType u;
|
813 |
|
|
u.value = payload->buf32[0];
|
814 |
|
|
uint32_t off = u.bits.offset;
|
815 |
|
|
if ((u.value >> 23) & 0x1) {
|
816 |
|
|
off |= 0xFF000000;
|
817 |
|
|
}
|
818 |
|
|
off = static_cast<uint32_t>(
|
819 |
|
|
R[Reg_pc] + (off << 2) + PREFETCH_OFFSET[icpu_->getInstrMode()]);
|
820 |
|
|
R[Reg_pc] = off;
|
821 |
|
|
icpu_->setBranch(off);
|
822 |
|
|
return 4;
|
823 |
|
|
}
|
824 |
|
|
};
|
825 |
|
|
|
826 |
|
|
/** Branch with Link */
|
827 |
|
|
class BL : public ArmInstruction {
|
828 |
|
|
public:
|
829 |
|
|
BL(CpuCortex_Functional *icpu) :
|
830 |
|
|
ArmInstruction(icpu, "BL", "????1011????????????????????????") {}
|
831 |
|
|
|
832 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
833 |
|
|
BranchType u;
|
834 |
|
|
u.value = payload->buf32[0];
|
835 |
|
|
R[Reg_lr] = R[Reg_pc] + 4;
|
836 |
|
|
uint32_t off = u.bits.offset;
|
837 |
|
|
if ((u.value >> 23) & 0x1) {
|
838 |
|
|
off |= 0xFF000000;
|
839 |
|
|
}
|
840 |
|
|
off = static_cast<uint32_t>(
|
841 |
|
|
R[Reg_pc] + (off << 2) + PREFETCH_OFFSET[icpu_->getInstrMode()]);
|
842 |
|
|
R[Reg_pc] = off;
|
843 |
|
|
icpu_->setBranch(off);
|
844 |
|
|
return 4;
|
845 |
|
|
}
|
846 |
|
|
};
|
847 |
|
|
|
848 |
|
|
/** Branch and Exchange */
|
849 |
|
|
class BX : public ArmInstruction {
|
850 |
|
|
public:
|
851 |
|
|
BX(CpuCortex_Functional *icpu) :
|
852 |
|
|
ArmInstruction(icpu, "BX", "????000100101111111111110001????") {}
|
853 |
|
|
|
854 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
855 |
|
|
BranchType u;
|
856 |
|
|
u.value = payload->buf32[0];
|
857 |
|
|
uint32_t off = static_cast<uint32_t>(R[u.bits.offset & 0xf]);
|
858 |
|
|
if (off & 0x1) {
|
859 |
|
|
icpu_->setInstrMode(THUMB_mode);
|
860 |
|
|
} else {
|
861 |
|
|
icpu_->setInstrMode(ARM_mode);
|
862 |
|
|
}
|
863 |
|
|
R[Reg_pc] = off;
|
864 |
|
|
icpu_->setBranch(off);
|
865 |
|
|
return 4;
|
866 |
|
|
}
|
867 |
|
|
};
|
868 |
|
|
|
869 |
|
|
/** Load word pre-adding immediate offset to base register */
|
870 |
|
|
static const char *LDR_OPCODES[4] = {
|
871 |
|
|
"????0100???1????????????????????", // immedaiate, post incr
|
872 |
|
|
"????0101???1????????????????????", // immedaiate, pre incr
|
873 |
|
|
"????0110???1????????????????????", // shift reg, post incr
|
874 |
|
|
"????0111???1????????????????????", // shift reg, pre incr
|
875 |
|
|
};
|
876 |
|
|
|
877 |
|
|
class LDR : public SingleDataTransferInstruction {
|
878 |
|
|
public:
|
879 |
|
|
LDR(CpuCortex_Functional *icpu, int opidx) :
|
880 |
|
|
SingleDataTransferInstruction(icpu, "LDR", LDR_OPCODES[opidx]) {}
|
881 |
|
|
};
|
882 |
|
|
|
883 |
|
|
/** Load Signed Byte */
|
884 |
|
|
static const char *LDRSB_OPCODES[4] = {
|
885 |
|
|
"????0000???1????????????1101????", // post incr
|
886 |
|
|
"????0001???1????????????1101????", // pre incr
|
887 |
|
|
};
|
888 |
|
|
|
889 |
|
|
class LDRSB : public HWordSignedDataTransferInstruction {
|
890 |
|
|
public:
|
891 |
|
|
LDRSB(CpuCortex_Functional *icpu, int opidx) :
|
892 |
|
|
HWordSignedDataTransferInstruction(icpu, "LDRSB", LDRSB_OPCODES[opidx])
|
893 |
|
|
{}
|
894 |
|
|
};
|
895 |
|
|
|
896 |
|
|
/** Load Unsigned Half-Word */
|
897 |
|
|
static const char *LDRH_OPCODES[4] = {
|
898 |
|
|
"????0000???1????????????1011????", // post incr
|
899 |
|
|
"????0001???1????????????1011????", // pre incr
|
900 |
|
|
};
|
901 |
|
|
|
902 |
|
|
class LDRH : public HWordSignedDataTransferInstruction {
|
903 |
|
|
public:
|
904 |
|
|
LDRH(CpuCortex_Functional *icpu, int opidx) :
|
905 |
|
|
HWordSignedDataTransferInstruction(icpu, "LDRH", LDRH_OPCODES[opidx])
|
906 |
|
|
{}
|
907 |
|
|
};
|
908 |
|
|
|
909 |
|
|
/** Load Signed Half-word */
|
910 |
|
|
static const char *LDRSH_OPCODES[4] = {
|
911 |
|
|
"????0000???1????????????1111????", // post incr
|
912 |
|
|
"????0001???1????????????1111????", // pre incr
|
913 |
|
|
};
|
914 |
|
|
|
915 |
|
|
class LDRSH : public HWordSignedDataTransferInstruction {
|
916 |
|
|
public:
|
917 |
|
|
LDRSH(CpuCortex_Functional *icpu, int opidx) :
|
918 |
|
|
HWordSignedDataTransferInstruction(icpu, "LDRSH", LDRSB_OPCODES[opidx])
|
919 |
|
|
{}
|
920 |
|
|
};
|
921 |
|
|
|
922 |
|
|
/** Load Block data */
|
923 |
|
|
static const char *LDM_OPCODES[4] = {
|
924 |
|
|
"????1000???1????????????????????", // post incr
|
925 |
|
|
"????1001???1????????????????????", // pre incr
|
926 |
|
|
};
|
927 |
|
|
|
928 |
|
|
class LDM : public BlockDataTransferInstruction {
|
929 |
|
|
public:
|
930 |
|
|
LDM(CpuCortex_Functional *icpu, int opidx) :
|
931 |
|
|
BlockDataTransferInstruction(icpu, "LDM", LDM_OPCODES[opidx]) {}
|
932 |
|
|
};
|
933 |
|
|
|
934 |
|
|
|
935 |
|
|
|
936 |
|
|
/** Store word */
|
937 |
|
|
static const char *STR_OPCODES[4] = {
|
938 |
|
|
"????0100?0?0????????????????????", // immedaiate, post incr
|
939 |
|
|
"????0101?0?0????????????????????", // immedaiate, pre incr
|
940 |
|
|
"????0110?0?0????????????????????", // shift reg, post incr
|
941 |
|
|
"????0111?0?0????????????????????", // shift reg, pre incr
|
942 |
|
|
};
|
943 |
|
|
|
944 |
|
|
class STR : public SingleDataTransferInstruction {
|
945 |
|
|
public:
|
946 |
|
|
STR(CpuCortex_Functional *icpu, int opidx) :
|
947 |
|
|
SingleDataTransferInstruction(icpu, "STR", STR_OPCODES[opidx]) {}
|
948 |
|
|
};
|
949 |
|
|
|
950 |
|
|
/** Store Byte */
|
951 |
|
|
static const char *STRB_OPCODES[4] = {
|
952 |
|
|
"????0100?1?0????????????????????", // immedaiate, post incr
|
953 |
|
|
"????0101?1?0????????????????????", // immedaiate, pre incr
|
954 |
|
|
"????0110?1?0????????????????????", // shift reg, post incr
|
955 |
|
|
"????0111?1?0????????????????????", // shift reg, pre incr
|
956 |
|
|
};
|
957 |
|
|
|
958 |
|
|
class STRB : public SingleDataTransferInstruction {
|
959 |
|
|
public:
|
960 |
|
|
STRB(CpuCortex_Functional *icpu, int opidx) :
|
961 |
|
|
SingleDataTransferInstruction(icpu, "STRB", STRB_OPCODES[opidx]) {}
|
962 |
|
|
};
|
963 |
|
|
|
964 |
|
|
/** Store Half-Word */
|
965 |
|
|
static const char *STRH_OPCODES[4] = {
|
966 |
|
|
"????0000???0????????????1?11????", // post incr
|
967 |
|
|
"????0001???0????????????1?11????", // pre incr
|
968 |
|
|
};
|
969 |
|
|
|
970 |
|
|
class STRH : public HWordSignedDataTransferInstruction {
|
971 |
|
|
public:
|
972 |
|
|
STRH(CpuCortex_Functional *icpu, int opidx) :
|
973 |
|
|
HWordSignedDataTransferInstruction(icpu, "STRH", STRH_OPCODES[opidx])
|
974 |
|
|
{}
|
975 |
|
|
};
|
976 |
|
|
|
977 |
|
|
/** Store Block data */
|
978 |
|
|
static const char *STM_OPCODES[4] = {
|
979 |
|
|
"????1000???0????????????????????", // post incr
|
980 |
|
|
"????1001???0????????????????????", // pre incr
|
981 |
|
|
};
|
982 |
|
|
|
983 |
|
|
class STM : public BlockDataTransferInstruction {
|
984 |
|
|
public:
|
985 |
|
|
STM(CpuCortex_Functional *icpu, int opidx) :
|
986 |
|
|
BlockDataTransferInstruction(icpu, "STM", STM_OPCODES[opidx]) {}
|
987 |
|
|
};
|
988 |
|
|
|
989 |
|
|
/** Move from coprocessor to ARM7TDMI-S register (L=1) */
|
990 |
|
|
class MRC : public ArmInstruction {
|
991 |
|
|
public:
|
992 |
|
|
MRC(CpuCortex_Functional *icpu) :
|
993 |
|
|
ArmInstruction(icpu, "MRC", "????1110???1???????????????1????") {}
|
994 |
|
|
|
995 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
996 |
|
|
CoprocessorTransferType u;
|
997 |
|
|
u.value = payload->buf32[0];
|
998 |
|
|
return 4;
|
999 |
|
|
}
|
1000 |
|
|
};
|
1001 |
|
|
|
1002 |
|
|
/** Move from ARM7TDMI-S register to coprocessor (L=0) */
|
1003 |
|
|
class MCR : public ArmInstruction {
|
1004 |
|
|
public:
|
1005 |
|
|
MCR(CpuCortex_Functional *icpu) :
|
1006 |
|
|
ArmInstruction(icpu, "MRC", "????1110???0???????????????1????") {}
|
1007 |
|
|
|
1008 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1009 |
|
|
CoprocessorTransferType u;
|
1010 |
|
|
u.value = payload->buf32[0];
|
1011 |
|
|
return 4;
|
1012 |
|
|
}
|
1013 |
|
|
};
|
1014 |
|
|
|
1015 |
|
|
/**
|
1016 |
|
|
* @brief Transfer register to PSR flags.
|
1017 |
|
|
*/
|
1018 |
|
|
static const char *MSR_OPCODES[2] = {
|
1019 |
|
|
"????00010?10????1111????????????",
|
1020 |
|
|
"????00110?10????1111????????????"
|
1021 |
|
|
};
|
1022 |
|
|
|
1023 |
|
|
class MSR : public ArmInstruction {
|
1024 |
|
|
public:
|
1025 |
|
|
MSR(CpuCortex_Functional *icpu, int opidx) :
|
1026 |
|
|
ArmInstruction(icpu, "MSR", MSR_OPCODES[opidx]) {}
|
1027 |
|
|
|
1028 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1029 |
|
|
PsrTransferType u;
|
1030 |
|
|
u.value = payload->buf32[0];
|
1031 |
|
|
return 4;
|
1032 |
|
|
}
|
1033 |
|
|
};
|
1034 |
|
|
|
1035 |
|
|
class MRS : public ArmInstruction {
|
1036 |
|
|
public:
|
1037 |
|
|
MRS(CpuCortex_Functional *icpu) :
|
1038 |
|
|
ArmInstruction(icpu, "MRS", "????00010?001111????000000000000") {}
|
1039 |
|
|
|
1040 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1041 |
|
|
PsrTransferType u;
|
1042 |
|
|
u.value = payload->buf32[0];
|
1043 |
|
|
return 4;
|
1044 |
|
|
}
|
1045 |
|
|
};
|
1046 |
|
|
|
1047 |
|
|
class NOP : public ArmInstruction {
|
1048 |
|
|
public:
|
1049 |
|
|
NOP(CpuCortex_Functional *icpu) :
|
1050 |
|
|
ArmInstruction(icpu, "NOP", "????0011001000001111000000000000") {}
|
1051 |
|
|
|
1052 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1053 |
|
|
return 4;
|
1054 |
|
|
}
|
1055 |
|
|
};
|
1056 |
|
|
|
1057 |
|
|
/** Bytes zero-extending
|
1058 |
|
|
UXTB extracts an 8-bit value from a register and zero extends it to 32 bits.
|
1059 |
|
|
You can specify a rotation by 0, 8, 16, or 24 bits before extracting
|
1060 |
|
|
the 8-bit value.
|
1061 |
|
|
*/
|
1062 |
|
|
class UXTB : public ArmInstruction {
|
1063 |
|
|
public:
|
1064 |
|
|
UXTB(CpuCortex_Functional *icpu) :
|
1065 |
|
|
ArmInstruction(icpu, "UXTB", "????011011101111????????0111????") {}
|
1066 |
|
|
|
1067 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1068 |
|
|
SignExtendType u;
|
1069 |
|
|
u.value = payload->buf32[0];
|
1070 |
|
|
uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
|
1071 |
|
|
t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
|
1072 |
|
|
t1 &= 0xFF;
|
1073 |
|
|
R[u.bits.rd] = static_cast<uint32_t>(t1);
|
1074 |
|
|
return 4;
|
1075 |
|
|
}
|
1076 |
|
|
};
|
1077 |
|
|
|
1078 |
|
|
/** */
|
1079 |
|
|
class UXTAB : public ArmInstruction {
|
1080 |
|
|
public:
|
1081 |
|
|
UXTAB(CpuCortex_Functional *icpu) :
|
1082 |
|
|
ArmInstruction(icpu, "UXTAB", "????01101110????????????0111????") {}
|
1083 |
|
|
|
1084 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1085 |
|
|
SignExtendType u;
|
1086 |
|
|
u.value = payload->buf32[0];
|
1087 |
|
|
uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
|
1088 |
|
|
t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
|
1089 |
|
|
t1 &= 0xFF;
|
1090 |
|
|
R[u.bits.rd] = R[u.bits.rn] + static_cast<uint32_t>(t1);
|
1091 |
|
|
return 4;
|
1092 |
|
|
}
|
1093 |
|
|
};
|
1094 |
|
|
|
1095 |
|
|
/** UXTB16 extracts two 8-bit values from a register and zero extends them
|
1096 |
|
|
to 16 bits each. You can specify a rotation by 0, 8, 16, or 24 bits before
|
1097 |
|
|
extracting the 8-bit values.
|
1098 |
|
|
*/
|
1099 |
|
|
class UXTB16 : public ArmInstruction {
|
1100 |
|
|
public:
|
1101 |
|
|
UXTB16(CpuCortex_Functional *icpu) :
|
1102 |
|
|
ArmInstruction(icpu, "UXTB16", "????011011001111????????0111????") {}
|
1103 |
|
|
|
1104 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1105 |
|
|
SignExtendType u;
|
1106 |
|
|
u.value = payload->buf32[0];
|
1107 |
|
|
uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
|
1108 |
|
|
t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
|
1109 |
|
|
t1 &= 0x00FF00FF;
|
1110 |
|
|
R[u.bits.rd] = static_cast<uint32_t>(t1);
|
1111 |
|
|
return 4;
|
1112 |
|
|
}
|
1113 |
|
|
};
|
1114 |
|
|
|
1115 |
|
|
/** UXTAB16 extracts two 8-bit values from a register, zero extends them
|
1116 |
|
|
to 16 bits each, and adds the results to the two values from another
|
1117 |
|
|
register. You can specify a rotation by 0, 8, 16, or 24 bits before
|
1118 |
|
|
extracting the 8-bit values.
|
1119 |
|
|
*/
|
1120 |
|
|
class UXTAB16 : public ArmInstruction {
|
1121 |
|
|
public:
|
1122 |
|
|
UXTAB16(CpuCortex_Functional *icpu) :
|
1123 |
|
|
ArmInstruction(icpu, "UXTAB16", "????01101100????????????0111????") {}
|
1124 |
|
|
|
1125 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1126 |
|
|
SignExtendType u;
|
1127 |
|
|
u.value = payload->buf32[0];
|
1128 |
|
|
uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
|
1129 |
|
|
t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
|
1130 |
|
|
uint32_t a = (R[u.bits.rd] & 0xFFFF) + (t1 & 0xFF);
|
1131 |
|
|
uint32_t b = ((R[u.bits.rd] >> 16) & 0xFFFF) + ((t1 >> 16) & 0xFF);
|
1132 |
|
|
R[u.bits.rd] = (b << 16) | a;
|
1133 |
|
|
return 4;
|
1134 |
|
|
}
|
1135 |
|
|
};
|
1136 |
|
|
|
1137 |
|
|
|
1138 |
|
|
/** UXTH extracts a 16-bit value from a register and zero extends it
|
1139 |
|
|
to 32 bits. You can specify a rotation by 0, 8, 16, or 24 bits before
|
1140 |
|
|
extracting the 16-bit value.
|
1141 |
|
|
*/
|
1142 |
|
|
class UXTH : public ArmInstruction {
|
1143 |
|
|
public:
|
1144 |
|
|
UXTH(CpuCortex_Functional *icpu) :
|
1145 |
|
|
ArmInstruction(icpu, "UXTH", "????011011111111????????0111????") {}
|
1146 |
|
|
|
1147 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1148 |
|
|
SignExtendType u;
|
1149 |
|
|
u.value = payload->buf32[0];
|
1150 |
|
|
uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
|
1151 |
|
|
t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
|
1152 |
|
|
t1 &= 0xFFFF;
|
1153 |
|
|
R[u.bits.rd] = static_cast<uint32_t>(t1);
|
1154 |
|
|
return 4;
|
1155 |
|
|
}
|
1156 |
|
|
};
|
1157 |
|
|
|
1158 |
|
|
/** UXTAH extracts a 16-bit value from a register, zero extends it to 32 bits,
|
1159 |
|
|
and adds the result to a value in another register. You can specify a
|
1160 |
|
|
rotation by 0, 8, 16, or 24 bits before extracting the 16-bit value.
|
1161 |
|
|
*/
|
1162 |
|
|
class UXTAH : public ArmInstruction {
|
1163 |
|
|
public:
|
1164 |
|
|
UXTAH(CpuCortex_Functional *icpu) :
|
1165 |
|
|
ArmInstruction(icpu, "UXTAH", "????01101111????????????0111????") {}
|
1166 |
|
|
|
1167 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1168 |
|
|
SignExtendType u;
|
1169 |
|
|
u.value = payload->buf32[0];
|
1170 |
|
|
uint64_t t1 = (R[u.bits.rm] & 0xFFFFFFFF) >> (8*u.bits.rotate);
|
1171 |
|
|
t1 = (R[u.bits.rm] << (32 - 8*u.bits.rotate)) | t1;
|
1172 |
|
|
t1 &= 0xFFFF;
|
1173 |
|
|
R[u.bits.rd] = R[u.bits.rn] + static_cast<uint32_t>(t1);
|
1174 |
|
|
return 4;
|
1175 |
|
|
}
|
1176 |
|
|
};
|
1177 |
|
|
|
1178 |
|
|
|
1179 |
|
|
/**
|
1180 |
|
|
* @brief SWI (software breakpoint instruction)
|
1181 |
|
|
*
|
1182 |
|
|
*/
|
1183 |
|
|
class SWI : public ArmInstruction {
|
1184 |
|
|
public:
|
1185 |
|
|
SWI(CpuCortex_Functional *icpu) :
|
1186 |
|
|
ArmInstruction(icpu, "SWI", "????1110???1???????????????1????") {}
|
1187 |
|
|
|
1188 |
|
|
virtual int exec_checked(Reg64Type *payload) {
|
1189 |
|
|
icpu_->raiseSoftwareIrq();
|
1190 |
|
|
return 4;
|
1191 |
|
|
}
|
1192 |
|
|
};
|
1193 |
|
|
|
1194 |
|
|
|
1195 |
|
|
|
1196 |
|
|
void CpuCortex_Functional::addArm7tmdiIsa() {
|
1197 |
|
|
|
1198 |
|
|
// Arm V6 instructions:
|
1199 |
|
|
// CPS, SRS, RFE
|
1200 |
|
|
// REV, REV16, REVSH
|
1201 |
|
|
// SETEND
|
1202 |
|
|
// LDREX, STREX
|
1203 |
|
|
// SXTB, SXTH, UXTB, UXTH
|
1204 |
|
|
addSupportedInstruction(new UXTB(this)); // same opcode as STRB
|
1205 |
|
|
addSupportedInstruction(new UXTAB(this));
|
1206 |
|
|
addSupportedInstruction(new UXTB16(this)); // rn=1111b
|
1207 |
|
|
addSupportedInstruction(new UXTAB16(this)); // rn=????b
|
1208 |
|
|
addSupportedInstruction(new UXTH(this)); // rn=1111b
|
1209 |
|
|
addSupportedInstruction(new UXTAH(this)); // rn=????
|
1210 |
|
|
|
1211 |
|
|
// use the same as opcodes TEQ, TST, CMN and CMP without S-flag
|
1212 |
|
|
// and must be registered first.
|
1213 |
|
|
addSupportedInstruction(new BX(this)); // use TST,MSR opcode
|
1214 |
|
|
addSupportedInstruction(new NOP(this)); // use MSR opcode
|
1215 |
|
|
addSupportedInstruction(new MOVT(this));
|
1216 |
|
|
addSupportedInstruction(new MOVW(this));
|
1217 |
|
|
addSupportedInstruction(new MUL(this));
|
1218 |
|
|
addSupportedInstruction(new MLA(this));
|
1219 |
|
|
addSupportedInstruction(new UMULL(this));
|
1220 |
|
|
addSupportedInstruction(new UMLAL(this));
|
1221 |
|
|
addSupportedInstruction(new SMULL(this));
|
1222 |
|
|
addSupportedInstruction(new SMLAL(this));
|
1223 |
|
|
addSupportedInstruction(new MRS(this));
|
1224 |
|
|
addSupportedInstruction(new MSR(this, 0));
|
1225 |
|
|
addSupportedInstruction(new MSR(this, 1));
|
1226 |
|
|
|
1227 |
|
|
addSupportedInstruction(new AND(this, 0));
|
1228 |
|
|
addSupportedInstruction(new AND(this, 1));
|
1229 |
|
|
addSupportedInstruction(new EOR(this, 0));
|
1230 |
|
|
addSupportedInstruction(new EOR(this, 1));
|
1231 |
|
|
addSupportedInstruction(new SUB(this, 0));
|
1232 |
|
|
addSupportedInstruction(new SUB(this, 1));
|
1233 |
|
|
addSupportedInstruction(new RSB(this, 0));
|
1234 |
|
|
addSupportedInstruction(new RSB(this, 1));
|
1235 |
|
|
addSupportedInstruction(new ADD(this, 0));
|
1236 |
|
|
addSupportedInstruction(new ADD(this, 1));
|
1237 |
|
|
addSupportedInstruction(new ADC(this, 0));
|
1238 |
|
|
addSupportedInstruction(new ADC(this, 1));
|
1239 |
|
|
addSupportedInstruction(new SBC(this, 0));
|
1240 |
|
|
addSupportedInstruction(new SBC(this, 1));
|
1241 |
|
|
addSupportedInstruction(new RSC(this, 0));
|
1242 |
|
|
addSupportedInstruction(new RSC(this, 1));
|
1243 |
|
|
addSupportedInstruction(new TST(this, 0));
|
1244 |
|
|
addSupportedInstruction(new TST(this, 1));
|
1245 |
|
|
addSupportedInstruction(new TEQ(this, 0));
|
1246 |
|
|
addSupportedInstruction(new TEQ(this, 1));
|
1247 |
|
|
addSupportedInstruction(new CMP(this, 0));
|
1248 |
|
|
addSupportedInstruction(new CMP(this, 1));
|
1249 |
|
|
addSupportedInstruction(new CMN(this, 0));
|
1250 |
|
|
addSupportedInstruction(new CMN(this, 1));
|
1251 |
|
|
addSupportedInstruction(new ORR(this, 0));
|
1252 |
|
|
addSupportedInstruction(new ORR(this, 1));
|
1253 |
|
|
addSupportedInstruction(new MOV(this, 0));
|
1254 |
|
|
addSupportedInstruction(new MOV(this, 1));
|
1255 |
|
|
addSupportedInstruction(new BIC(this, 0));
|
1256 |
|
|
addSupportedInstruction(new BIC(this, 1));
|
1257 |
|
|
addSupportedInstruction(new MVN(this, 0));
|
1258 |
|
|
addSupportedInstruction(new MVN(this, 1));
|
1259 |
|
|
addSupportedInstruction(new B(this));
|
1260 |
|
|
addSupportedInstruction(new BL(this));
|
1261 |
|
|
addSupportedInstruction(new LDR(this, 0));
|
1262 |
|
|
addSupportedInstruction(new LDR(this, 1));
|
1263 |
|
|
addSupportedInstruction(new LDR(this, 2));
|
1264 |
|
|
addSupportedInstruction(new LDR(this, 3));
|
1265 |
|
|
addSupportedInstruction(new LDRSB(this, 0));
|
1266 |
|
|
addSupportedInstruction(new LDRSB(this, 1));
|
1267 |
|
|
addSupportedInstruction(new LDRH(this, 0));
|
1268 |
|
|
addSupportedInstruction(new LDRH(this, 1));
|
1269 |
|
|
addSupportedInstruction(new LDRSH(this, 0));
|
1270 |
|
|
addSupportedInstruction(new LDRSH(this, 1));
|
1271 |
|
|
addSupportedInstruction(new LDM(this, 0));
|
1272 |
|
|
addSupportedInstruction(new LDM(this, 1));
|
1273 |
|
|
addSupportedInstruction(new STR(this, 0));
|
1274 |
|
|
addSupportedInstruction(new STR(this, 1));
|
1275 |
|
|
addSupportedInstruction(new STR(this, 2));
|
1276 |
|
|
addSupportedInstruction(new STR(this, 3));
|
1277 |
|
|
addSupportedInstruction(new STRB(this, 0));
|
1278 |
|
|
addSupportedInstruction(new STRB(this, 1));
|
1279 |
|
|
addSupportedInstruction(new STRB(this, 2));
|
1280 |
|
|
addSupportedInstruction(new STRB(this, 3));
|
1281 |
|
|
addSupportedInstruction(new STRH(this, 0));
|
1282 |
|
|
addSupportedInstruction(new STRH(this, 1));
|
1283 |
|
|
addSupportedInstruction(new STM(this, 0));
|
1284 |
|
|
addSupportedInstruction(new STM(this, 1));
|
1285 |
|
|
addSupportedInstruction(new MCR(this));
|
1286 |
|
|
addSupportedInstruction(new MRC(this));
|
1287 |
|
|
addSupportedInstruction(new SWI(this));
|
1288 |
|
|
}
|
1289 |
|
|
|
1290 |
|
|
} // namespace debugger
|