]>
Commit | Line | Data |
---|---|---|
e03feba0 MR |
1 | /* |
2 | * QEMU AVR CPU | |
3 | * | |
4 | * Copyright (c) 2019-2020 Michael Rolnik | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2.1 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see | |
18 | * <http://www.gnu.org/licenses/lgpl-2.1.html> | |
19 | */ | |
20 | ||
21 | #include "qemu/osdep.h" | |
22 | #include "qemu/qemu-print.h" | |
23 | #include "tcg/tcg.h" | |
24 | #include "cpu.h" | |
25 | #include "exec/exec-all.h" | |
26 | #include "tcg/tcg-op.h" | |
27 | #include "exec/cpu_ldst.h" | |
28 | #include "exec/helper-proto.h" | |
29 | #include "exec/helper-gen.h" | |
30 | #include "exec/log.h" | |
31 | #include "exec/translator.h" | |
32 | #include "exec/gen-icount.h" | |
33 | ||
34 | /* | |
35 | * Define if you want a BREAK instruction translated to a breakpoint | |
36 | * Active debugging connection is assumed | |
37 | * This is for | |
38 | * https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tests | |
39 | * tests | |
40 | */ | |
41 | #undef BREAKPOINT_ON_BREAK | |
42 | ||
43 | static TCGv cpu_pc; | |
44 | ||
45 | static TCGv cpu_Cf; | |
46 | static TCGv cpu_Zf; | |
47 | static TCGv cpu_Nf; | |
48 | static TCGv cpu_Vf; | |
49 | static TCGv cpu_Sf; | |
50 | static TCGv cpu_Hf; | |
51 | static TCGv cpu_Tf; | |
52 | static TCGv cpu_If; | |
53 | ||
54 | static TCGv cpu_rampD; | |
55 | static TCGv cpu_rampX; | |
56 | static TCGv cpu_rampY; | |
57 | static TCGv cpu_rampZ; | |
58 | ||
59 | static TCGv cpu_r[NUMBER_OF_CPU_REGISTERS]; | |
60 | static TCGv cpu_eind; | |
61 | static TCGv cpu_sp; | |
62 | ||
63 | static TCGv cpu_skip; | |
64 | ||
65 | static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = { | |
66 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | |
67 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | |
68 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | |
69 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", | |
70 | }; | |
71 | #define REG(x) (cpu_r[x]) | |
72 | ||
eba6814a SW |
73 | #define DISAS_EXIT DISAS_TARGET_0 /* We want return to the cpu main loop. */ |
74 | #define DISAS_LOOKUP DISAS_TARGET_1 /* We have a variable condition exit. */ | |
75 | #define DISAS_CHAIN DISAS_TARGET_2 /* We have a single condition exit. */ | |
e03feba0 MR |
76 | |
77 | typedef struct DisasContext DisasContext; | |
78 | ||
79 | /* This is the state at translation time. */ | |
80 | struct DisasContext { | |
93d4d5e4 | 81 | DisasContextBase base; |
e03feba0 MR |
82 | |
83 | CPUAVRState *env; | |
84 | CPUState *cs; | |
85 | ||
86 | target_long npc; | |
87 | uint32_t opcode; | |
88 | ||
89 | /* Routine used to access memory */ | |
90 | int memidx; | |
e03feba0 MR |
91 | |
92 | /* | |
93 | * some AVR instructions can make the following instruction to be skipped | |
94 | * Let's name those instructions | |
95 | * A - instruction that can skip the next one | |
96 | * B - instruction that can be skipped. this depends on execution of A | |
97 | * there are two scenarios | |
98 | * 1. A and B belong to the same translation block | |
99 | * 2. A is the last instruction in the translation block and B is the last | |
100 | * | |
101 | * following variables are used to simplify the skipping logic, they are | |
102 | * used in the following manner (sketch) | |
103 | * | |
104 | * TCGLabel *skip_label = NULL; | |
bcef6d76 | 105 | * if (ctx->skip_cond != TCG_COND_NEVER) { |
e03feba0 MR |
106 | * skip_label = gen_new_label(); |
107 | * tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label); | |
108 | * } | |
109 | * | |
110 | * if (free_skip_var0) { | |
111 | * tcg_temp_free(skip_var0); | |
112 | * free_skip_var0 = false; | |
113 | * } | |
114 | * | |
bcef6d76 | 115 | * translate(ctx); |
e03feba0 MR |
116 | * |
117 | * if (skip_label) { | |
118 | * gen_set_label(skip_label); | |
119 | * } | |
120 | */ | |
121 | TCGv skip_var0; | |
122 | TCGv skip_var1; | |
123 | TCGCond skip_cond; | |
124 | bool free_skip_var0; | |
125 | }; | |
126 | ||
a107fdb0 MR |
127 | void avr_cpu_tcg_init(void) |
128 | { | |
129 | int i; | |
130 | ||
131 | #define AVR_REG_OFFS(x) offsetof(CPUAVRState, x) | |
132 | cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w), "pc"); | |
133 | cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf"); | |
134 | cpu_Zf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf"); | |
135 | cpu_Nf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf"); | |
136 | cpu_Vf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf"); | |
137 | cpu_Sf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf"); | |
138 | cpu_Hf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf"); | |
139 | cpu_Tf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf"); | |
140 | cpu_If = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If"); | |
141 | cpu_rampD = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), "rampD"); | |
142 | cpu_rampX = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), "rampX"); | |
143 | cpu_rampY = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), "rampY"); | |
144 | cpu_rampZ = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), "rampZ"); | |
145 | cpu_eind = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind), "eind"); | |
146 | cpu_sp = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp), "sp"); | |
147 | cpu_skip = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(skip), "skip"); | |
148 | ||
149 | for (i = 0; i < NUMBER_OF_CPU_REGISTERS; i++) { | |
150 | cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), | |
151 | reg_names[i]); | |
152 | } | |
153 | #undef AVR_REG_OFFS | |
154 | } | |
155 | ||
865f3bb9 MR |
156 | static int to_regs_16_31_by_one(DisasContext *ctx, int indx) |
157 | { | |
158 | return 16 + (indx % 16); | |
159 | } | |
160 | ||
161 | static int to_regs_16_23_by_one(DisasContext *ctx, int indx) | |
162 | { | |
163 | return 16 + (indx % 8); | |
164 | } | |
165 | ||
166 | static int to_regs_24_30_by_two(DisasContext *ctx, int indx) | |
167 | { | |
168 | return 24 + (indx % 4) * 2; | |
169 | } | |
170 | ||
9732b024 MR |
171 | static int to_regs_00_30_by_two(DisasContext *ctx, int indx) |
172 | { | |
173 | return (indx % 16) * 2; | |
174 | } | |
865f3bb9 | 175 | |
9d316c75 MR |
176 | static uint16_t next_word(DisasContext *ctx) |
177 | { | |
178 | return cpu_lduw_code(ctx->env, ctx->npc++ * 2); | |
179 | } | |
180 | ||
181 | static int append_16(DisasContext *ctx, int x) | |
182 | { | |
183 | return x << 16 | next_word(ctx); | |
184 | } | |
185 | ||
e03feba0 MR |
186 | static bool avr_have_feature(DisasContext *ctx, int feature) |
187 | { | |
188 | if (!avr_feature(ctx->env, feature)) { | |
189 | gen_helper_unsupported(cpu_env); | |
93d4d5e4 | 190 | ctx->base.is_jmp = DISAS_NORETURN; |
e03feba0 MR |
191 | return false; |
192 | } | |
193 | return true; | |
194 | } | |
195 | ||
196 | static bool decode_insn(DisasContext *ctx, uint16_t insn); | |
abff1abf | 197 | #include "decode-insn.c.inc" |
865f3bb9 MR |
198 | |
199 | /* | |
200 | * Arithmetic Instructions | |
201 | */ | |
202 | ||
203 | /* | |
204 | * Utility functions for updating status registers: | |
205 | * | |
206 | * - gen_add_CHf() | |
207 | * - gen_add_Vf() | |
208 | * - gen_sub_CHf() | |
209 | * - gen_sub_Vf() | |
210 | * - gen_NSf() | |
211 | * - gen_ZNSf() | |
212 | * | |
213 | */ | |
214 | ||
215 | static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) | |
216 | { | |
217 | TCGv t1 = tcg_temp_new_i32(); | |
218 | TCGv t2 = tcg_temp_new_i32(); | |
219 | TCGv t3 = tcg_temp_new_i32(); | |
220 | ||
221 | tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */ | |
222 | tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */ | |
223 | tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */ | |
224 | tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */ | |
225 | tcg_gen_or_tl(t1, t1, t3); | |
226 | ||
227 | tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */ | |
228 | tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */ | |
229 | tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); | |
230 | ||
231 | tcg_temp_free_i32(t3); | |
232 | tcg_temp_free_i32(t2); | |
233 | tcg_temp_free_i32(t1); | |
234 | } | |
235 | ||
236 | static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) | |
237 | { | |
238 | TCGv t1 = tcg_temp_new_i32(); | |
239 | TCGv t2 = tcg_temp_new_i32(); | |
240 | ||
241 | /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */ | |
242 | /* = (Rd ^ R) & ~(Rd ^ Rr) */ | |
243 | tcg_gen_xor_tl(t1, Rd, R); | |
244 | tcg_gen_xor_tl(t2, Rd, Rr); | |
245 | tcg_gen_andc_tl(t1, t1, t2); | |
246 | ||
247 | tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ | |
248 | ||
249 | tcg_temp_free_i32(t2); | |
250 | tcg_temp_free_i32(t1); | |
251 | } | |
252 | ||
253 | static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr) | |
254 | { | |
255 | TCGv t1 = tcg_temp_new_i32(); | |
256 | TCGv t2 = tcg_temp_new_i32(); | |
257 | TCGv t3 = tcg_temp_new_i32(); | |
258 | ||
259 | tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */ | |
260 | tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */ | |
261 | tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */ | |
262 | tcg_gen_and_tl(t3, t3, R); | |
263 | tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */ | |
264 | ||
265 | tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */ | |
266 | tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */ | |
267 | tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); | |
268 | ||
269 | tcg_temp_free_i32(t3); | |
270 | tcg_temp_free_i32(t2); | |
271 | tcg_temp_free_i32(t1); | |
272 | } | |
273 | ||
274 | static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr) | |
275 | { | |
276 | TCGv t1 = tcg_temp_new_i32(); | |
277 | TCGv t2 = tcg_temp_new_i32(); | |
278 | ||
279 | /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */ | |
280 | /* = (Rd ^ R) & (Rd ^ R) */ | |
281 | tcg_gen_xor_tl(t1, Rd, R); | |
282 | tcg_gen_xor_tl(t2, Rd, Rr); | |
283 | tcg_gen_and_tl(t1, t1, t2); | |
284 | ||
285 | tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ | |
286 | ||
287 | tcg_temp_free_i32(t2); | |
288 | tcg_temp_free_i32(t1); | |
289 | } | |
290 | ||
291 | static void gen_NSf(TCGv R) | |
292 | { | |
293 | tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ | |
294 | tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ | |
295 | } | |
296 | ||
297 | static void gen_ZNSf(TCGv R) | |
298 | { | |
299 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
300 | ||
301 | /* update status register */ | |
302 | tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ | |
303 | tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ | |
304 | } | |
305 | ||
306 | /* | |
307 | * Adds two registers without the C Flag and places the result in the | |
308 | * destination register Rd. | |
309 | */ | |
310 | static bool trans_ADD(DisasContext *ctx, arg_ADD *a) | |
311 | { | |
312 | TCGv Rd = cpu_r[a->rd]; | |
313 | TCGv Rr = cpu_r[a->rr]; | |
314 | TCGv R = tcg_temp_new_i32(); | |
315 | ||
316 | tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */ | |
317 | tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ | |
318 | ||
319 | /* update status register */ | |
320 | gen_add_CHf(R, Rd, Rr); | |
321 | gen_add_Vf(R, Rd, Rr); | |
322 | gen_ZNSf(R); | |
323 | ||
324 | /* update output registers */ | |
325 | tcg_gen_mov_tl(Rd, R); | |
326 | ||
327 | tcg_temp_free_i32(R); | |
328 | ||
329 | return true; | |
330 | } | |
331 | ||
332 | /* | |
333 | * Adds two registers and the contents of the C Flag and places the result in | |
334 | * the destination register Rd. | |
335 | */ | |
336 | static bool trans_ADC(DisasContext *ctx, arg_ADC *a) | |
337 | { | |
338 | TCGv Rd = cpu_r[a->rd]; | |
339 | TCGv Rr = cpu_r[a->rr]; | |
340 | TCGv R = tcg_temp_new_i32(); | |
341 | ||
342 | tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */ | |
343 | tcg_gen_add_tl(R, R, cpu_Cf); | |
344 | tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ | |
345 | ||
346 | /* update status register */ | |
347 | gen_add_CHf(R, Rd, Rr); | |
348 | gen_add_Vf(R, Rd, Rr); | |
349 | gen_ZNSf(R); | |
350 | ||
351 | /* update output registers */ | |
352 | tcg_gen_mov_tl(Rd, R); | |
353 | ||
354 | tcg_temp_free_i32(R); | |
355 | ||
356 | return true; | |
357 | } | |
358 | ||
359 | /* | |
360 | * Adds an immediate value (0 - 63) to a register pair and places the result | |
361 | * in the register pair. This instruction operates on the upper four register | |
362 | * pairs, and is well suited for operations on the pointer registers. This | |
363 | * instruction is not available in all devices. Refer to the device specific | |
364 | * instruction set summary. | |
365 | */ | |
366 | static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a) | |
367 | { | |
368 | if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { | |
369 | return true; | |
370 | } | |
371 | ||
372 | TCGv RdL = cpu_r[a->rd]; | |
373 | TCGv RdH = cpu_r[a->rd + 1]; | |
374 | int Imm = (a->imm); | |
375 | TCGv R = tcg_temp_new_i32(); | |
376 | TCGv Rd = tcg_temp_new_i32(); | |
377 | ||
378 | tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ | |
379 | tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */ | |
380 | tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ | |
381 | ||
382 | /* update status register */ | |
383 | tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ | |
384 | tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); | |
385 | tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */ | |
386 | tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); | |
387 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
388 | tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ | |
389 | tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */ | |
390 | ||
391 | /* update output registers */ | |
392 | tcg_gen_andi_tl(RdL, R, 0xff); | |
393 | tcg_gen_shri_tl(RdH, R, 8); | |
394 | ||
395 | tcg_temp_free_i32(Rd); | |
396 | tcg_temp_free_i32(R); | |
397 | ||
398 | return true; | |
399 | } | |
400 | ||
401 | /* | |
402 | * Subtracts two registers and places the result in the destination | |
403 | * register Rd. | |
404 | */ | |
405 | static bool trans_SUB(DisasContext *ctx, arg_SUB *a) | |
406 | { | |
407 | TCGv Rd = cpu_r[a->rd]; | |
408 | TCGv Rr = cpu_r[a->rr]; | |
409 | TCGv R = tcg_temp_new_i32(); | |
410 | ||
411 | tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ | |
412 | tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ | |
413 | ||
414 | /* update status register */ | |
415 | tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ | |
416 | gen_sub_CHf(R, Rd, Rr); | |
417 | gen_sub_Vf(R, Rd, Rr); | |
418 | gen_ZNSf(R); | |
419 | ||
420 | /* update output registers */ | |
421 | tcg_gen_mov_tl(Rd, R); | |
422 | ||
423 | tcg_temp_free_i32(R); | |
424 | ||
425 | return true; | |
426 | } | |
427 | ||
428 | /* | |
429 | * Subtracts a register and a constant and places the result in the | |
430 | * destination register Rd. This instruction is working on Register R16 to R31 | |
431 | * and is very well suited for operations on the X, Y, and Z-pointers. | |
432 | */ | |
433 | static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a) | |
434 | { | |
435 | TCGv Rd = cpu_r[a->rd]; | |
436 | TCGv Rr = tcg_const_i32(a->imm); | |
437 | TCGv R = tcg_temp_new_i32(); | |
438 | ||
439 | tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */ | |
440 | tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ | |
441 | ||
442 | /* update status register */ | |
443 | gen_sub_CHf(R, Rd, Rr); | |
444 | gen_sub_Vf(R, Rd, Rr); | |
445 | gen_ZNSf(R); | |
446 | ||
447 | /* update output registers */ | |
448 | tcg_gen_mov_tl(Rd, R); | |
449 | ||
450 | tcg_temp_free_i32(R); | |
451 | tcg_temp_free_i32(Rr); | |
452 | ||
453 | return true; | |
454 | } | |
455 | ||
456 | /* | |
457 | * Subtracts two registers and subtracts with the C Flag and places the | |
458 | * result in the destination register Rd. | |
459 | */ | |
460 | static bool trans_SBC(DisasContext *ctx, arg_SBC *a) | |
461 | { | |
462 | TCGv Rd = cpu_r[a->rd]; | |
463 | TCGv Rr = cpu_r[a->rr]; | |
464 | TCGv R = tcg_temp_new_i32(); | |
465 | TCGv zero = tcg_const_i32(0); | |
466 | ||
467 | tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ | |
468 | tcg_gen_sub_tl(R, R, cpu_Cf); | |
469 | tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ | |
470 | ||
471 | /* update status register */ | |
472 | gen_sub_CHf(R, Rd, Rr); | |
473 | gen_sub_Vf(R, Rd, Rr); | |
474 | gen_NSf(R); | |
475 | ||
476 | /* | |
477 | * Previous value remains unchanged when the result is zero; | |
478 | * cleared otherwise. | |
479 | */ | |
480 | tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); | |
481 | ||
482 | /* update output registers */ | |
483 | tcg_gen_mov_tl(Rd, R); | |
484 | ||
485 | tcg_temp_free_i32(zero); | |
486 | tcg_temp_free_i32(R); | |
487 | ||
488 | return true; | |
489 | } | |
490 | ||
491 | /* | |
492 | * SBCI -- Subtract Immediate with Carry | |
493 | */ | |
494 | static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a) | |
495 | { | |
496 | TCGv Rd = cpu_r[a->rd]; | |
497 | TCGv Rr = tcg_const_i32(a->imm); | |
498 | TCGv R = tcg_temp_new_i32(); | |
499 | TCGv zero = tcg_const_i32(0); | |
500 | ||
501 | tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ | |
502 | tcg_gen_sub_tl(R, R, cpu_Cf); | |
503 | tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ | |
504 | ||
505 | /* update status register */ | |
506 | gen_sub_CHf(R, Rd, Rr); | |
507 | gen_sub_Vf(R, Rd, Rr); | |
508 | gen_NSf(R); | |
509 | ||
510 | /* | |
511 | * Previous value remains unchanged when the result is zero; | |
512 | * cleared otherwise. | |
513 | */ | |
514 | tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); | |
515 | ||
516 | /* update output registers */ | |
517 | tcg_gen_mov_tl(Rd, R); | |
518 | ||
519 | tcg_temp_free_i32(zero); | |
520 | tcg_temp_free_i32(R); | |
521 | tcg_temp_free_i32(Rr); | |
522 | ||
523 | return true; | |
524 | } | |
525 | ||
526 | /* | |
527 | * Subtracts an immediate value (0-63) from a register pair and places the | |
528 | * result in the register pair. This instruction operates on the upper four | |
529 | * register pairs, and is well suited for operations on the Pointer Registers. | |
530 | * This instruction is not available in all devices. Refer to the device | |
531 | * specific instruction set summary. | |
532 | */ | |
533 | static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a) | |
534 | { | |
535 | if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { | |
536 | return true; | |
537 | } | |
538 | ||
539 | TCGv RdL = cpu_r[a->rd]; | |
540 | TCGv RdH = cpu_r[a->rd + 1]; | |
541 | int Imm = (a->imm); | |
542 | TCGv R = tcg_temp_new_i32(); | |
543 | TCGv Rd = tcg_temp_new_i32(); | |
544 | ||
545 | tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ | |
546 | tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */ | |
547 | tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ | |
548 | ||
549 | /* update status register */ | |
550 | tcg_gen_andc_tl(cpu_Cf, R, Rd); | |
551 | tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */ | |
552 | tcg_gen_andc_tl(cpu_Vf, Rd, R); | |
553 | tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */ | |
554 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
555 | tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ | |
556 | tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ | |
557 | ||
558 | /* update output registers */ | |
559 | tcg_gen_andi_tl(RdL, R, 0xff); | |
560 | tcg_gen_shri_tl(RdH, R, 8); | |
561 | ||
562 | tcg_temp_free_i32(Rd); | |
563 | tcg_temp_free_i32(R); | |
564 | ||
565 | return true; | |
566 | } | |
567 | ||
568 | /* | |
569 | * Performs the logical AND between the contents of register Rd and register | |
570 | * Rr and places the result in the destination register Rd. | |
571 | */ | |
572 | static bool trans_AND(DisasContext *ctx, arg_AND *a) | |
573 | { | |
574 | TCGv Rd = cpu_r[a->rd]; | |
575 | TCGv Rr = cpu_r[a->rr]; | |
576 | TCGv R = tcg_temp_new_i32(); | |
577 | ||
578 | tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */ | |
579 | ||
580 | /* update status register */ | |
581 | tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ | |
582 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
583 | gen_ZNSf(R); | |
584 | ||
585 | /* update output registers */ | |
586 | tcg_gen_mov_tl(Rd, R); | |
587 | ||
588 | tcg_temp_free_i32(R); | |
589 | ||
590 | return true; | |
591 | } | |
592 | ||
593 | /* | |
594 | * Performs the logical AND between the contents of register Rd and a constant | |
595 | * and places the result in the destination register Rd. | |
596 | */ | |
597 | static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a) | |
598 | { | |
599 | TCGv Rd = cpu_r[a->rd]; | |
600 | int Imm = (a->imm); | |
601 | ||
602 | tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */ | |
603 | ||
604 | /* update status register */ | |
605 | tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ | |
606 | gen_ZNSf(Rd); | |
607 | ||
608 | return true; | |
609 | } | |
610 | ||
611 | /* | |
612 | * Performs the logical OR between the contents of register Rd and register | |
613 | * Rr and places the result in the destination register Rd. | |
614 | */ | |
615 | static bool trans_OR(DisasContext *ctx, arg_OR *a) | |
616 | { | |
617 | TCGv Rd = cpu_r[a->rd]; | |
618 | TCGv Rr = cpu_r[a->rr]; | |
619 | TCGv R = tcg_temp_new_i32(); | |
620 | ||
621 | tcg_gen_or_tl(R, Rd, Rr); | |
622 | ||
623 | /* update status register */ | |
624 | tcg_gen_movi_tl(cpu_Vf, 0); | |
625 | gen_ZNSf(R); | |
626 | ||
627 | /* update output registers */ | |
628 | tcg_gen_mov_tl(Rd, R); | |
629 | ||
630 | tcg_temp_free_i32(R); | |
631 | ||
632 | return true; | |
633 | } | |
634 | ||
635 | /* | |
636 | * Performs the logical OR between the contents of register Rd and a | |
637 | * constant and places the result in the destination register Rd. | |
638 | */ | |
639 | static bool trans_ORI(DisasContext *ctx, arg_ORI *a) | |
640 | { | |
641 | TCGv Rd = cpu_r[a->rd]; | |
642 | int Imm = (a->imm); | |
643 | ||
644 | tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */ | |
645 | ||
646 | /* update status register */ | |
647 | tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ | |
648 | gen_ZNSf(Rd); | |
649 | ||
650 | return true; | |
651 | } | |
652 | ||
653 | /* | |
654 | * Performs the logical EOR between the contents of register Rd and | |
655 | * register Rr and places the result in the destination register Rd. | |
656 | */ | |
657 | static bool trans_EOR(DisasContext *ctx, arg_EOR *a) | |
658 | { | |
659 | TCGv Rd = cpu_r[a->rd]; | |
660 | TCGv Rr = cpu_r[a->rr]; | |
661 | ||
662 | tcg_gen_xor_tl(Rd, Rd, Rr); | |
663 | ||
664 | /* update status register */ | |
665 | tcg_gen_movi_tl(cpu_Vf, 0); | |
666 | gen_ZNSf(Rd); | |
667 | ||
668 | return true; | |
669 | } | |
670 | ||
671 | /* | |
672 | * Clears the specified bits in register Rd. Performs the logical AND | |
673 | * between the contents of register Rd and the complement of the constant mask | |
674 | * K. The result will be placed in register Rd. | |
675 | */ | |
676 | static bool trans_COM(DisasContext *ctx, arg_COM *a) | |
677 | { | |
678 | TCGv Rd = cpu_r[a->rd]; | |
679 | TCGv R = tcg_temp_new_i32(); | |
680 | ||
681 | tcg_gen_xori_tl(Rd, Rd, 0xff); | |
682 | ||
683 | /* update status register */ | |
684 | tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */ | |
685 | tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ | |
686 | gen_ZNSf(Rd); | |
687 | ||
688 | tcg_temp_free_i32(R); | |
689 | ||
690 | return true; | |
691 | } | |
692 | ||
693 | /* | |
694 | * Replaces the contents of register Rd with its two's complement; the | |
695 | * value $80 is left unchanged. | |
696 | */ | |
697 | static bool trans_NEG(DisasContext *ctx, arg_NEG *a) | |
698 | { | |
699 | TCGv Rd = cpu_r[a->rd]; | |
700 | TCGv t0 = tcg_const_i32(0); | |
701 | TCGv R = tcg_temp_new_i32(); | |
702 | ||
703 | tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */ | |
704 | tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ | |
705 | ||
706 | /* update status register */ | |
707 | gen_sub_CHf(R, t0, Rd); | |
708 | gen_sub_Vf(R, t0, Rd); | |
709 | gen_ZNSf(R); | |
710 | ||
711 | /* update output registers */ | |
712 | tcg_gen_mov_tl(Rd, R); | |
713 | ||
714 | tcg_temp_free_i32(t0); | |
715 | tcg_temp_free_i32(R); | |
716 | ||
717 | return true; | |
718 | } | |
719 | ||
720 | /* | |
721 | * Adds one -1- to the contents of register Rd and places the result in the | |
722 | * destination register Rd. The C Flag in SREG is not affected by the | |
723 | * operation, thus allowing the INC instruction to be used on a loop counter in | |
724 | * multiple-precision computations. When operating on unsigned numbers, only | |
725 | * BREQ and BRNE branches can be expected to perform consistently. When | |
726 | * operating on two's complement values, all signed branches are available. | |
727 | */ | |
728 | static bool trans_INC(DisasContext *ctx, arg_INC *a) | |
729 | { | |
730 | TCGv Rd = cpu_r[a->rd]; | |
731 | ||
732 | tcg_gen_addi_tl(Rd, Rd, 1); | |
733 | tcg_gen_andi_tl(Rd, Rd, 0xff); | |
734 | ||
735 | /* update status register */ | |
736 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */ | |
737 | gen_ZNSf(Rd); | |
738 | ||
739 | return true; | |
740 | } | |
741 | ||
742 | /* | |
743 | * Subtracts one -1- from the contents of register Rd and places the result | |
744 | * in the destination register Rd. The C Flag in SREG is not affected by the | |
745 | * operation, thus allowing the DEC instruction to be used on a loop counter in | |
746 | * multiple-precision computations. When operating on unsigned values, only | |
747 | * BREQ and BRNE branches can be expected to perform consistently. When | |
748 | * operating on two's complement values, all signed branches are available. | |
749 | */ | |
750 | static bool trans_DEC(DisasContext *ctx, arg_DEC *a) | |
751 | { | |
752 | TCGv Rd = cpu_r[a->rd]; | |
753 | ||
754 | tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */ | |
755 | tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */ | |
756 | ||
757 | /* update status register */ | |
758 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */ | |
759 | gen_ZNSf(Rd); | |
760 | ||
761 | return true; | |
762 | } | |
763 | ||
764 | /* | |
765 | * This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication. | |
766 | */ | |
767 | static bool trans_MUL(DisasContext *ctx, arg_MUL *a) | |
768 | { | |
769 | if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { | |
770 | return true; | |
771 | } | |
772 | ||
773 | TCGv R0 = cpu_r[0]; | |
774 | TCGv R1 = cpu_r[1]; | |
775 | TCGv Rd = cpu_r[a->rd]; | |
776 | TCGv Rr = cpu_r[a->rr]; | |
777 | TCGv R = tcg_temp_new_i32(); | |
778 | ||
779 | tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ | |
780 | tcg_gen_andi_tl(R0, R, 0xff); | |
781 | tcg_gen_shri_tl(R1, R, 8); | |
782 | ||
783 | /* update status register */ | |
784 | tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ | |
785 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
786 | ||
787 | tcg_temp_free_i32(R); | |
788 | ||
789 | return true; | |
790 | } | |
791 | ||
792 | /* | |
793 | * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication. | |
794 | */ | |
795 | static bool trans_MULS(DisasContext *ctx, arg_MULS *a) | |
796 | { | |
797 | if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { | |
798 | return true; | |
799 | } | |
800 | ||
801 | TCGv R0 = cpu_r[0]; | |
802 | TCGv R1 = cpu_r[1]; | |
803 | TCGv Rd = cpu_r[a->rd]; | |
804 | TCGv Rr = cpu_r[a->rr]; | |
805 | TCGv R = tcg_temp_new_i32(); | |
806 | TCGv t0 = tcg_temp_new_i32(); | |
807 | TCGv t1 = tcg_temp_new_i32(); | |
808 | ||
809 | tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ | |
810 | tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ | |
811 | tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ | |
812 | tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ | |
813 | tcg_gen_andi_tl(R0, R, 0xff); | |
814 | tcg_gen_shri_tl(R1, R, 8); | |
815 | ||
816 | /* update status register */ | |
817 | tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ | |
818 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
819 | ||
820 | tcg_temp_free_i32(t1); | |
821 | tcg_temp_free_i32(t0); | |
822 | tcg_temp_free_i32(R); | |
823 | ||
824 | return true; | |
825 | } | |
826 | ||
827 | /* | |
828 | * This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a | |
829 | * signed and an unsigned number. | |
830 | */ | |
831 | static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a) | |
832 | { | |
833 | if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { | |
834 | return true; | |
835 | } | |
836 | ||
837 | TCGv R0 = cpu_r[0]; | |
838 | TCGv R1 = cpu_r[1]; | |
839 | TCGv Rd = cpu_r[a->rd]; | |
840 | TCGv Rr = cpu_r[a->rr]; | |
841 | TCGv R = tcg_temp_new_i32(); | |
842 | TCGv t0 = tcg_temp_new_i32(); | |
843 | ||
844 | tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ | |
845 | tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ | |
846 | tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */ | |
847 | tcg_gen_andi_tl(R0, R, 0xff); | |
848 | tcg_gen_shri_tl(R1, R, 8); | |
849 | ||
850 | /* update status register */ | |
851 | tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ | |
852 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
853 | ||
854 | tcg_temp_free_i32(t0); | |
855 | tcg_temp_free_i32(R); | |
856 | ||
857 | return true; | |
858 | } | |
859 | ||
860 | /* | |
861 | * This instruction performs 8-bit x 8-bit -> 16-bit unsigned | |
862 | * multiplication and shifts the result one bit left. | |
863 | */ | |
864 | static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a) | |
865 | { | |
866 | if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { | |
867 | return true; | |
868 | } | |
869 | ||
870 | TCGv R0 = cpu_r[0]; | |
871 | TCGv R1 = cpu_r[1]; | |
872 | TCGv Rd = cpu_r[a->rd]; | |
873 | TCGv Rr = cpu_r[a->rr]; | |
874 | TCGv R = tcg_temp_new_i32(); | |
875 | ||
876 | tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ | |
877 | ||
878 | /* update status register */ | |
879 | tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ | |
880 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
881 | ||
882 | /* update output registers */ | |
883 | tcg_gen_shli_tl(R, R, 1); | |
884 | tcg_gen_andi_tl(R0, R, 0xff); | |
885 | tcg_gen_shri_tl(R1, R, 8); | |
886 | tcg_gen_andi_tl(R1, R1, 0xff); | |
887 | ||
888 | ||
889 | tcg_temp_free_i32(R); | |
890 | ||
891 | return true; | |
892 | } | |
893 | ||
894 | /* | |
895 | * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication | |
896 | * and shifts the result one bit left. | |
897 | */ | |
898 | static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a) | |
899 | { | |
900 | if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { | |
901 | return true; | |
902 | } | |
903 | ||
904 | TCGv R0 = cpu_r[0]; | |
905 | TCGv R1 = cpu_r[1]; | |
906 | TCGv Rd = cpu_r[a->rd]; | |
907 | TCGv Rr = cpu_r[a->rr]; | |
908 | TCGv R = tcg_temp_new_i32(); | |
909 | TCGv t0 = tcg_temp_new_i32(); | |
910 | TCGv t1 = tcg_temp_new_i32(); | |
911 | ||
912 | tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ | |
913 | tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ | |
914 | tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ | |
915 | tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ | |
916 | ||
917 | /* update status register */ | |
918 | tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ | |
919 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
920 | ||
921 | /* update output registers */ | |
922 | tcg_gen_shli_tl(R, R, 1); | |
923 | tcg_gen_andi_tl(R0, R, 0xff); | |
924 | tcg_gen_shri_tl(R1, R, 8); | |
925 | tcg_gen_andi_tl(R1, R1, 0xff); | |
926 | ||
927 | tcg_temp_free_i32(t1); | |
928 | tcg_temp_free_i32(t0); | |
929 | tcg_temp_free_i32(R); | |
930 | ||
931 | return true; | |
932 | } | |
933 | ||
934 | /* | |
935 | * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication | |
936 | * and shifts the result one bit left. | |
937 | */ | |
938 | static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a) | |
939 | { | |
940 | if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { | |
941 | return true; | |
942 | } | |
943 | ||
944 | TCGv R0 = cpu_r[0]; | |
945 | TCGv R1 = cpu_r[1]; | |
946 | TCGv Rd = cpu_r[a->rd]; | |
947 | TCGv Rr = cpu_r[a->rr]; | |
948 | TCGv R = tcg_temp_new_i32(); | |
949 | TCGv t0 = tcg_temp_new_i32(); | |
950 | ||
951 | tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ | |
952 | tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ | |
953 | tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ | |
954 | ||
955 | /* update status register */ | |
956 | tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ | |
957 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
958 | ||
959 | /* update output registers */ | |
960 | tcg_gen_shli_tl(R, R, 1); | |
961 | tcg_gen_andi_tl(R0, R, 0xff); | |
962 | tcg_gen_shri_tl(R1, R, 8); | |
963 | tcg_gen_andi_tl(R1, R1, 0xff); | |
964 | ||
965 | tcg_temp_free_i32(t0); | |
966 | tcg_temp_free_i32(R); | |
967 | ||
968 | return true; | |
969 | } | |
970 | ||
971 | /* | |
972 | * The module is an instruction set extension to the AVR CPU, performing | |
973 | * DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in | |
974 | * the CPU register file, registers R0-R7, where LSB of data is placed in LSB | |
975 | * of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including | |
976 | * parity bits) is placed in registers R8- R15, organized in the register file | |
977 | * with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES | |
978 | * instruction performs one round in the DES algorithm. Sixteen rounds must be | |
979 | * executed in increasing order to form the correct DES ciphertext or | |
980 | * plaintext. Intermediate results are stored in the register file (R0-R15) | |
981 | * after each DES instruction. The instruction's operand (K) determines which | |
982 | * round is executed, and the half carry flag (H) determines whether encryption | |
983 | * or decryption is performed. The DES algorithm is described in | |
984 | * "Specifications for the Data Encryption Standard" (Federal Information | |
985 | * Processing Standards Publication 46). Intermediate results in this | |
986 | * implementation differ from the standard because the initial permutation and | |
987 | * the inverse initial permutation are performed each iteration. This does not | |
988 | * affect the result in the final ciphertext or plaintext, but reduces | |
989 | * execution time. | |
990 | */ | |
991 | static bool trans_DES(DisasContext *ctx, arg_DES *a) | |
992 | { | |
993 | /* TODO */ | |
994 | if (!avr_have_feature(ctx, AVR_FEATURE_DES)) { | |
995 | return true; | |
996 | } | |
997 | ||
998 | qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); | |
999 | ||
1000 | return true; | |
1001 | } | |
9d316c75 MR |
1002 | |
1003 | /* | |
1004 | * Branch Instructions | |
1005 | */ | |
1006 | static void gen_jmp_ez(DisasContext *ctx) | |
1007 | { | |
1008 | tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); | |
1009 | tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind); | |
93d4d5e4 | 1010 | ctx->base.is_jmp = DISAS_LOOKUP; |
9d316c75 MR |
1011 | } |
1012 | ||
1013 | static void gen_jmp_z(DisasContext *ctx) | |
1014 | { | |
1015 | tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); | |
93d4d5e4 | 1016 | ctx->base.is_jmp = DISAS_LOOKUP; |
9d316c75 MR |
1017 | } |
1018 | ||
1019 | static void gen_push_ret(DisasContext *ctx, int ret) | |
1020 | { | |
1021 | if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { | |
1022 | ||
1023 | TCGv t0 = tcg_const_i32((ret & 0x0000ff)); | |
1024 | ||
1025 | tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB); | |
1026 | tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); | |
1027 | ||
1028 | tcg_temp_free_i32(t0); | |
1029 | } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { | |
1030 | ||
1031 | TCGv t0 = tcg_const_i32((ret & 0x00ffff)); | |
1032 | ||
1033 | tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); | |
1034 | tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW); | |
1035 | tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); | |
1036 | ||
1037 | tcg_temp_free_i32(t0); | |
1038 | ||
1039 | } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { | |
1040 | ||
1041 | TCGv lo = tcg_const_i32((ret & 0x0000ff)); | |
1042 | TCGv hi = tcg_const_i32((ret & 0xffff00) >> 8); | |
1043 | ||
1044 | tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); | |
1045 | tcg_gen_subi_tl(cpu_sp, cpu_sp, 2); | |
1046 | tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); | |
1047 | tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); | |
1048 | ||
1049 | tcg_temp_free_i32(lo); | |
1050 | tcg_temp_free_i32(hi); | |
1051 | } | |
1052 | } | |
1053 | ||
1054 | static void gen_pop_ret(DisasContext *ctx, TCGv ret) | |
1055 | { | |
1056 | if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { | |
1057 | tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); | |
1058 | tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB); | |
1059 | } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { | |
1060 | tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); | |
1061 | tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW); | |
1062 | tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); | |
1063 | } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { | |
1064 | TCGv lo = tcg_temp_new_i32(); | |
1065 | TCGv hi = tcg_temp_new_i32(); | |
1066 | ||
1067 | tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); | |
1068 | tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); | |
1069 | ||
1070 | tcg_gen_addi_tl(cpu_sp, cpu_sp, 2); | |
1071 | tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); | |
1072 | ||
1073 | tcg_gen_deposit_tl(ret, lo, hi, 8, 16); | |
1074 | ||
1075 | tcg_temp_free_i32(lo); | |
1076 | tcg_temp_free_i32(hi); | |
1077 | } | |
1078 | } | |
1079 | ||
1080 | static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) | |
1081 | { | |
93d4d5e4 | 1082 | const TranslationBlock *tb = ctx->base.tb; |
9d316c75 | 1083 | |
a50d52bc | 1084 | if (translator_use_goto_tb(&ctx->base, dest)) { |
9d316c75 MR |
1085 | tcg_gen_goto_tb(n); |
1086 | tcg_gen_movi_i32(cpu_pc, dest); | |
1087 | tcg_gen_exit_tb(tb, n); | |
1088 | } else { | |
1089 | tcg_gen_movi_i32(cpu_pc, dest); | |
a893daa9 | 1090 | tcg_gen_lookup_and_goto_ptr(); |
9d316c75 | 1091 | } |
93d4d5e4 | 1092 | ctx->base.is_jmp = DISAS_NORETURN; |
9d316c75 MR |
1093 | } |
1094 | ||
1095 | /* | |
1096 | * Relative jump to an address within PC - 2K +1 and PC + 2K (words). For | |
1097 | * AVR microcontrollers with Program memory not exceeding 4K words (8KB) this | |
1098 | * instruction can address the entire memory from every address location. See | |
1099 | * also JMP. | |
1100 | */ | |
1101 | static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a) | |
1102 | { | |
1103 | int dst = ctx->npc + a->imm; | |
1104 | ||
1105 | gen_goto_tb(ctx, 0, dst); | |
1106 | ||
1107 | return true; | |
1108 | } | |
1109 | ||
1110 | /* | |
1111 | * Indirect jump to the address pointed to by the Z (16 bits) Pointer | |
1112 | * Register in the Register File. The Z-pointer Register is 16 bits wide and | |
1113 | * allows jump within the lowest 64K words (128KB) section of Program memory. | |
1114 | * This instruction is not available in all devices. Refer to the device | |
1115 | * specific instruction set summary. | |
1116 | */ | |
1117 | static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a) | |
1118 | { | |
1119 | if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { | |
1120 | return true; | |
1121 | } | |
1122 | ||
1123 | gen_jmp_z(ctx); | |
1124 | ||
1125 | return true; | |
1126 | } | |
1127 | ||
1128 | /* | |
1129 | * Indirect jump to the address pointed to by the Z (16 bits) Pointer | |
1130 | * Register in the Register File and the EIND Register in the I/O space. This | |
1131 | * instruction allows for indirect jumps to the entire 4M (words) Program | |
1132 | * memory space. See also IJMP. This instruction is not available in all | |
1133 | * devices. Refer to the device specific instruction set summary. | |
1134 | */ | |
1135 | static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a) | |
1136 | { | |
1137 | if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { | |
1138 | return true; | |
1139 | } | |
1140 | ||
1141 | gen_jmp_ez(ctx); | |
1142 | return true; | |
1143 | } | |
1144 | ||
1145 | /* | |
1146 | * Jump to an address within the entire 4M (words) Program memory. See also | |
1147 | * RJMP. This instruction is not available in all devices. Refer to the device | |
1148 | * specific instruction set summary.0 | |
1149 | */ | |
1150 | static bool trans_JMP(DisasContext *ctx, arg_JMP *a) | |
1151 | { | |
1152 | if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { | |
1153 | return true; | |
1154 | } | |
1155 | ||
1156 | gen_goto_tb(ctx, 0, a->imm); | |
1157 | ||
1158 | return true; | |
1159 | } | |
1160 | ||
1161 | /* | |
1162 | * Relative call to an address within PC - 2K + 1 and PC + 2K (words). The | |
1163 | * return address (the instruction after the RCALL) is stored onto the Stack. | |
1164 | * See also CALL. For AVR microcontrollers with Program memory not exceeding 4K | |
1165 | * words (8KB) this instruction can address the entire memory from every | |
1166 | * address location. The Stack Pointer uses a post-decrement scheme during | |
1167 | * RCALL. | |
1168 | */ | |
1169 | static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a) | |
1170 | { | |
1171 | int ret = ctx->npc; | |
1172 | int dst = ctx->npc + a->imm; | |
1173 | ||
1174 | gen_push_ret(ctx, ret); | |
1175 | gen_goto_tb(ctx, 0, dst); | |
1176 | ||
1177 | return true; | |
1178 | } | |
1179 | ||
1180 | /* | |
1181 | * Calls to a subroutine within the entire 4M (words) Program memory. The | |
1182 | * return address (to the instruction after the CALL) will be stored onto the | |
1183 | * Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme during | |
1184 | * CALL. This instruction is not available in all devices. Refer to the device | |
1185 | * specific instruction set summary. | |
1186 | */ | |
1187 | static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a) | |
1188 | { | |
1189 | if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { | |
1190 | return true; | |
1191 | } | |
1192 | ||
1193 | int ret = ctx->npc; | |
1194 | ||
1195 | gen_push_ret(ctx, ret); | |
1196 | gen_jmp_z(ctx); | |
1197 | ||
1198 | return true; | |
1199 | } | |
1200 | ||
1201 | /* | |
1202 | * Indirect call of a subroutine pointed to by the Z (16 bits) Pointer | |
1203 | * Register in the Register File and the EIND Register in the I/O space. This | |
1204 | * instruction allows for indirect calls to the entire 4M (words) Program | |
1205 | * memory space. See also ICALL. The Stack Pointer uses a post-decrement scheme | |
1206 | * during EICALL. This instruction is not available in all devices. Refer to | |
1207 | * the device specific instruction set summary. | |
1208 | */ | |
1209 | static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a) | |
1210 | { | |
1211 | if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { | |
1212 | return true; | |
1213 | } | |
1214 | ||
1215 | int ret = ctx->npc; | |
1216 | ||
1217 | gen_push_ret(ctx, ret); | |
1218 | gen_jmp_ez(ctx); | |
1219 | return true; | |
1220 | } | |
1221 | ||
1222 | /* | |
1223 | * Calls to a subroutine within the entire Program memory. The return | |
1224 | * address (to the instruction after the CALL) will be stored onto the Stack. | |
1225 | * (See also RCALL). The Stack Pointer uses a post-decrement scheme during | |
1226 | * CALL. This instruction is not available in all devices. Refer to the device | |
1227 | * specific instruction set summary. | |
1228 | */ | |
1229 | static bool trans_CALL(DisasContext *ctx, arg_CALL *a) | |
1230 | { | |
1231 | if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { | |
1232 | return true; | |
1233 | } | |
1234 | ||
1235 | int Imm = a->imm; | |
1236 | int ret = ctx->npc; | |
1237 | ||
1238 | gen_push_ret(ctx, ret); | |
1239 | gen_goto_tb(ctx, 0, Imm); | |
1240 | ||
1241 | return true; | |
1242 | } | |
1243 | ||
1244 | /* | |
1245 | * Returns from subroutine. The return address is loaded from the STACK. | |
1246 | * The Stack Pointer uses a preincrement scheme during RET. | |
1247 | */ | |
1248 | static bool trans_RET(DisasContext *ctx, arg_RET *a) | |
1249 | { | |
1250 | gen_pop_ret(ctx, cpu_pc); | |
1251 | ||
93d4d5e4 | 1252 | ctx->base.is_jmp = DISAS_LOOKUP; |
9d316c75 MR |
1253 | return true; |
1254 | } | |
1255 | ||
1256 | /* | |
1257 | * Returns from interrupt. The return address is loaded from the STACK and | |
1258 | * the Global Interrupt Flag is set. Note that the Status Register is not | |
1259 | * automatically stored when entering an interrupt routine, and it is not | |
1260 | * restored when returning from an interrupt routine. This must be handled by | |
1261 | * the application program. The Stack Pointer uses a pre-increment scheme | |
1262 | * during RETI. | |
1263 | */ | |
1264 | static bool trans_RETI(DisasContext *ctx, arg_RETI *a) | |
1265 | { | |
1266 | gen_pop_ret(ctx, cpu_pc); | |
1267 | tcg_gen_movi_tl(cpu_If, 1); | |
1268 | ||
1269 | /* Need to return to main loop to re-evaluate interrupts. */ | |
93d4d5e4 | 1270 | ctx->base.is_jmp = DISAS_EXIT; |
9d316c75 MR |
1271 | return true; |
1272 | } | |
1273 | ||
1274 | /* | |
1275 | * This instruction performs a compare between two registers Rd and Rr, and | |
1276 | * skips the next instruction if Rd = Rr. | |
1277 | */ | |
1278 | static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a) | |
1279 | { | |
1280 | ctx->skip_cond = TCG_COND_EQ; | |
1281 | ctx->skip_var0 = cpu_r[a->rd]; | |
1282 | ctx->skip_var1 = cpu_r[a->rr]; | |
1283 | return true; | |
1284 | } | |
1285 | ||
1286 | /* | |
1287 | * This instruction performs a compare between two registers Rd and Rr. | |
1288 | * None of the registers are changed. All conditional branches can be used | |
1289 | * after this instruction. | |
1290 | */ | |
1291 | static bool trans_CP(DisasContext *ctx, arg_CP *a) | |
1292 | { | |
1293 | TCGv Rd = cpu_r[a->rd]; | |
1294 | TCGv Rr = cpu_r[a->rr]; | |
1295 | TCGv R = tcg_temp_new_i32(); | |
1296 | ||
1297 | tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ | |
1298 | tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ | |
1299 | ||
1300 | /* update status register */ | |
1301 | gen_sub_CHf(R, Rd, Rr); | |
1302 | gen_sub_Vf(R, Rd, Rr); | |
1303 | gen_ZNSf(R); | |
1304 | ||
1305 | tcg_temp_free_i32(R); | |
1306 | ||
1307 | return true; | |
1308 | } | |
1309 | ||
1310 | /* | |
1311 | * This instruction performs a compare between two registers Rd and Rr and | |
1312 | * also takes into account the previous carry. None of the registers are | |
1313 | * changed. All conditional branches can be used after this instruction. | |
1314 | */ | |
1315 | static bool trans_CPC(DisasContext *ctx, arg_CPC *a) | |
1316 | { | |
1317 | TCGv Rd = cpu_r[a->rd]; | |
1318 | TCGv Rr = cpu_r[a->rr]; | |
1319 | TCGv R = tcg_temp_new_i32(); | |
1320 | TCGv zero = tcg_const_i32(0); | |
1321 | ||
1322 | tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ | |
1323 | tcg_gen_sub_tl(R, R, cpu_Cf); | |
1324 | tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ | |
1325 | /* update status register */ | |
1326 | gen_sub_CHf(R, Rd, Rr); | |
1327 | gen_sub_Vf(R, Rd, Rr); | |
1328 | gen_NSf(R); | |
1329 | ||
1330 | /* | |
1331 | * Previous value remains unchanged when the result is zero; | |
1332 | * cleared otherwise. | |
1333 | */ | |
1334 | tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); | |
1335 | ||
1336 | tcg_temp_free_i32(zero); | |
1337 | tcg_temp_free_i32(R); | |
1338 | ||
1339 | return true; | |
1340 | } | |
1341 | ||
1342 | /* | |
1343 | * This instruction performs a compare between register Rd and a constant. | |
1344 | * The register is not changed. All conditional branches can be used after this | |
1345 | * instruction. | |
1346 | */ | |
1347 | static bool trans_CPI(DisasContext *ctx, arg_CPI *a) | |
1348 | { | |
1349 | TCGv Rd = cpu_r[a->rd]; | |
1350 | int Imm = a->imm; | |
1351 | TCGv Rr = tcg_const_i32(Imm); | |
1352 | TCGv R = tcg_temp_new_i32(); | |
1353 | ||
1354 | tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ | |
1355 | tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ | |
1356 | ||
1357 | /* update status register */ | |
1358 | gen_sub_CHf(R, Rd, Rr); | |
1359 | gen_sub_Vf(R, Rd, Rr); | |
1360 | gen_ZNSf(R); | |
1361 | ||
1362 | tcg_temp_free_i32(R); | |
1363 | tcg_temp_free_i32(Rr); | |
1364 | ||
1365 | return true; | |
1366 | } | |
1367 | ||
1368 | /* | |
1369 | * This instruction tests a single bit in a register and skips the next | |
1370 | * instruction if the bit is cleared. | |
1371 | */ | |
1372 | static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a) | |
1373 | { | |
1374 | TCGv Rr = cpu_r[a->rr]; | |
1375 | ||
1376 | ctx->skip_cond = TCG_COND_EQ; | |
1377 | ctx->skip_var0 = tcg_temp_new(); | |
1378 | ctx->free_skip_var0 = true; | |
1379 | ||
1380 | tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); | |
1381 | return true; | |
1382 | } | |
1383 | ||
1384 | /* | |
1385 | * This instruction tests a single bit in a register and skips the next | |
1386 | * instruction if the bit is set. | |
1387 | */ | |
1388 | static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a) | |
1389 | { | |
1390 | TCGv Rr = cpu_r[a->rr]; | |
1391 | ||
1392 | ctx->skip_cond = TCG_COND_NE; | |
1393 | ctx->skip_var0 = tcg_temp_new(); | |
1394 | ctx->free_skip_var0 = true; | |
1395 | ||
1396 | tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); | |
1397 | return true; | |
1398 | } | |
1399 | ||
1400 | /* | |
1401 | * This instruction tests a single bit in an I/O Register and skips the | |
1402 | * next instruction if the bit is cleared. This instruction operates on the | |
1403 | * lower 32 I/O Registers -- addresses 0-31. | |
1404 | */ | |
1405 | static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) | |
1406 | { | |
1407 | TCGv temp = tcg_const_i32(a->reg); | |
1408 | ||
1409 | gen_helper_inb(temp, cpu_env, temp); | |
1410 | tcg_gen_andi_tl(temp, temp, 1 << a->bit); | |
1411 | ctx->skip_cond = TCG_COND_EQ; | |
1412 | ctx->skip_var0 = temp; | |
1413 | ctx->free_skip_var0 = true; | |
1414 | ||
1415 | return true; | |
1416 | } | |
1417 | ||
1418 | /* | |
1419 | * This instruction tests a single bit in an I/O Register and skips the | |
1420 | * next instruction if the bit is set. This instruction operates on the lower | |
1421 | * 32 I/O Registers -- addresses 0-31. | |
1422 | */ | |
1423 | static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) | |
1424 | { | |
1425 | TCGv temp = tcg_const_i32(a->reg); | |
1426 | ||
1427 | gen_helper_inb(temp, cpu_env, temp); | |
1428 | tcg_gen_andi_tl(temp, temp, 1 << a->bit); | |
1429 | ctx->skip_cond = TCG_COND_NE; | |
1430 | ctx->skip_var0 = temp; | |
1431 | ctx->free_skip_var0 = true; | |
1432 | ||
1433 | return true; | |
1434 | } | |
1435 | ||
1436 | /* | |
1437 | * Conditional relative branch. Tests a single bit in SREG and branches | |
1438 | * relatively to PC if the bit is cleared. This instruction branches relatively | |
1439 | * to PC in either direction (PC - 63 < = destination <= PC + 64). The | |
1440 | * parameter k is the offset from PC and is represented in two's complement | |
1441 | * form. | |
1442 | */ | |
1443 | static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a) | |
1444 | { | |
1445 | TCGLabel *not_taken = gen_new_label(); | |
1446 | ||
1447 | TCGv var; | |
1448 | ||
1449 | switch (a->bit) { | |
1450 | case 0x00: | |
1451 | var = cpu_Cf; | |
1452 | break; | |
1453 | case 0x01: | |
1454 | var = cpu_Zf; | |
1455 | break; | |
1456 | case 0x02: | |
1457 | var = cpu_Nf; | |
1458 | break; | |
1459 | case 0x03: | |
1460 | var = cpu_Vf; | |
1461 | break; | |
1462 | case 0x04: | |
1463 | var = cpu_Sf; | |
1464 | break; | |
1465 | case 0x05: | |
1466 | var = cpu_Hf; | |
1467 | break; | |
1468 | case 0x06: | |
1469 | var = cpu_Tf; | |
1470 | break; | |
1471 | case 0x07: | |
1472 | var = cpu_If; | |
1473 | break; | |
1474 | default: | |
1475 | g_assert_not_reached(); | |
1476 | } | |
1477 | ||
1478 | tcg_gen_brcondi_i32(TCG_COND_NE, var, 0, not_taken); | |
1479 | gen_goto_tb(ctx, 0, ctx->npc + a->imm); | |
1480 | gen_set_label(not_taken); | |
1481 | ||
93d4d5e4 | 1482 | ctx->base.is_jmp = DISAS_CHAIN; |
9d316c75 MR |
1483 | return true; |
1484 | } | |
1485 | ||
1486 | /* | |
1487 | * Conditional relative branch. Tests a single bit in SREG and branches | |
1488 | * relatively to PC if the bit is set. This instruction branches relatively to | |
1489 | * PC in either direction (PC - 63 < = destination <= PC + 64). The parameter k | |
1490 | * is the offset from PC and is represented in two's complement form. | |
1491 | */ | |
1492 | static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a) | |
1493 | { | |
1494 | TCGLabel *not_taken = gen_new_label(); | |
1495 | ||
1496 | TCGv var; | |
1497 | ||
1498 | switch (a->bit) { | |
1499 | case 0x00: | |
1500 | var = cpu_Cf; | |
1501 | break; | |
1502 | case 0x01: | |
1503 | var = cpu_Zf; | |
1504 | break; | |
1505 | case 0x02: | |
1506 | var = cpu_Nf; | |
1507 | break; | |
1508 | case 0x03: | |
1509 | var = cpu_Vf; | |
1510 | break; | |
1511 | case 0x04: | |
1512 | var = cpu_Sf; | |
1513 | break; | |
1514 | case 0x05: | |
1515 | var = cpu_Hf; | |
1516 | break; | |
1517 | case 0x06: | |
1518 | var = cpu_Tf; | |
1519 | break; | |
1520 | case 0x07: | |
1521 | var = cpu_If; | |
1522 | break; | |
1523 | default: | |
1524 | g_assert_not_reached(); | |
1525 | } | |
1526 | ||
1527 | tcg_gen_brcondi_i32(TCG_COND_EQ, var, 0, not_taken); | |
1528 | gen_goto_tb(ctx, 0, ctx->npc + a->imm); | |
1529 | gen_set_label(not_taken); | |
1530 | ||
93d4d5e4 | 1531 | ctx->base.is_jmp = DISAS_CHAIN; |
9d316c75 MR |
1532 | return true; |
1533 | } | |
9732b024 MR |
1534 | |
1535 | /* | |
1536 | * Data Transfer Instructions | |
1537 | */ | |
1538 | ||
1539 | /* | |
1540 | * in the gen_set_addr & gen_get_addr functions | |
1541 | * H assumed to be in 0x00ff0000 format | |
1542 | * M assumed to be in 0x000000ff format | |
1543 | * L assumed to be in 0x000000ff format | |
1544 | */ | |
1545 | static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L) | |
1546 | { | |
1547 | ||
1548 | tcg_gen_andi_tl(L, addr, 0x000000ff); | |
1549 | ||
1550 | tcg_gen_andi_tl(M, addr, 0x0000ff00); | |
1551 | tcg_gen_shri_tl(M, M, 8); | |
1552 | ||
1553 | tcg_gen_andi_tl(H, addr, 0x00ff0000); | |
1554 | } | |
1555 | ||
1556 | static void gen_set_xaddr(TCGv addr) | |
1557 | { | |
1558 | gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]); | |
1559 | } | |
1560 | ||
1561 | static void gen_set_yaddr(TCGv addr) | |
1562 | { | |
1563 | gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]); | |
1564 | } | |
1565 | ||
1566 | static void gen_set_zaddr(TCGv addr) | |
1567 | { | |
1568 | gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]); | |
1569 | } | |
1570 | ||
1571 | static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L) | |
1572 | { | |
1573 | TCGv addr = tcg_temp_new_i32(); | |
1574 | ||
1575 | tcg_gen_deposit_tl(addr, M, H, 8, 8); | |
1576 | tcg_gen_deposit_tl(addr, L, addr, 8, 16); | |
1577 | ||
1578 | return addr; | |
1579 | } | |
1580 | ||
1581 | static TCGv gen_get_xaddr(void) | |
1582 | { | |
1583 | return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]); | |
1584 | } | |
1585 | ||
1586 | static TCGv gen_get_yaddr(void) | |
1587 | { | |
1588 | return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]); | |
1589 | } | |
1590 | ||
1591 | static TCGv gen_get_zaddr(void) | |
1592 | { | |
1593 | return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]); | |
1594 | } | |
1595 | ||
1596 | /* | |
1597 | * Load one byte indirect from data space to register and stores an clear | |
1598 | * the bits in data space specified by the register. The instruction can only | |
1599 | * be used towards internal SRAM. The data location is pointed to by the Z (16 | |
1600 | * bits) Pointer Register in the Register File. Memory access is limited to the | |
1601 | * current data segment of 64KB. To access another data segment in devices with | |
1602 | * more than 64KB data space, the RAMPZ in register in the I/O area has to be | |
1603 | * changed. The Z-pointer Register is left unchanged by the operation. This | |
1604 | * instruction is especially suited for clearing status bits stored in SRAM. | |
1605 | */ | |
1606 | static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) | |
1607 | { | |
93d4d5e4 | 1608 | if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) { |
9732b024 MR |
1609 | gen_helper_fullwr(cpu_env, data, addr); |
1610 | } else { | |
1611 | tcg_gen_qemu_st8(data, addr, MMU_DATA_IDX); /* mem[addr] = data */ | |
1612 | } | |
1613 | } | |
1614 | ||
1615 | static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) | |
1616 | { | |
93d4d5e4 | 1617 | if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) { |
9732b024 MR |
1618 | gen_helper_fullrd(data, cpu_env, addr); |
1619 | } else { | |
1620 | tcg_gen_qemu_ld8u(data, addr, MMU_DATA_IDX); /* data = mem[addr] */ | |
1621 | } | |
1622 | } | |
1623 | ||
1624 | /* | |
1625 | * This instruction makes a copy of one register into another. The source | |
1626 | * register Rr is left unchanged, while the destination register Rd is loaded | |
1627 | * with a copy of Rr. | |
1628 | */ | |
1629 | static bool trans_MOV(DisasContext *ctx, arg_MOV *a) | |
1630 | { | |
1631 | TCGv Rd = cpu_r[a->rd]; | |
1632 | TCGv Rr = cpu_r[a->rr]; | |
1633 | ||
1634 | tcg_gen_mov_tl(Rd, Rr); | |
1635 | ||
1636 | return true; | |
1637 | } | |
1638 | ||
1639 | /* | |
1640 | * This instruction makes a copy of one register pair into another register | |
1641 | * pair. The source register pair Rr+1:Rr is left unchanged, while the | |
1642 | * destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr. This | |
1643 | * instruction is not available in all devices. Refer to the device specific | |
1644 | * instruction set summary. | |
1645 | */ | |
1646 | static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a) | |
1647 | { | |
1648 | if (!avr_have_feature(ctx, AVR_FEATURE_MOVW)) { | |
1649 | return true; | |
1650 | } | |
1651 | ||
1652 | TCGv RdL = cpu_r[a->rd]; | |
1653 | TCGv RdH = cpu_r[a->rd + 1]; | |
1654 | TCGv RrL = cpu_r[a->rr]; | |
1655 | TCGv RrH = cpu_r[a->rr + 1]; | |
1656 | ||
1657 | tcg_gen_mov_tl(RdH, RrH); | |
1658 | tcg_gen_mov_tl(RdL, RrL); | |
1659 | ||
1660 | return true; | |
1661 | } | |
1662 | ||
1663 | /* | |
1664 | * Loads an 8 bit constant directly to register 16 to 31. | |
1665 | */ | |
1666 | static bool trans_LDI(DisasContext *ctx, arg_LDI *a) | |
1667 | { | |
1668 | TCGv Rd = cpu_r[a->rd]; | |
1669 | int imm = a->imm; | |
1670 | ||
1671 | tcg_gen_movi_tl(Rd, imm); | |
1672 | ||
1673 | return true; | |
1674 | } | |
1675 | ||
1676 | /* | |
1677 | * Loads one byte from the data space to a register. For parts with SRAM, | |
1678 | * the data space consists of the Register File, I/O memory and internal SRAM | |
1679 | * (and external SRAM if applicable). For parts without SRAM, the data space | |
1680 | * consists of the register file only. The EEPROM has a separate address space. | |
1681 | * A 16-bit address must be supplied. Memory access is limited to the current | |
1682 | * data segment of 64KB. The LDS instruction uses the RAMPD Register to access | |
1683 | * memory above 64KB. To access another data segment in devices with more than | |
1684 | * 64KB data space, the RAMPD in register in the I/O area has to be changed. | |
1685 | * This instruction is not available in all devices. Refer to the device | |
1686 | * specific instruction set summary. | |
1687 | */ | |
1688 | static bool trans_LDS(DisasContext *ctx, arg_LDS *a) | |
1689 | { | |
1690 | TCGv Rd = cpu_r[a->rd]; | |
1691 | TCGv addr = tcg_temp_new_i32(); | |
1692 | TCGv H = cpu_rampD; | |
1693 | a->imm = next_word(ctx); | |
1694 | ||
1695 | tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ | |
1696 | tcg_gen_shli_tl(addr, addr, 16); | |
1697 | tcg_gen_ori_tl(addr, addr, a->imm); | |
1698 | ||
1699 | gen_data_load(ctx, Rd, addr); | |
1700 | ||
1701 | tcg_temp_free_i32(addr); | |
1702 | ||
1703 | return true; | |
1704 | } | |
1705 | ||
1706 | /* | |
1707 | * Loads one byte indirect from the data space to a register. For parts | |
1708 | * with SRAM, the data space consists of the Register File, I/O memory and | |
1709 | * internal SRAM (and external SRAM if applicable). For parts without SRAM, the | |
1710 | * data space consists of the Register File only. In some parts the Flash | |
1711 | * Memory has been mapped to the data space and can be read using this command. | |
1712 | * The EEPROM has a separate address space. The data location is pointed to by | |
1713 | * the X (16 bits) Pointer Register in the Register File. Memory access is | |
1714 | * limited to the current data segment of 64KB. To access another data segment | |
1715 | * in devices with more than 64KB data space, the RAMPX in register in the I/O | |
1716 | * area has to be changed. The X-pointer Register can either be left unchanged | |
1717 | * by the operation, or it can be post-incremented or predecremented. These | |
1718 | * features are especially suited for accessing arrays, tables, and Stack | |
1719 | * Pointer usage of the X-pointer Register. Note that only the low byte of the | |
1720 | * X-pointer is updated in devices with no more than 256 bytes data space. For | |
1721 | * such devices, the high byte of the pointer is not used by this instruction | |
1722 | * and can be used for other purposes. The RAMPX Register in the I/O area is | |
1723 | * updated in parts with more than 64KB data space or more than 64KB Program | |
1724 | * memory, and the increment/decrement is added to the entire 24-bit address on | |
1725 | * such devices. Not all variants of this instruction is available in all | |
1726 | * devices. Refer to the device specific instruction set summary. In the | |
1727 | * Reduced Core tinyAVR the LD instruction can be used to achieve the same | |
1728 | * operation as LPM since the program memory is mapped to the data memory | |
1729 | * space. | |
1730 | */ | |
1731 | static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a) | |
1732 | { | |
1733 | TCGv Rd = cpu_r[a->rd]; | |
1734 | TCGv addr = gen_get_xaddr(); | |
1735 | ||
1736 | gen_data_load(ctx, Rd, addr); | |
1737 | ||
1738 | tcg_temp_free_i32(addr); | |
1739 | ||
1740 | return true; | |
1741 | } | |
1742 | ||
1743 | static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a) | |
1744 | { | |
1745 | TCGv Rd = cpu_r[a->rd]; | |
1746 | TCGv addr = gen_get_xaddr(); | |
1747 | ||
1748 | gen_data_load(ctx, Rd, addr); | |
1749 | tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ | |
1750 | ||
1751 | gen_set_xaddr(addr); | |
1752 | ||
1753 | tcg_temp_free_i32(addr); | |
1754 | ||
1755 | return true; | |
1756 | } | |
1757 | ||
1758 | static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a) | |
1759 | { | |
1760 | TCGv Rd = cpu_r[a->rd]; | |
1761 | TCGv addr = gen_get_xaddr(); | |
1762 | ||
1763 | tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ | |
1764 | gen_data_load(ctx, Rd, addr); | |
1765 | gen_set_xaddr(addr); | |
1766 | ||
1767 | tcg_temp_free_i32(addr); | |
1768 | ||
1769 | return true; | |
1770 | } | |
1771 | ||
1772 | /* | |
1773 | * Loads one byte indirect with or without displacement from the data space | |
1774 | * to a register. For parts with SRAM, the data space consists of the Register | |
1775 | * File, I/O memory and internal SRAM (and external SRAM if applicable). For | |
1776 | * parts without SRAM, the data space consists of the Register File only. In | |
1777 | * some parts the Flash Memory has been mapped to the data space and can be | |
1778 | * read using this command. The EEPROM has a separate address space. The data | |
1779 | * location is pointed to by the Y (16 bits) Pointer Register in the Register | |
1780 | * File. Memory access is limited to the current data segment of 64KB. To | |
1781 | * access another data segment in devices with more than 64KB data space, the | |
1782 | * RAMPY in register in the I/O area has to be changed. The Y-pointer Register | |
1783 | * can either be left unchanged by the operation, or it can be post-incremented | |
1784 | * or predecremented. These features are especially suited for accessing | |
1785 | * arrays, tables, and Stack Pointer usage of the Y-pointer Register. Note that | |
1786 | * only the low byte of the Y-pointer is updated in devices with no more than | |
1787 | * 256 bytes data space. For such devices, the high byte of the pointer is not | |
1788 | * used by this instruction and can be used for other purposes. The RAMPY | |
1789 | * Register in the I/O area is updated in parts with more than 64KB data space | |
1790 | * or more than 64KB Program memory, and the increment/decrement/displacement | |
1791 | * is added to the entire 24-bit address on such devices. Not all variants of | |
1792 | * this instruction is available in all devices. Refer to the device specific | |
1793 | * instruction set summary. In the Reduced Core tinyAVR the LD instruction can | |
1794 | * be used to achieve the same operation as LPM since the program memory is | |
1795 | * mapped to the data memory space. | |
1796 | */ | |
1797 | static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a) | |
1798 | { | |
1799 | TCGv Rd = cpu_r[a->rd]; | |
1800 | TCGv addr = gen_get_yaddr(); | |
1801 | ||
1802 | gen_data_load(ctx, Rd, addr); | |
1803 | tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ | |
1804 | ||
1805 | gen_set_yaddr(addr); | |
1806 | ||
1807 | tcg_temp_free_i32(addr); | |
1808 | ||
1809 | return true; | |
1810 | } | |
1811 | ||
1812 | static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a) | |
1813 | { | |
1814 | TCGv Rd = cpu_r[a->rd]; | |
1815 | TCGv addr = gen_get_yaddr(); | |
1816 | ||
1817 | tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ | |
1818 | gen_data_load(ctx, Rd, addr); | |
1819 | gen_set_yaddr(addr); | |
1820 | ||
1821 | tcg_temp_free_i32(addr); | |
1822 | ||
1823 | return true; | |
1824 | } | |
1825 | ||
1826 | static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a) | |
1827 | { | |
1828 | TCGv Rd = cpu_r[a->rd]; | |
1829 | TCGv addr = gen_get_yaddr(); | |
1830 | ||
1831 | tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ | |
1832 | gen_data_load(ctx, Rd, addr); | |
1833 | ||
1834 | tcg_temp_free_i32(addr); | |
1835 | ||
1836 | return true; | |
1837 | } | |
1838 | ||
1839 | /* | |
1840 | * Loads one byte indirect with or without displacement from the data space | |
1841 | * to a register. For parts with SRAM, the data space consists of the Register | |
1842 | * File, I/O memory and internal SRAM (and external SRAM if applicable). For | |
1843 | * parts without SRAM, the data space consists of the Register File only. In | |
1844 | * some parts the Flash Memory has been mapped to the data space and can be | |
1845 | * read using this command. The EEPROM has a separate address space. The data | |
1846 | * location is pointed to by the Z (16 bits) Pointer Register in the Register | |
1847 | * File. Memory access is limited to the current data segment of 64KB. To | |
1848 | * access another data segment in devices with more than 64KB data space, the | |
1849 | * RAMPZ in register in the I/O area has to be changed. The Z-pointer Register | |
1850 | * can either be left unchanged by the operation, or it can be post-incremented | |
1851 | * or predecremented. These features are especially suited for Stack Pointer | |
1852 | * usage of the Z-pointer Register, however because the Z-pointer Register can | |
1853 | * be used for indirect subroutine calls, indirect jumps and table lookup, it | |
1854 | * is often more convenient to use the X or Y-pointer as a dedicated Stack | |
1855 | * Pointer. Note that only the low byte of the Z-pointer is updated in devices | |
1856 | * with no more than 256 bytes data space. For such devices, the high byte of | |
1857 | * the pointer is not used by this instruction and can be used for other | |
1858 | * purposes. The RAMPZ Register in the I/O area is updated in parts with more | |
1859 | * than 64KB data space or more than 64KB Program memory, and the | |
1860 | * increment/decrement/displacement is added to the entire 24-bit address on | |
1861 | * such devices. Not all variants of this instruction is available in all | |
1862 | * devices. Refer to the device specific instruction set summary. In the | |
1863 | * Reduced Core tinyAVR the LD instruction can be used to achieve the same | |
1864 | * operation as LPM since the program memory is mapped to the data memory | |
1865 | * space. For using the Z-pointer for table lookup in Program memory see the | |
1866 | * LPM and ELPM instructions. | |
1867 | */ | |
1868 | static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a) | |
1869 | { | |
1870 | TCGv Rd = cpu_r[a->rd]; | |
1871 | TCGv addr = gen_get_zaddr(); | |
1872 | ||
1873 | gen_data_load(ctx, Rd, addr); | |
1874 | tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ | |
1875 | ||
1876 | gen_set_zaddr(addr); | |
1877 | ||
1878 | tcg_temp_free_i32(addr); | |
1879 | ||
1880 | return true; | |
1881 | } | |
1882 | ||
1883 | static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a) | |
1884 | { | |
1885 | TCGv Rd = cpu_r[a->rd]; | |
1886 | TCGv addr = gen_get_zaddr(); | |
1887 | ||
1888 | tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ | |
1889 | gen_data_load(ctx, Rd, addr); | |
1890 | ||
1891 | gen_set_zaddr(addr); | |
1892 | ||
1893 | tcg_temp_free_i32(addr); | |
1894 | ||
1895 | return true; | |
1896 | } | |
1897 | ||
1898 | static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a) | |
1899 | { | |
1900 | TCGv Rd = cpu_r[a->rd]; | |
1901 | TCGv addr = gen_get_zaddr(); | |
1902 | ||
1903 | tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ | |
1904 | gen_data_load(ctx, Rd, addr); | |
1905 | ||
1906 | tcg_temp_free_i32(addr); | |
1907 | ||
1908 | return true; | |
1909 | } | |
1910 | ||
1911 | /* | |
1912 | * Stores one byte from a Register to the data space. For parts with SRAM, | |
1913 | * the data space consists of the Register File, I/O memory and internal SRAM | |
1914 | * (and external SRAM if applicable). For parts without SRAM, the data space | |
1915 | * consists of the Register File only. The EEPROM has a separate address space. | |
1916 | * A 16-bit address must be supplied. Memory access is limited to the current | |
1917 | * data segment of 64KB. The STS instruction uses the RAMPD Register to access | |
1918 | * memory above 64KB. To access another data segment in devices with more than | |
1919 | * 64KB data space, the RAMPD in register in the I/O area has to be changed. | |
1920 | * This instruction is not available in all devices. Refer to the device | |
1921 | * specific instruction set summary. | |
1922 | */ | |
1923 | static bool trans_STS(DisasContext *ctx, arg_STS *a) | |
1924 | { | |
1925 | TCGv Rd = cpu_r[a->rd]; | |
1926 | TCGv addr = tcg_temp_new_i32(); | |
1927 | TCGv H = cpu_rampD; | |
1928 | a->imm = next_word(ctx); | |
1929 | ||
1930 | tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ | |
1931 | tcg_gen_shli_tl(addr, addr, 16); | |
1932 | tcg_gen_ori_tl(addr, addr, a->imm); | |
1933 | gen_data_store(ctx, Rd, addr); | |
1934 | ||
1935 | tcg_temp_free_i32(addr); | |
1936 | ||
1937 | return true; | |
1938 | } | |
1939 | ||
1940 | /* | |
1941 | * Stores one byte indirect from a register to data space. For parts with SRAM, | |
1942 | * the data space consists of the Register File, I/O memory, and internal SRAM | |
1943 | * (and external SRAM if applicable). For parts without SRAM, the data space | |
1944 | * consists of the Register File only. The EEPROM has a separate address space. | |
1945 | * | |
1946 | * The data location is pointed to by the X (16 bits) Pointer Register in the | |
1947 | * Register File. Memory access is limited to the current data segment of 64KB. | |
1948 | * To access another data segment in devices with more than 64KB data space, the | |
1949 | * RAMPX in register in the I/O area has to be changed. | |
1950 | * | |
1951 | * The X-pointer Register can either be left unchanged by the operation, or it | |
1952 | * can be post-incremented or pre-decremented. These features are especially | |
1953 | * suited for accessing arrays, tables, and Stack Pointer usage of the | |
1954 | * X-pointer Register. Note that only the low byte of the X-pointer is updated | |
1955 | * in devices with no more than 256 bytes data space. For such devices, the high | |
1956 | * byte of the pointer is not used by this instruction and can be used for other | |
1957 | * purposes. The RAMPX Register in the I/O area is updated in parts with more | |
1958 | * than 64KB data space or more than 64KB Program memory, and the increment / | |
1959 | * decrement is added to the entire 24-bit address on such devices. | |
1960 | */ | |
1961 | static bool trans_STX1(DisasContext *ctx, arg_STX1 *a) | |
1962 | { | |
1963 | TCGv Rd = cpu_r[a->rr]; | |
1964 | TCGv addr = gen_get_xaddr(); | |
1965 | ||
1966 | gen_data_store(ctx, Rd, addr); | |
1967 | ||
1968 | tcg_temp_free_i32(addr); | |
1969 | ||
1970 | return true; | |
1971 | } | |
1972 | ||
1973 | static bool trans_STX2(DisasContext *ctx, arg_STX2 *a) | |
1974 | { | |
1975 | TCGv Rd = cpu_r[a->rr]; | |
1976 | TCGv addr = gen_get_xaddr(); | |
1977 | ||
1978 | gen_data_store(ctx, Rd, addr); | |
1979 | tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ | |
1980 | gen_set_xaddr(addr); | |
1981 | ||
1982 | tcg_temp_free_i32(addr); | |
1983 | ||
1984 | return true; | |
1985 | } | |
1986 | ||
1987 | static bool trans_STX3(DisasContext *ctx, arg_STX3 *a) | |
1988 | { | |
1989 | TCGv Rd = cpu_r[a->rr]; | |
1990 | TCGv addr = gen_get_xaddr(); | |
1991 | ||
1992 | tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ | |
1993 | gen_data_store(ctx, Rd, addr); | |
1994 | gen_set_xaddr(addr); | |
1995 | ||
1996 | tcg_temp_free_i32(addr); | |
1997 | ||
1998 | return true; | |
1999 | } | |
2000 | ||
2001 | /* | |
2002 | * Stores one byte indirect with or without displacement from a register to data | |
2003 | * space. For parts with SRAM, the data space consists of the Register File, I/O | |
2004 | * memory, and internal SRAM (and external SRAM if applicable). For parts | |
2005 | * without SRAM, the data space consists of the Register File only. The EEPROM | |
2006 | * has a separate address space. | |
2007 | * | |
2008 | * The data location is pointed to by the Y (16 bits) Pointer Register in the | |
2009 | * Register File. Memory access is limited to the current data segment of 64KB. | |
2010 | * To access another data segment in devices with more than 64KB data space, the | |
2011 | * RAMPY in register in the I/O area has to be changed. | |
2012 | * | |
2013 | * The Y-pointer Register can either be left unchanged by the operation, or it | |
2014 | * can be post-incremented or pre-decremented. These features are especially | |
2015 | * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer | |
2016 | * Register. Note that only the low byte of the Y-pointer is updated in devices | |
2017 | * with no more than 256 bytes data space. For such devices, the high byte of | |
2018 | * the pointer is not used by this instruction and can be used for other | |
2019 | * purposes. The RAMPY Register in the I/O area is updated in parts with more | |
2020 | * than 64KB data space or more than 64KB Program memory, and the increment / | |
2021 | * decrement / displacement is added to the entire 24-bit address on such | |
2022 | * devices. | |
2023 | */ | |
2024 | static bool trans_STY2(DisasContext *ctx, arg_STY2 *a) | |
2025 | { | |
2026 | TCGv Rd = cpu_r[a->rd]; | |
2027 | TCGv addr = gen_get_yaddr(); | |
2028 | ||
2029 | gen_data_store(ctx, Rd, addr); | |
2030 | tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ | |
2031 | gen_set_yaddr(addr); | |
2032 | ||
2033 | tcg_temp_free_i32(addr); | |
2034 | ||
2035 | return true; | |
2036 | } | |
2037 | ||
2038 | static bool trans_STY3(DisasContext *ctx, arg_STY3 *a) | |
2039 | { | |
2040 | TCGv Rd = cpu_r[a->rd]; | |
2041 | TCGv addr = gen_get_yaddr(); | |
2042 | ||
2043 | tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ | |
2044 | gen_data_store(ctx, Rd, addr); | |
2045 | gen_set_yaddr(addr); | |
2046 | ||
2047 | tcg_temp_free_i32(addr); | |
2048 | ||
2049 | return true; | |
2050 | } | |
2051 | ||
2052 | static bool trans_STDY(DisasContext *ctx, arg_STDY *a) | |
2053 | { | |
2054 | TCGv Rd = cpu_r[a->rd]; | |
2055 | TCGv addr = gen_get_yaddr(); | |
2056 | ||
2057 | tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ | |
2058 | gen_data_store(ctx, Rd, addr); | |
2059 | ||
2060 | tcg_temp_free_i32(addr); | |
2061 | ||
2062 | return true; | |
2063 | } | |
2064 | ||
2065 | /* | |
2066 | * Stores one byte indirect with or without displacement from a register to data | |
2067 | * space. For parts with SRAM, the data space consists of the Register File, I/O | |
2068 | * memory, and internal SRAM (and external SRAM if applicable). For parts | |
2069 | * without SRAM, the data space consists of the Register File only. The EEPROM | |
2070 | * has a separate address space. | |
2071 | * | |
2072 | * The data location is pointed to by the Y (16 bits) Pointer Register in the | |
2073 | * Register File. Memory access is limited to the current data segment of 64KB. | |
2074 | * To access another data segment in devices with more than 64KB data space, the | |
2075 | * RAMPY in register in the I/O area has to be changed. | |
2076 | * | |
2077 | * The Y-pointer Register can either be left unchanged by the operation, or it | |
2078 | * can be post-incremented or pre-decremented. These features are especially | |
2079 | * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer | |
2080 | * Register. Note that only the low byte of the Y-pointer is updated in devices | |
2081 | * with no more than 256 bytes data space. For such devices, the high byte of | |
2082 | * the pointer is not used by this instruction and can be used for other | |
2083 | * purposes. The RAMPY Register in the I/O area is updated in parts with more | |
2084 | * than 64KB data space or more than 64KB Program memory, and the increment / | |
2085 | * decrement / displacement is added to the entire 24-bit address on such | |
2086 | * devices. | |
2087 | */ | |
2088 | static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a) | |
2089 | { | |
2090 | TCGv Rd = cpu_r[a->rd]; | |
2091 | TCGv addr = gen_get_zaddr(); | |
2092 | ||
2093 | gen_data_store(ctx, Rd, addr); | |
2094 | tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ | |
2095 | ||
2096 | gen_set_zaddr(addr); | |
2097 | ||
2098 | tcg_temp_free_i32(addr); | |
2099 | ||
2100 | return true; | |
2101 | } | |
2102 | ||
2103 | static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a) | |
2104 | { | |
2105 | TCGv Rd = cpu_r[a->rd]; | |
2106 | TCGv addr = gen_get_zaddr(); | |
2107 | ||
2108 | tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ | |
2109 | gen_data_store(ctx, Rd, addr); | |
2110 | ||
2111 | gen_set_zaddr(addr); | |
2112 | ||
2113 | tcg_temp_free_i32(addr); | |
2114 | ||
2115 | return true; | |
2116 | } | |
2117 | ||
2118 | static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a) | |
2119 | { | |
2120 | TCGv Rd = cpu_r[a->rd]; | |
2121 | TCGv addr = gen_get_zaddr(); | |
2122 | ||
2123 | tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ | |
2124 | gen_data_store(ctx, Rd, addr); | |
2125 | ||
2126 | tcg_temp_free_i32(addr); | |
2127 | ||
2128 | return true; | |
2129 | } | |
2130 | ||
2131 | /* | |
2132 | * Loads one byte pointed to by the Z-register into the destination | |
2133 | * register Rd. This instruction features a 100% space effective constant | |
2134 | * initialization or constant data fetch. The Program memory is organized in | |
2135 | * 16-bit words while the Z-pointer is a byte address. Thus, the least | |
2136 | * significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high | |
2137 | * byte (ZLSB = 1). This instruction can address the first 64KB (32K words) of | |
2138 | * Program memory. The Zpointer Register can either be left unchanged by the | |
2139 | * operation, or it can be incremented. The incrementation does not apply to | |
2140 | * the RAMPZ Register. | |
2141 | * | |
2142 | * Devices with Self-Programming capability can use the LPM instruction to read | |
2143 | * the Fuse and Lock bit values. | |
2144 | */ | |
2145 | static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a) | |
2146 | { | |
2147 | if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { | |
2148 | return true; | |
2149 | } | |
2150 | ||
2151 | TCGv Rd = cpu_r[0]; | |
2152 | TCGv addr = tcg_temp_new_i32(); | |
2153 | TCGv H = cpu_r[31]; | |
2154 | TCGv L = cpu_r[30]; | |
2155 | ||
2156 | tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ | |
2157 | tcg_gen_or_tl(addr, addr, L); | |
2158 | tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ | |
2159 | ||
2160 | tcg_temp_free_i32(addr); | |
2161 | ||
2162 | return true; | |
2163 | } | |
2164 | ||
2165 | static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a) | |
2166 | { | |
2167 | if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { | |
2168 | return true; | |
2169 | } | |
2170 | ||
2171 | TCGv Rd = cpu_r[a->rd]; | |
2172 | TCGv addr = tcg_temp_new_i32(); | |
2173 | TCGv H = cpu_r[31]; | |
2174 | TCGv L = cpu_r[30]; | |
2175 | ||
2176 | tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ | |
2177 | tcg_gen_or_tl(addr, addr, L); | |
2178 | tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ | |
2179 | ||
2180 | tcg_temp_free_i32(addr); | |
2181 | ||
2182 | return true; | |
2183 | } | |
2184 | ||
2185 | static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a) | |
2186 | { | |
2187 | if (!avr_have_feature(ctx, AVR_FEATURE_LPMX)) { | |
2188 | return true; | |
2189 | } | |
2190 | ||
2191 | TCGv Rd = cpu_r[a->rd]; | |
2192 | TCGv addr = tcg_temp_new_i32(); | |
2193 | TCGv H = cpu_r[31]; | |
2194 | TCGv L = cpu_r[30]; | |
2195 | ||
2196 | tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ | |
2197 | tcg_gen_or_tl(addr, addr, L); | |
2198 | tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ | |
2199 | tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ | |
2200 | tcg_gen_andi_tl(L, addr, 0xff); | |
2201 | tcg_gen_shri_tl(addr, addr, 8); | |
2202 | tcg_gen_andi_tl(H, addr, 0xff); | |
2203 | ||
2204 | tcg_temp_free_i32(addr); | |
2205 | ||
2206 | return true; | |
2207 | } | |
2208 | ||
2209 | /* | |
2210 | * Loads one byte pointed to by the Z-register and the RAMPZ Register in | |
2211 | * the I/O space, and places this byte in the destination register Rd. This | |
2212 | * instruction features a 100% space effective constant initialization or | |
2213 | * constant data fetch. The Program memory is organized in 16-bit words while | |
2214 | * the Z-pointer is a byte address. Thus, the least significant bit of the | |
2215 | * Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This | |
2216 | * instruction can address the entire Program memory space. The Z-pointer | |
2217 | * Register can either be left unchanged by the operation, or it can be | |
2218 | * incremented. The incrementation applies to the entire 24-bit concatenation | |
2219 | * of the RAMPZ and Z-pointer Registers. | |
2220 | * | |
2221 | * Devices with Self-Programming capability can use the ELPM instruction to | |
2222 | * read the Fuse and Lock bit value. | |
2223 | */ | |
2224 | static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a) | |
2225 | { | |
2226 | if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { | |
2227 | return true; | |
2228 | } | |
2229 | ||
2230 | TCGv Rd = cpu_r[0]; | |
2231 | TCGv addr = gen_get_zaddr(); | |
2232 | ||
2233 | tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ | |
2234 | ||
2235 | tcg_temp_free_i32(addr); | |
2236 | ||
2237 | return true; | |
2238 | } | |
2239 | ||
2240 | static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a) | |
2241 | { | |
2242 | if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { | |
2243 | return true; | |
2244 | } | |
2245 | ||
2246 | TCGv Rd = cpu_r[a->rd]; | |
2247 | TCGv addr = gen_get_zaddr(); | |
2248 | ||
2249 | tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ | |
2250 | ||
2251 | tcg_temp_free_i32(addr); | |
2252 | ||
2253 | return true; | |
2254 | } | |
2255 | ||
2256 | static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a) | |
2257 | { | |
2258 | if (!avr_have_feature(ctx, AVR_FEATURE_ELPMX)) { | |
2259 | return true; | |
2260 | } | |
2261 | ||
2262 | TCGv Rd = cpu_r[a->rd]; | |
2263 | TCGv addr = gen_get_zaddr(); | |
2264 | ||
2265 | tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ | |
2266 | tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ | |
2267 | gen_set_zaddr(addr); | |
2268 | ||
2269 | tcg_temp_free_i32(addr); | |
2270 | ||
2271 | return true; | |
2272 | } | |
2273 | ||
2274 | /* | |
2275 | * SPM can be used to erase a page in the Program memory, to write a page | |
2276 | * in the Program memory (that is already erased), and to set Boot Loader Lock | |
2277 | * bits. In some devices, the Program memory can be written one word at a time, | |
2278 | * in other devices an entire page can be programmed simultaneously after first | |
2279 | * filling a temporary page buffer. In all cases, the Program memory must be | |
2280 | * erased one page at a time. When erasing the Program memory, the RAMPZ and | |
2281 | * Z-register are used as page address. When writing the Program memory, the | |
2282 | * RAMPZ and Z-register are used as page or word address, and the R1:R0 | |
2283 | * register pair is used as data(1). When setting the Boot Loader Lock bits, | |
2284 | * the R1:R0 register pair is used as data. Refer to the device documentation | |
2285 | * for detailed description of SPM usage. This instruction can address the | |
2286 | * entire Program memory. | |
2287 | * | |
2288 | * The SPM instruction is not available in all devices. Refer to the device | |
2289 | * specific instruction set summary. | |
2290 | * | |
2291 | * Note: 1. R1 determines the instruction high byte, and R0 determines the | |
2292 | * instruction low byte. | |
2293 | */ | |
2294 | static bool trans_SPM(DisasContext *ctx, arg_SPM *a) | |
2295 | { | |
2296 | /* TODO */ | |
2297 | if (!avr_have_feature(ctx, AVR_FEATURE_SPM)) { | |
2298 | return true; | |
2299 | } | |
2300 | ||
2301 | return true; | |
2302 | } | |
2303 | ||
2304 | static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a) | |
2305 | { | |
2306 | /* TODO */ | |
2307 | if (!avr_have_feature(ctx, AVR_FEATURE_SPMX)) { | |
2308 | return true; | |
2309 | } | |
2310 | ||
2311 | return true; | |
2312 | } | |
2313 | ||
2314 | /* | |
2315 | * Loads data from the I/O Space (Ports, Timers, Configuration Registers, | |
2316 | * etc.) into register Rd in the Register File. | |
2317 | */ | |
2318 | static bool trans_IN(DisasContext *ctx, arg_IN *a) | |
2319 | { | |
2320 | TCGv Rd = cpu_r[a->rd]; | |
2321 | TCGv port = tcg_const_i32(a->imm); | |
2322 | ||
2323 | gen_helper_inb(Rd, cpu_env, port); | |
2324 | ||
2325 | tcg_temp_free_i32(port); | |
2326 | ||
2327 | return true; | |
2328 | } | |
2329 | ||
2330 | /* | |
2331 | * Stores data from register Rr in the Register File to I/O Space (Ports, | |
2332 | * Timers, Configuration Registers, etc.). | |
2333 | */ | |
2334 | static bool trans_OUT(DisasContext *ctx, arg_OUT *a) | |
2335 | { | |
2336 | TCGv Rd = cpu_r[a->rd]; | |
2337 | TCGv port = tcg_const_i32(a->imm); | |
2338 | ||
2339 | gen_helper_outb(cpu_env, port, Rd); | |
2340 | ||
2341 | tcg_temp_free_i32(port); | |
2342 | ||
2343 | return true; | |
2344 | } | |
2345 | ||
2346 | /* | |
2347 | * This instruction stores the contents of register Rr on the STACK. The | |
2348 | * Stack Pointer is post-decremented by 1 after the PUSH. This instruction is | |
2349 | * not available in all devices. Refer to the device specific instruction set | |
2350 | * summary. | |
2351 | */ | |
2352 | static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a) | |
2353 | { | |
2354 | TCGv Rd = cpu_r[a->rd]; | |
2355 | ||
2356 | gen_data_store(ctx, Rd, cpu_sp); | |
2357 | tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); | |
2358 | ||
2359 | return true; | |
2360 | } | |
2361 | ||
2362 | /* | |
2363 | * This instruction loads register Rd with a byte from the STACK. The Stack | |
2364 | * Pointer is pre-incremented by 1 before the POP. This instruction is not | |
2365 | * available in all devices. Refer to the device specific instruction set | |
2366 | * summary. | |
2367 | */ | |
2368 | static bool trans_POP(DisasContext *ctx, arg_POP *a) | |
2369 | { | |
2370 | /* | |
2371 | * Using a temp to work around some strange behaviour: | |
2372 | * tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); | |
2373 | * gen_data_load(ctx, Rd, cpu_sp); | |
2374 | * seems to cause the add to happen twice. | |
2375 | * This doesn't happen if either the add or the load is removed. | |
2376 | */ | |
2377 | TCGv t1 = tcg_temp_new_i32(); | |
2378 | TCGv Rd = cpu_r[a->rd]; | |
2379 | ||
2380 | tcg_gen_addi_tl(t1, cpu_sp, 1); | |
2381 | gen_data_load(ctx, Rd, t1); | |
2382 | tcg_gen_mov_tl(cpu_sp, t1); | |
2383 | ||
2384 | return true; | |
2385 | } | |
2386 | ||
2387 | /* | |
2388 | * Exchanges one byte indirect between register and data space. The data | |
2389 | * location is pointed to by the Z (16 bits) Pointer Register in the Register | |
2390 | * File. Memory access is limited to the current data segment of 64KB. To | |
2391 | * access another data segment in devices with more than 64KB data space, the | |
2392 | * RAMPZ in register in the I/O area has to be changed. | |
2393 | * | |
2394 | * The Z-pointer Register is left unchanged by the operation. This instruction | |
2395 | * is especially suited for writing/reading status bits stored in SRAM. | |
2396 | */ | |
2397 | static bool trans_XCH(DisasContext *ctx, arg_XCH *a) | |
2398 | { | |
2399 | if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { | |
2400 | return true; | |
2401 | } | |
2402 | ||
2403 | TCGv Rd = cpu_r[a->rd]; | |
2404 | TCGv t0 = tcg_temp_new_i32(); | |
2405 | TCGv addr = gen_get_zaddr(); | |
2406 | ||
2407 | gen_data_load(ctx, t0, addr); | |
2408 | gen_data_store(ctx, Rd, addr); | |
2409 | tcg_gen_mov_tl(Rd, t0); | |
2410 | ||
2411 | tcg_temp_free_i32(t0); | |
2412 | tcg_temp_free_i32(addr); | |
2413 | ||
2414 | return true; | |
2415 | } | |
2416 | ||
2417 | /* | |
2418 | * Load one byte indirect from data space to register and set bits in data | |
2419 | * space specified by the register. The instruction can only be used towards | |
2420 | * internal SRAM. The data location is pointed to by the Z (16 bits) Pointer | |
2421 | * Register in the Register File. Memory access is limited to the current data | |
2422 | * segment of 64KB. To access another data segment in devices with more than | |
2423 | * 64KB data space, the RAMPZ in register in the I/O area has to be changed. | |
2424 | * | |
2425 | * The Z-pointer Register is left unchanged by the operation. This instruction | |
2426 | * is especially suited for setting status bits stored in SRAM. | |
2427 | */ | |
2428 | static bool trans_LAS(DisasContext *ctx, arg_LAS *a) | |
2429 | { | |
2430 | if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { | |
2431 | return true; | |
2432 | } | |
2433 | ||
2434 | TCGv Rr = cpu_r[a->rd]; | |
2435 | TCGv addr = gen_get_zaddr(); | |
2436 | TCGv t0 = tcg_temp_new_i32(); | |
2437 | TCGv t1 = tcg_temp_new_i32(); | |
2438 | ||
2439 | gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ | |
2440 | tcg_gen_or_tl(t1, t0, Rr); | |
2441 | tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */ | |
2442 | gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ | |
2443 | ||
2444 | tcg_temp_free_i32(t1); | |
2445 | tcg_temp_free_i32(t0); | |
2446 | tcg_temp_free_i32(addr); | |
2447 | ||
2448 | return true; | |
2449 | } | |
2450 | ||
2451 | /* | |
2452 | * Load one byte indirect from data space to register and stores and clear | |
2453 | * the bits in data space specified by the register. The instruction can | |
2454 | * only be used towards internal SRAM. The data location is pointed to by | |
2455 | * the Z (16 bits) Pointer Register in the Register File. Memory access is | |
2456 | * limited to the current data segment of 64KB. To access another data | |
2457 | * segment in devices with more than 64KB data space, the RAMPZ in register | |
2458 | * in the I/O area has to be changed. | |
2459 | * | |
2460 | * The Z-pointer Register is left unchanged by the operation. This instruction | |
2461 | * is especially suited for clearing status bits stored in SRAM. | |
2462 | */ | |
2463 | static bool trans_LAC(DisasContext *ctx, arg_LAC *a) | |
2464 | { | |
2465 | if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { | |
2466 | return true; | |
2467 | } | |
2468 | ||
2469 | TCGv Rr = cpu_r[a->rd]; | |
2470 | TCGv addr = gen_get_zaddr(); | |
2471 | TCGv t0 = tcg_temp_new_i32(); | |
2472 | TCGv t1 = tcg_temp_new_i32(); | |
2473 | ||
2474 | gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ | |
2475 | tcg_gen_andc_tl(t1, t0, Rr); /* t1 = t0 & (0xff - Rr) = t0 & ~Rr */ | |
2476 | tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */ | |
2477 | gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ | |
2478 | ||
2479 | tcg_temp_free_i32(t1); | |
2480 | tcg_temp_free_i32(t0); | |
2481 | tcg_temp_free_i32(addr); | |
2482 | ||
2483 | return true; | |
2484 | } | |
2485 | ||
2486 | ||
2487 | /* | |
2488 | * Load one byte indirect from data space to register and toggles bits in | |
2489 | * the data space specified by the register. The instruction can only be used | |
2490 | * towards SRAM. The data location is pointed to by the Z (16 bits) Pointer | |
2491 | * Register in the Register File. Memory access is limited to the current data | |
2492 | * segment of 64KB. To access another data segment in devices with more than | |
2493 | * 64KB data space, the RAMPZ in register in the I/O area has to be changed. | |
2494 | * | |
2495 | * The Z-pointer Register is left unchanged by the operation. This instruction | |
2496 | * is especially suited for changing status bits stored in SRAM. | |
2497 | */ | |
2498 | static bool trans_LAT(DisasContext *ctx, arg_LAT *a) | |
2499 | { | |
2500 | if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { | |
2501 | return true; | |
2502 | } | |
2503 | ||
2504 | TCGv Rd = cpu_r[a->rd]; | |
2505 | TCGv addr = gen_get_zaddr(); | |
2506 | TCGv t0 = tcg_temp_new_i32(); | |
2507 | TCGv t1 = tcg_temp_new_i32(); | |
2508 | ||
2509 | gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ | |
2510 | tcg_gen_xor_tl(t1, t0, Rd); | |
2511 | tcg_gen_mov_tl(Rd, t0); /* Rd = t0 */ | |
2512 | gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ | |
2513 | ||
2514 | tcg_temp_free_i32(t1); | |
2515 | tcg_temp_free_i32(t0); | |
2516 | tcg_temp_free_i32(addr); | |
2517 | ||
2518 | return true; | |
2519 | } | |
5718cef0 MR |
2520 | |
2521 | /* | |
2522 | * Bit and Bit-test Instructions | |
2523 | */ | |
2524 | static void gen_rshift_ZNVSf(TCGv R) | |
2525 | { | |
2526 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ | |
2527 | tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ | |
2528 | tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf); | |
2529 | tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ | |
2530 | } | |
2531 | ||
2532 | /* | |
2533 | * Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is | |
2534 | * loaded into the C Flag of the SREG. This operation effectively divides an | |
2535 | * unsigned value by two. The C Flag can be used to round the result. | |
2536 | */ | |
2537 | static bool trans_LSR(DisasContext *ctx, arg_LSR *a) | |
2538 | { | |
2539 | TCGv Rd = cpu_r[a->rd]; | |
2540 | ||
2541 | tcg_gen_andi_tl(cpu_Cf, Rd, 1); | |
2542 | tcg_gen_shri_tl(Rd, Rd, 1); | |
2543 | ||
2544 | /* update status register */ | |
2545 | tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, Rd, 0); /* Zf = Rd == 0 */ | |
2546 | tcg_gen_movi_tl(cpu_Nf, 0); | |
2547 | tcg_gen_mov_tl(cpu_Vf, cpu_Cf); | |
2548 | tcg_gen_mov_tl(cpu_Sf, cpu_Vf); | |
2549 | ||
2550 | return true; | |
2551 | } | |
2552 | ||
2553 | /* | |
2554 | * Shifts all bits in Rd one place to the right. The C Flag is shifted into | |
2555 | * bit 7 of Rd. Bit 0 is shifted into the C Flag. This operation, combined | |
2556 | * with ASR, effectively divides multi-byte signed values by two. Combined with | |
2557 | * LSR it effectively divides multi-byte unsigned values by two. The Carry Flag | |
2558 | * can be used to round the result. | |
2559 | */ | |
2560 | static bool trans_ROR(DisasContext *ctx, arg_ROR *a) | |
2561 | { | |
2562 | TCGv Rd = cpu_r[a->rd]; | |
2563 | TCGv t0 = tcg_temp_new_i32(); | |
2564 | ||
2565 | tcg_gen_shli_tl(t0, cpu_Cf, 7); | |
2566 | ||
2567 | /* update status register */ | |
2568 | tcg_gen_andi_tl(cpu_Cf, Rd, 1); | |
2569 | ||
2570 | /* update output register */ | |
2571 | tcg_gen_shri_tl(Rd, Rd, 1); | |
2572 | tcg_gen_or_tl(Rd, Rd, t0); | |
2573 | ||
2574 | /* update status register */ | |
2575 | gen_rshift_ZNVSf(Rd); | |
2576 | ||
2577 | tcg_temp_free_i32(t0); | |
2578 | ||
2579 | return true; | |
2580 | } | |
2581 | ||
2582 | /* | |
2583 | * Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0 | |
2584 | * is loaded into the C Flag of the SREG. This operation effectively divides a | |
2585 | * signed value by two without changing its sign. The Carry Flag can be used to | |
2586 | * round the result. | |
2587 | */ | |
2588 | static bool trans_ASR(DisasContext *ctx, arg_ASR *a) | |
2589 | { | |
2590 | TCGv Rd = cpu_r[a->rd]; | |
2591 | TCGv t0 = tcg_temp_new_i32(); | |
2592 | ||
2593 | /* update status register */ | |
2594 | tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */ | |
2595 | ||
2596 | /* update output register */ | |
2597 | tcg_gen_andi_tl(t0, Rd, 0x80); /* Rd = (Rd & 0x80) | (Rd >> 1) */ | |
2598 | tcg_gen_shri_tl(Rd, Rd, 1); | |
2599 | tcg_gen_or_tl(Rd, Rd, t0); | |
2600 | ||
2601 | /* update status register */ | |
2602 | gen_rshift_ZNVSf(Rd); | |
2603 | ||
2604 | tcg_temp_free_i32(t0); | |
2605 | ||
2606 | return true; | |
2607 | } | |
2608 | ||
2609 | /* | |
2610 | * Swaps high and low nibbles in a register. | |
2611 | */ | |
2612 | static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) | |
2613 | { | |
2614 | TCGv Rd = cpu_r[a->rd]; | |
2615 | TCGv t0 = tcg_temp_new_i32(); | |
2616 | TCGv t1 = tcg_temp_new_i32(); | |
2617 | ||
2618 | tcg_gen_andi_tl(t0, Rd, 0x0f); | |
2619 | tcg_gen_shli_tl(t0, t0, 4); | |
2620 | tcg_gen_andi_tl(t1, Rd, 0xf0); | |
2621 | tcg_gen_shri_tl(t1, t1, 4); | |
2622 | tcg_gen_or_tl(Rd, t0, t1); | |
2623 | ||
2624 | tcg_temp_free_i32(t1); | |
2625 | tcg_temp_free_i32(t0); | |
2626 | ||
2627 | return true; | |
2628 | } | |
2629 | ||
2630 | /* | |
2631 | * Sets a specified bit in an I/O Register. This instruction operates on | |
2632 | * the lower 32 I/O Registers -- addresses 0-31. | |
2633 | */ | |
2634 | static bool trans_SBI(DisasContext *ctx, arg_SBI *a) | |
2635 | { | |
2636 | TCGv data = tcg_temp_new_i32(); | |
2637 | TCGv port = tcg_const_i32(a->reg); | |
2638 | ||
2639 | gen_helper_inb(data, cpu_env, port); | |
2640 | tcg_gen_ori_tl(data, data, 1 << a->bit); | |
2641 | gen_helper_outb(cpu_env, port, data); | |
2642 | ||
2643 | tcg_temp_free_i32(port); | |
2644 | tcg_temp_free_i32(data); | |
2645 | ||
2646 | return true; | |
2647 | } | |
2648 | ||
2649 | /* | |
2650 | * Clears a specified bit in an I/O Register. This instruction operates on | |
2651 | * the lower 32 I/O Registers -- addresses 0-31. | |
2652 | */ | |
2653 | static bool trans_CBI(DisasContext *ctx, arg_CBI *a) | |
2654 | { | |
2655 | TCGv data = tcg_temp_new_i32(); | |
2656 | TCGv port = tcg_const_i32(a->reg); | |
2657 | ||
2658 | gen_helper_inb(data, cpu_env, port); | |
2659 | tcg_gen_andi_tl(data, data, ~(1 << a->bit)); | |
2660 | gen_helper_outb(cpu_env, port, data); | |
2661 | ||
2662 | tcg_temp_free_i32(data); | |
2663 | tcg_temp_free_i32(port); | |
2664 | ||
2665 | return true; | |
2666 | } | |
2667 | ||
2668 | /* | |
2669 | * Stores bit b from Rd to the T Flag in SREG (Status Register). | |
2670 | */ | |
2671 | static bool trans_BST(DisasContext *ctx, arg_BST *a) | |
2672 | { | |
2673 | TCGv Rd = cpu_r[a->rd]; | |
2674 | ||
2675 | tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit); | |
2676 | tcg_gen_shri_tl(cpu_Tf, cpu_Tf, a->bit); | |
2677 | ||
2678 | return true; | |
2679 | } | |
2680 | ||
2681 | /* | |
2682 | * Copies the T Flag in the SREG (Status Register) to bit b in register Rd. | |
2683 | */ | |
2684 | static bool trans_BLD(DisasContext *ctx, arg_BLD *a) | |
2685 | { | |
2686 | TCGv Rd = cpu_r[a->rd]; | |
2687 | TCGv t1 = tcg_temp_new_i32(); | |
2688 | ||
2689 | tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */ | |
2690 | tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */ | |
2691 | tcg_gen_or_tl(Rd, Rd, t1); | |
2692 | ||
2693 | tcg_temp_free_i32(t1); | |
2694 | ||
2695 | return true; | |
2696 | } | |
2697 | ||
2698 | /* | |
2699 | * Sets a single Flag or bit in SREG. | |
2700 | */ | |
2701 | static bool trans_BSET(DisasContext *ctx, arg_BSET *a) | |
2702 | { | |
2703 | switch (a->bit) { | |
2704 | case 0x00: | |
2705 | tcg_gen_movi_tl(cpu_Cf, 0x01); | |
2706 | break; | |
2707 | case 0x01: | |
2708 | tcg_gen_movi_tl(cpu_Zf, 0x01); | |
2709 | break; | |
2710 | case 0x02: | |
2711 | tcg_gen_movi_tl(cpu_Nf, 0x01); | |
2712 | break; | |
2713 | case 0x03: | |
2714 | tcg_gen_movi_tl(cpu_Vf, 0x01); | |
2715 | break; | |
2716 | case 0x04: | |
2717 | tcg_gen_movi_tl(cpu_Sf, 0x01); | |
2718 | break; | |
2719 | case 0x05: | |
2720 | tcg_gen_movi_tl(cpu_Hf, 0x01); | |
2721 | break; | |
2722 | case 0x06: | |
2723 | tcg_gen_movi_tl(cpu_Tf, 0x01); | |
2724 | break; | |
2725 | case 0x07: | |
2726 | tcg_gen_movi_tl(cpu_If, 0x01); | |
2727 | break; | |
2728 | } | |
2729 | ||
2730 | return true; | |
2731 | } | |
2732 | ||
2733 | /* | |
2734 | * Clears a single Flag in SREG. | |
2735 | */ | |
2736 | static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a) | |
2737 | { | |
2738 | switch (a->bit) { | |
2739 | case 0x00: | |
2740 | tcg_gen_movi_tl(cpu_Cf, 0x00); | |
2741 | break; | |
2742 | case 0x01: | |
2743 | tcg_gen_movi_tl(cpu_Zf, 0x00); | |
2744 | break; | |
2745 | case 0x02: | |
2746 | tcg_gen_movi_tl(cpu_Nf, 0x00); | |
2747 | break; | |
2748 | case 0x03: | |
2749 | tcg_gen_movi_tl(cpu_Vf, 0x00); | |
2750 | break; | |
2751 | case 0x04: | |
2752 | tcg_gen_movi_tl(cpu_Sf, 0x00); | |
2753 | break; | |
2754 | case 0x05: | |
2755 | tcg_gen_movi_tl(cpu_Hf, 0x00); | |
2756 | break; | |
2757 | case 0x06: | |
2758 | tcg_gen_movi_tl(cpu_Tf, 0x00); | |
2759 | break; | |
2760 | case 0x07: | |
2761 | tcg_gen_movi_tl(cpu_If, 0x00); | |
2762 | break; | |
2763 | } | |
2764 | ||
2765 | return true; | |
2766 | } | |
46188cab MR |
2767 | |
2768 | /* | |
2769 | * MCU Control Instructions | |
2770 | */ | |
2771 | ||
2772 | /* | |
2773 | * The BREAK instruction is used by the On-chip Debug system, and is | |
2774 | * normally not used in the application software. When the BREAK instruction is | |
2775 | * executed, the AVR CPU is set in the Stopped Mode. This gives the On-chip | |
2776 | * Debugger access to internal resources. If any Lock bits are set, or either | |
2777 | * the JTAGEN or OCDEN Fuses are unprogrammed, the CPU will treat the BREAK | |
2778 | * instruction as a NOP and will not enter the Stopped mode. This instruction | |
2779 | * is not available in all devices. Refer to the device specific instruction | |
2780 | * set summary. | |
2781 | */ | |
2782 | static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a) | |
2783 | { | |
2784 | if (!avr_have_feature(ctx, AVR_FEATURE_BREAK)) { | |
2785 | return true; | |
2786 | } | |
2787 | ||
2788 | #ifdef BREAKPOINT_ON_BREAK | |
2789 | tcg_gen_movi_tl(cpu_pc, ctx->npc - 1); | |
2790 | gen_helper_debug(cpu_env); | |
93d4d5e4 | 2791 | ctx->base.is_jmp = DISAS_EXIT; |
46188cab MR |
2792 | #else |
2793 | /* NOP */ | |
2794 | #endif | |
2795 | ||
2796 | return true; | |
2797 | } | |
2798 | ||
2799 | /* | |
2800 | * This instruction performs a single cycle No Operation. | |
2801 | */ | |
2802 | static bool trans_NOP(DisasContext *ctx, arg_NOP *a) | |
2803 | { | |
2804 | ||
2805 | /* NOP */ | |
2806 | ||
2807 | return true; | |
2808 | } | |
2809 | ||
2810 | /* | |
2811 | * This instruction sets the circuit in sleep mode defined by the MCU | |
2812 | * Control Register. | |
2813 | */ | |
2814 | static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) | |
2815 | { | |
2816 | gen_helper_sleep(cpu_env); | |
93d4d5e4 | 2817 | ctx->base.is_jmp = DISAS_NORETURN; |
46188cab MR |
2818 | return true; |
2819 | } | |
2820 | ||
2821 | /* | |
2822 | * This instruction resets the Watchdog Timer. This instruction must be | |
2823 | * executed within a limited time given by the WD prescaler. See the Watchdog | |
2824 | * Timer hardware specification. | |
2825 | */ | |
2826 | static bool trans_WDR(DisasContext *ctx, arg_WDR *a) | |
2827 | { | |
2828 | gen_helper_wdr(cpu_env); | |
2829 | ||
2830 | return true; | |
2831 | } | |
9baade8d MR |
2832 | |
2833 | /* | |
2834 | * Core translation mechanism functions: | |
2835 | * | |
2836 | * - translate() | |
2837 | * - canonicalize_skip() | |
2838 | * - gen_intermediate_code() | |
2839 | * - restore_state_to_opc() | |
2840 | * | |
2841 | */ | |
2842 | static void translate(DisasContext *ctx) | |
2843 | { | |
2844 | uint32_t opcode = next_word(ctx); | |
2845 | ||
2846 | if (!decode_insn(ctx, opcode)) { | |
2847 | gen_helper_unsupported(cpu_env); | |
93d4d5e4 | 2848 | ctx->base.is_jmp = DISAS_NORETURN; |
9baade8d MR |
2849 | } |
2850 | } | |
2851 | ||
2852 | /* Standardize the cpu_skip condition to NE. */ | |
2853 | static bool canonicalize_skip(DisasContext *ctx) | |
2854 | { | |
2855 | switch (ctx->skip_cond) { | |
2856 | case TCG_COND_NEVER: | |
2857 | /* Normal case: cpu_skip is known to be false. */ | |
2858 | return false; | |
2859 | ||
2860 | case TCG_COND_ALWAYS: | |
2861 | /* | |
2862 | * Breakpoint case: cpu_skip is known to be true, via TB_FLAGS_SKIP. | |
2863 | * The breakpoint is on the instruction being skipped, at the start | |
2864 | * of the TranslationBlock. No need to update. | |
2865 | */ | |
2866 | return false; | |
2867 | ||
2868 | case TCG_COND_NE: | |
2869 | if (ctx->skip_var1 == NULL) { | |
2870 | tcg_gen_mov_tl(cpu_skip, ctx->skip_var0); | |
2871 | } else { | |
2872 | tcg_gen_xor_tl(cpu_skip, ctx->skip_var0, ctx->skip_var1); | |
2873 | ctx->skip_var1 = NULL; | |
2874 | } | |
2875 | break; | |
2876 | ||
2877 | default: | |
2878 | /* Convert to a NE condition vs 0. */ | |
2879 | if (ctx->skip_var1 == NULL) { | |
2880 | tcg_gen_setcondi_tl(ctx->skip_cond, cpu_skip, ctx->skip_var0, 0); | |
2881 | } else { | |
2882 | tcg_gen_setcond_tl(ctx->skip_cond, cpu_skip, | |
2883 | ctx->skip_var0, ctx->skip_var1); | |
2884 | ctx->skip_var1 = NULL; | |
2885 | } | |
2886 | ctx->skip_cond = TCG_COND_NE; | |
2887 | break; | |
2888 | } | |
2889 | if (ctx->free_skip_var0) { | |
2890 | tcg_temp_free(ctx->skip_var0); | |
2891 | ctx->free_skip_var0 = false; | |
2892 | } | |
2893 | ctx->skip_var0 = cpu_skip; | |
2894 | return true; | |
2895 | } | |
2896 | ||
3fbd28d8 | 2897 | static void avr_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) |
9baade8d | 2898 | { |
3fbd28d8 | 2899 | DisasContext *ctx = container_of(dcbase, DisasContext, base); |
9baade8d | 2900 | CPUAVRState *env = cs->env_ptr; |
3fbd28d8 RH |
2901 | uint32_t tb_flags = ctx->base.tb->flags; |
2902 | ||
2903 | ctx->cs = cs; | |
2904 | ctx->env = env; | |
2905 | ctx->npc = ctx->base.pc_first / 2; | |
2906 | ||
2907 | ctx->skip_cond = TCG_COND_NEVER; | |
2908 | if (tb_flags & TB_FLAGS_SKIP) { | |
2909 | ctx->skip_cond = TCG_COND_ALWAYS; | |
2910 | ctx->skip_var0 = cpu_skip; | |
2911 | } | |
2912 | ||
2913 | if (tb_flags & TB_FLAGS_FULL_ACCESS) { | |
9baade8d MR |
2914 | /* |
2915 | * This flag is set by ST/LD instruction we will regenerate it ONLY | |
2916 | * with mem/cpu memory access instead of mem access | |
2917 | */ | |
3fbd28d8 | 2918 | ctx->base.max_insns = 1; |
9baade8d | 2919 | } |
3fbd28d8 | 2920 | } |
9baade8d | 2921 | |
3fbd28d8 RH |
2922 | static void avr_tr_tb_start(DisasContextBase *db, CPUState *cs) |
2923 | { | |
2924 | } | |
9baade8d | 2925 | |
3fbd28d8 RH |
2926 | static void avr_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) |
2927 | { | |
2928 | DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
9baade8d | 2929 | |
3fbd28d8 RH |
2930 | tcg_gen_insn_start(ctx->npc); |
2931 | } | |
9baade8d | 2932 | |
3fbd28d8 RH |
2933 | static void avr_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) |
2934 | { | |
2935 | DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
2936 | TCGLabel *skip_label = NULL; | |
2937 | ||
3fbd28d8 RH |
2938 | /* Conditionally skip the next instruction, if indicated. */ |
2939 | if (ctx->skip_cond != TCG_COND_NEVER) { | |
2940 | skip_label = gen_new_label(); | |
2941 | if (ctx->skip_var0 == cpu_skip) { | |
2942 | /* | |
2943 | * Copy cpu_skip so that we may zero it before the branch. | |
2944 | * This ensures that cpu_skip is non-zero after the label | |
2945 | * if and only if the skipped insn itself sets a skip. | |
2946 | */ | |
2947 | ctx->free_skip_var0 = true; | |
2948 | ctx->skip_var0 = tcg_temp_new(); | |
2949 | tcg_gen_mov_tl(ctx->skip_var0, cpu_skip); | |
2950 | tcg_gen_movi_tl(cpu_skip, 0); | |
2951 | } | |
2952 | if (ctx->skip_var1 == NULL) { | |
2953 | tcg_gen_brcondi_tl(ctx->skip_cond, ctx->skip_var0, 0, skip_label); | |
2954 | } else { | |
2955 | tcg_gen_brcond_tl(ctx->skip_cond, ctx->skip_var0, | |
2956 | ctx->skip_var1, skip_label); | |
2957 | ctx->skip_var1 = NULL; | |
2958 | } | |
2959 | if (ctx->free_skip_var0) { | |
2960 | tcg_temp_free(ctx->skip_var0); | |
2961 | ctx->free_skip_var0 = false; | |
9baade8d | 2962 | } |
3fbd28d8 RH |
2963 | ctx->skip_cond = TCG_COND_NEVER; |
2964 | ctx->skip_var0 = NULL; | |
2965 | } | |
2966 | ||
2967 | translate(ctx); | |
9baade8d | 2968 | |
3fbd28d8 | 2969 | ctx->base.pc_next = ctx->npc * 2; |
9baade8d | 2970 | |
3fbd28d8 RH |
2971 | if (skip_label) { |
2972 | canonicalize_skip(ctx); | |
2973 | gen_set_label(skip_label); | |
2974 | if (ctx->base.is_jmp == DISAS_NORETURN) { | |
2975 | ctx->base.is_jmp = DISAS_CHAIN; | |
9baade8d | 2976 | } |
3fbd28d8 | 2977 | } |
9baade8d | 2978 | |
3fbd28d8 RH |
2979 | if (ctx->base.is_jmp == DISAS_NEXT) { |
2980 | target_ulong page_first = ctx->base.pc_first & TARGET_PAGE_MASK; | |
2981 | ||
2982 | if ((ctx->base.pc_next - page_first) >= TARGET_PAGE_SIZE - 4) { | |
2983 | ctx->base.is_jmp = DISAS_TOO_MANY; | |
2984 | } | |
9baade8d | 2985 | } |
3fbd28d8 | 2986 | } |
9baade8d | 2987 | |
3fbd28d8 RH |
2988 | static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) |
2989 | { | |
2990 | DisasContext *ctx = container_of(dcbase, DisasContext, base); | |
bcef6d76 | 2991 | bool nonconst_skip = canonicalize_skip(ctx); |
9baade8d | 2992 | |
bcef6d76 | 2993 | switch (ctx->base.is_jmp) { |
9baade8d MR |
2994 | case DISAS_NORETURN: |
2995 | assert(!nonconst_skip); | |
2996 | break; | |
2997 | case DISAS_NEXT: | |
2998 | case DISAS_TOO_MANY: | |
2999 | case DISAS_CHAIN: | |
3000 | if (!nonconst_skip) { | |
3001 | /* Note gen_goto_tb checks singlestep. */ | |
bcef6d76 | 3002 | gen_goto_tb(ctx, 1, ctx->npc); |
9baade8d MR |
3003 | break; |
3004 | } | |
bcef6d76 | 3005 | tcg_gen_movi_tl(cpu_pc, ctx->npc); |
9baade8d MR |
3006 | /* fall through */ |
3007 | case DISAS_LOOKUP: | |
a893daa9 RH |
3008 | tcg_gen_lookup_and_goto_ptr(); |
3009 | break; | |
9baade8d | 3010 | case DISAS_EXIT: |
a893daa9 | 3011 | tcg_gen_exit_tb(NULL, 0); |
9baade8d MR |
3012 | break; |
3013 | default: | |
3014 | g_assert_not_reached(); | |
3015 | } | |
3fbd28d8 | 3016 | } |
9baade8d | 3017 | |
8eb806a7 RH |
3018 | static void avr_tr_disas_log(const DisasContextBase *dcbase, |
3019 | CPUState *cs, FILE *logfile) | |
3fbd28d8 | 3020 | { |
8eb806a7 RH |
3021 | fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first)); |
3022 | target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size); | |
3fbd28d8 RH |
3023 | } |
3024 | ||
3025 | static const TranslatorOps avr_tr_ops = { | |
3026 | .init_disas_context = avr_tr_init_disas_context, | |
3027 | .tb_start = avr_tr_tb_start, | |
3028 | .insn_start = avr_tr_insn_start, | |
3fbd28d8 RH |
3029 | .translate_insn = avr_tr_translate_insn, |
3030 | .tb_stop = avr_tr_tb_stop, | |
3031 | .disas_log = avr_tr_disas_log, | |
3032 | }; | |
3033 | ||
3034 | void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) | |
3035 | { | |
3036 | DisasContext dc = { }; | |
3037 | translator_loop(&avr_tr_ops, &dc.base, cs, tb, max_insns); | |
9baade8d MR |
3038 | } |
3039 | ||
3040 | void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, | |
3041 | target_ulong *data) | |
3042 | { | |
3043 | env->pc_w = data[0]; | |
3044 | } |