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