cpu_arm_instr_dpi.cc Source File

Back to the index.

cpu_arm_instr_dpi.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2019 Anders Gavare. 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 met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. 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  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * ARM Data Processing Instructions
29  * --------------------------------
30  *
31  * xxxx000a aaaSnnnn ddddcccc ctttmmmm Register form
32  * xxxx001a aaaSnnnn ddddrrrr bbbbbbbb Immediate form
33  *
34  * 4 bits to select which instruction, one of the following:
35  *
36  * 0000 and 1000 tst
37  * 0001 eor 1001 teq
38  * 0010 sub 1010 cmp
39  * 0011 rsb 1011 cmn
40  * 0100 add 1100 orr
41  * 0101 adc 1101 mov
42  * 0110 sbc 1110 bic
43  * 0111 rsc 1111 mvn
44  *
45  * 1 bit to select Status flag update.
46  *
47  * 1 bit to select Register form or Immediate form.
48  *
49  * 1 bit to select if the PC register is used.
50  *
51  * Each function must also (as always) be repeated for each possible ARM
52  * condition code (15 in total). Total: 1920 functions.
53  *
54  * NOTE: This does not include any special common cases, which might be
55  * nice to have. Examples: comparing against zero, moving common
56  * constants.
57  *
58  * See src/tools/generate_arm_dpi.c for more details.
59  */
60 
61 
62 #ifndef NOTHING
63 #define NOTHING
64 // Used to break out of dyntrans. TODO: Duplicate of arm_instr_nothing
65 // code in tmp_arm_head.cc.
66 void abortdyntrans(struct cpu* cpu, struct arm_instr_call* ic) { cpu->cd.arm.next_ic --; }
67 static struct arm_instr_call abortdyntrans_call = { abortdyntrans, {0,0,0} };
68 #endif // NOTHING
69 
70 
71 /*
72  * arg[0] = pointer to rn
73  * arg[1] = int32_t immediate value OR ptr to a reg_func() function
74  * arg[2] = pointer to rd
75  */
76 void A__NAME(struct cpu *cpu, struct arm_instr_call *ic)
77 {
78 #if defined(A__RSB) || defined(A__RSC)
79 #define VAR_A b
80 #define VAR_B a
81 #else
82 #define VAR_A a
83 #define VAR_B b
84 #endif
85 
86 #ifdef A__REG
87  uint32_t (*reg_func)(struct cpu *, struct arm_instr_call *)
88  = (uint32_t (*)(struct cpu *, struct arm_instr_call *))
89  (void *)(size_t)ic->arg[1];
90 #endif
91 
92 #ifdef A__S
93  uint32_t c32;
94 #endif
95 #if defined(A__CMP) || defined(A__CMN) || defined(A__ADC) || defined(A__ADD) \
96  || defined(A__RSC) || defined(A__RSB) || defined(A__SBC) || defined(A__SUB)
97 #ifdef A__S
98  uint64_t
99 #else
100  uint32_t
101 #endif
102 #else
103  uint32_t
104 #endif
105  VAR_B =
106 #ifdef A__REG
107  reg_func(cpu, ic)
108 #else
109 #ifdef A__REGSHORT
110  reg(ic->arg[1])
111 #else
112  ic->arg[1]
113 #endif
114 #endif
115  , c64
116 #if !defined(A__MOV) && !defined(A__MVN)
117  , VAR_A = reg(ic->arg[0])
118 #endif
119  ;
120 
121 #if defined(A__MOV) || defined(A__MVN) || defined(A__TST) || defined(A__TEQ) \
122  || defined(A__AND) || defined(A__BIC) || defined(A__EOR) || defined(A__ORR)
123 #if !defined(A__REG) && !defined(A__REGSHORT) && defined(A__S)
124  /*
125  * TODO: This is not 100% correct, but should work with "recommended"
126  * ARM code: Immediate values larger than 255 are encoded with
127  * rotation. If the S-bit is set, then the carry bit is set to the
128  * highest bit of the operand.
129  *
130  * TODO 2: Perhaps this check should be moved out from here, and into
131  * cpu_arm_instr.c. (More correct, and higher performance.)
132  */
133  if (VAR_B > 255) {
134  if (VAR_B & 0x80000000)
135  cpu->cd.arm.flags |= ARM_F_C;
136  else
137  cpu->cd.arm.flags &= ~ARM_F_C;
138  }
139 #endif
140 #endif
141 
142 
143 #if !defined(A__MOV) && !defined(A__MVN)
144 #ifdef A__PC
145  if (ic->arg[0] == (size_t)&cpu->cd.arm.r[ARM_PC]) {
146  uint32_t low_pc = ((size_t)ic - (size_t)
147  cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call);
150  VAR_A += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT) + 8;
151  }
152 #endif
153 #endif
154 
155  /*
156  * Perform the operation:
157  */
158 #if defined(A__AND) || defined(A__TST)
159  c64 = a & b;
160 #endif
161 #if defined(A__EOR) || defined(A__TEQ)
162  c64 = a ^ b;
163 #endif
164 #if defined(A__SUB) || defined(A__CMP) || defined(A__RSB)
165  c64 = a - b;
166 #endif
167 #if defined(A__ADD) || defined(A__CMN)
168  c64 = a + b;
169 #endif
170 #if defined(A__ADC)
171  c64 = a + b + (cpu->cd.arm.flags & ARM_F_C? 1 : 0);
172 #endif
173 #if defined(A__SBC) || defined(A__RSC)
174  c64 = a - b - (cpu->cd.arm.flags & ARM_F_C? 0 : 1);
175 #endif
176 #if defined(A__ORR)
177  c64 = a | b;
178 #endif
179 #if defined(A__MOV)
180  c64 = b;
181 #endif
182 #if defined(A__BIC)
183  c64 = a & ~b;
184 #endif
185 #if defined(A__MVN)
186  c64 = ~b;
187 #endif
188 
189 
190 #if defined(A__CMP) || defined(A__CMN) || defined(A__TST) || defined(A__TEQ)
191  /* No write to rd for compare/test. */
192 #else
193 #ifdef A__PC
194  if (ic->arg[2] == (size_t)&cpu->cd.arm.r[ARM_PC]) {
195 #ifndef A__S
196  uint32_t old_pc = cpu->pc;
197  uint32_t mask_within_page = ((ARM_IC_ENTRIES_PER_PAGE-1)
199  ((1 << ARM_INSTR_ALIGNMENT_SHIFT) - 1);
200 #endif
201  cpu->pc = (uint32_t)c64;
202 #ifdef A__S
203  /* Copy the right SPSR into CPSR: */
205  switch (cpu->cd.arm.cpsr & ARM_FLAG_MODE) {
206  case ARM_MODE_FIQ32:
207  cpu->cd.arm.cpsr = cpu->cd.arm.spsr_fiq; break;
208  case ARM_MODE_IRQ32:
209  cpu->cd.arm.cpsr = cpu->cd.arm.spsr_irq; break;
210  case ARM_MODE_SVC32:
211  cpu->cd.arm.cpsr = cpu->cd.arm.spsr_svc; break;
212  case ARM_MODE_ABT32:
213  cpu->cd.arm.cpsr = cpu->cd.arm.spsr_abt; break;
214  case ARM_MODE_UND32:
215  cpu->cd.arm.cpsr = cpu->cd.arm.spsr_und; break;
216  }
217  cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
219 #else
220  if ((old_pc & ~mask_within_page) ==
221  ((uint32_t)cpu->pc & ~mask_within_page)) {
222  cpu->cd.arm.next_ic = cpu->cd.arm.cur_ic_page +
223  ((cpu->pc & mask_within_page) >>
225  } else
226 #endif
228 
229  if (cpu->pc & 1) {
230  // Switch to THUMB and break out of the dyntrans loop.
231  cpu->cd.arm.cpsr |= ARM_FLAG_T;
232  cpu->cd.arm.next_ic = &abortdyntrans_call;
233  }
234  return;
235  } else
236  reg(ic->arg[2]) = c64;
237 #else
238  reg(ic->arg[2]) = c64;
239 #endif
240 #endif
241 
242 
243  /*
244  * Status flag update (if the S-bit is set):
245  */
246 #ifdef A__S
247  c32 = c64;
248  cpu->cd.arm.flags
249 #if defined(A__CMP) || defined(A__CMN) || defined(A__ADC) || defined(A__ADD) \
250  || defined(A__RSB) || defined(A__RSC) || defined(A__SBC) || defined(A__SUB)
251  &= ~(ARM_F_V | ARM_F_C | ARM_F_Z | ARM_F_N);
252 #else
253  &= ~(ARM_F_Z | ARM_F_N);
254 #endif
255 
256 #if defined(A__CMP) || defined(A__RSB) || defined(A__SUB) || \
257  defined(A__RSC) || defined(A__SBC)
258  if ((uint32_t)a >= (uint32_t)b)
259  cpu->cd.arm.flags |= ARM_F_C;
260 #else
261 #if defined(A__ADC) || defined(A__ADD) || defined(A__CMN)
262  if (c32 != c64)
263  cpu->cd.arm.flags |= ARM_F_C;
264 #endif
265 #endif
266 
267  if (c32 == 0)
268  cpu->cd.arm.flags |= ARM_F_Z;
269 
270  if ((int32_t)c32 < 0)
271  cpu->cd.arm.flags |= ARM_F_N;
272 
273  /* Calculate the Overflow bit: */
274 #if defined(A__CMP) || defined(A__CMN) || defined(A__ADC) || defined(A__ADD) \
275  || defined(A__RSB) || defined(A__RSC) || defined(A__SBC) || defined(A__SUB)
276  {
277  int v = 0;
278 #if defined(A__ADD) || defined(A__CMN)
279  if (((int32_t)a >= 0 && (int32_t)b >= 0 &&
280  (int32_t)c32 < 0) ||
281  ((int32_t)a < 0 && (int32_t)b < 0 &&
282  (int32_t)c32 >= 0))
283  v = 1;
284 #else
285 #if defined(A__SUB) || defined(A__RSB) || defined(A__CMP) || \
286  defined(A__RSC) || defined(A__SBC)
287  if (((int32_t)a >= 0 && (int32_t)b < 0 &&
288  (int32_t)c32 < 0) ||
289  ((int32_t)a < 0 && (int32_t)b >= 0 &&
290  (int32_t)c32 >= 0))
291  v = 1;
292 #endif
293 #endif
294  if (v)
295  cpu->cd.arm.flags |= ARM_F_V;
296  }
297 #endif
298 #endif /* A__S */
299 
300 #undef VAR_A
301 #undef VAR_B
302 }
303 
304 
305 void A__NAME__eq(struct cpu *cpu, struct arm_instr_call *ic)
306 { if (cpu->cd.arm.flags & ARM_F_Z) A__NAME(cpu, ic); }
307 void A__NAME__ne(struct cpu *cpu, struct arm_instr_call *ic)
308 { if (!(cpu->cd.arm.flags & ARM_F_Z)) A__NAME(cpu, ic); }
309 void A__NAME__cs(struct cpu *cpu, struct arm_instr_call *ic)
310 { if (cpu->cd.arm.flags & ARM_F_C) A__NAME(cpu, ic); }
311 void A__NAME__cc(struct cpu *cpu, struct arm_instr_call *ic)
312 { if (!(cpu->cd.arm.flags & ARM_F_C)) A__NAME(cpu, ic); }
313 void A__NAME__mi(struct cpu *cpu, struct arm_instr_call *ic)
314 { if (cpu->cd.arm.flags & ARM_F_N) A__NAME(cpu, ic); }
315 void A__NAME__pl(struct cpu *cpu, struct arm_instr_call *ic)
316 { if (!(cpu->cd.arm.flags & ARM_F_N)) A__NAME(cpu, ic); }
317 void A__NAME__vs(struct cpu *cpu, struct arm_instr_call *ic)
318 { if (cpu->cd.arm.flags & ARM_F_V) A__NAME(cpu, ic); }
319 void A__NAME__vc(struct cpu *cpu, struct arm_instr_call *ic)
320 { if (!(cpu->cd.arm.flags & ARM_F_V)) A__NAME(cpu, ic); }
321 
322 #ifndef BLAHURG
323 #define BLAHURG
324 extern uint8_t condition_hi[16];
325 extern uint8_t condition_ge[16];
326 extern uint8_t condition_gt[16];
327 #endif
328 
329 void A__NAME__hi(struct cpu *cpu, struct arm_instr_call *ic)
330 { if (condition_hi[cpu->cd.arm.flags]) A__NAME(cpu, ic); }
331 void A__NAME__ls(struct cpu *cpu, struct arm_instr_call *ic)
332 { if (!condition_hi[cpu->cd.arm.flags]) A__NAME(cpu, ic); }
333 void A__NAME__ge(struct cpu *cpu, struct arm_instr_call *ic)
334 { if (condition_ge[cpu->cd.arm.flags]) A__NAME(cpu, ic); }
335 void A__NAME__lt(struct cpu *cpu, struct arm_instr_call *ic)
336 { if (!condition_ge[cpu->cd.arm.flags]) A__NAME(cpu, ic); }
337 void A__NAME__gt(struct cpu *cpu, struct arm_instr_call *ic)
338 { if (condition_gt[cpu->cd.arm.flags]) A__NAME(cpu, ic); }
339 void A__NAME__le(struct cpu *cpu, struct arm_instr_call *ic)
340 { if (!condition_gt[cpu->cd.arm.flags]) A__NAME(cpu, ic); }
341 
A__ADD
#define A__ADD
Definition: tmp_arm_dpi.cc:4647
ARM_MODE_SVC32
#define ARM_MODE_SVC32
Definition: cpu_arm.h:111
abortdyntrans
void abortdyntrans(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:66
ARM_IC_ENTRIES_PER_PAGE
#define ARM_IC_ENTRIES_PER_PAGE
Definition: cpu_arm.h:80
A__NAME__mi
void A__NAME__mi(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:313
A__NAME__ge
void A__NAME__ge(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:333
A__NAME
void A__NAME(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:76
arm_cpu::cpsr
uint32_t cpsr
Definition: cpu_arm.h:175
A__NAME__eq
void A__NAME__eq(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:305
ARM_MODE_ABT32
#define ARM_MODE_ABT32
Definition: cpu_arm.h:112
ARM_INSTR_ALIGNMENT_SHIFT
#define ARM_INSTR_ALIGNMENT_SHIFT
Definition: cpu_arm.h:79
A__NAME__hi
void A__NAME__hi(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:329
A__CMN
#define A__CMN
Definition: tmp_arm_dpi.cc:4906
condition_gt
uint8_t condition_gt[16]
Definition: cpu_arm_instr.cc:130
ARM_MODE_FIQ32
#define ARM_MODE_FIQ32
Definition: cpu_arm.h:109
arm_cpu::flags
size_t flags
Definition: cpu_arm.h:174
A__NAME__vs
void A__NAME__vs(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:317
arm_cpu::spsr_und
uint32_t spsr_und
Definition: cpu_arm.h:178
arm_cpu::spsr_irq
uint32_t spsr_irq
Definition: cpu_arm.h:179
A__SBC
#define A__SBC
Definition: tmp_arm_dpi.cc:4721
A__SUB
#define A__SUB
Definition: tmp_arm_dpi.cc:4573
cpu::cd
union cpu::@1 cd
arm_load_register_bank
void arm_load_register_bank(struct cpu *cpu)
Definition: cpu_arm.cc:561
ic
struct arm_instr_call * ic
Definition: tmp_arm_multi.cc:50
ARM_MODE_UND32
#define ARM_MODE_UND32
Definition: cpu_arm.h:113
arm_cpu::spsr_abt
uint32_t spsr_abt
Definition: cpu_arm.h:177
arm_cpu::r
uint32_t r[N_ARM_REGS]
Definition: cpu_arm.h:155
arm_save_register_bank
void arm_save_register_bank(struct cpu *cpu)
Definition: cpu_arm.cc:514
A__NAME__ne
void A__NAME__ne(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:307
VAR_A
#define VAR_A
ARM_FLAG_T
#define ARM_FLAG_T
Definition: cpu_arm.h:101
arm_cpu::spsr_fiq
uint32_t spsr_fiq
Definition: cpu_arm.h:180
ARM_MODE_IRQ32
#define ARM_MODE_IRQ32
Definition: cpu_arm.h:110
ARM_PC
#define ARM_PC
Definition: cpu_arm.h:56
ARM_F_N
#define ARM_F_N
Definition: cpu_arm.h:86
VAR_B
#define VAR_B
reg
#define reg(x)
Definition: tmp_alpha_tail.cc:53
A__NAME__vc
void A__NAME__vc(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:319
A__NAME__cc
void A__NAME__cc(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:311
condition_hi
uint8_t condition_hi[16]
Definition: cpu_arm_instr.cc:128
A__RSB
#define A__RSB
Definition: tmp_arm_dpi.cc:4610
ARM_FLAG_MODE
#define ARM_FLAG_MODE
Definition: cpu_arm.h:103
ARM_F_Z
#define ARM_F_Z
Definition: cpu_arm.h:87
A__RSC
#define A__RSC
Definition: tmp_arm_dpi.cc:4758
cpu::arm
struct arm_cpu arm
Definition: cpu.h:444
A__NAME__pl
void A__NAME__pl(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:315
A__ADC
#define A__ADC
Definition: tmp_arm_dpi.cc:4684
A__NAME__le
void A__NAME__le(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:339
condition_ge
uint8_t condition_ge[16]
Definition: cpu_arm_instr.cc:129
A__NAME__gt
void A__NAME__gt(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:337
quick_pc_to_pointers
#define quick_pc_to_pointers(cpu)
Definition: quick_pc_to_pointers.h:29
A__NAME__lt
void A__NAME__lt(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:335
A__NAME__cs
void A__NAME__cs(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:309
cpu
Definition: cpu.h:326
arm_cpu::spsr_svc
uint32_t spsr_svc
Definition: cpu_arm.h:176
ARM_F_V
#define ARM_F_V
Definition: cpu_arm.h:89
A__NAME__ls
void A__NAME__ls(struct cpu *cpu, struct arm_instr_call *ic)
Definition: cpu_arm_instr_dpi.cc:331
A__CMP
#define A__CMP
Definition: tmp_arm_dpi.cc:4869
cpu::pc
uint64_t pc
Definition: cpu.h:386
ARM_F_C
#define ARM_F_C
Definition: cpu_arm.h:88

Generated on Tue Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18