xref: /openbmc/qemu/target/avr/translate.c (revision a107fdb0)
1e03feba0SMichael Rolnik /*
2e03feba0SMichael Rolnik  * QEMU AVR CPU
3e03feba0SMichael Rolnik  *
4e03feba0SMichael Rolnik  * Copyright (c) 2019-2020 Michael Rolnik
5e03feba0SMichael Rolnik  *
6e03feba0SMichael Rolnik  * This library is free software; you can redistribute it and/or
7e03feba0SMichael Rolnik  * modify it under the terms of the GNU Lesser General Public
8e03feba0SMichael Rolnik  * License as published by the Free Software Foundation; either
9e03feba0SMichael Rolnik  * version 2.1 of the License, or (at your option) any later version.
10e03feba0SMichael Rolnik  *
11e03feba0SMichael Rolnik  * This library is distributed in the hope that it will be useful,
12e03feba0SMichael Rolnik  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13e03feba0SMichael Rolnik  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14e03feba0SMichael Rolnik  * Lesser General Public License for more details.
15e03feba0SMichael Rolnik  *
16e03feba0SMichael Rolnik  * You should have received a copy of the GNU Lesser General Public
17e03feba0SMichael Rolnik  * License along with this library; if not, see
18e03feba0SMichael Rolnik  * <http://www.gnu.org/licenses/lgpl-2.1.html>
19e03feba0SMichael Rolnik  */
20e03feba0SMichael Rolnik 
21e03feba0SMichael Rolnik #include "qemu/osdep.h"
22e03feba0SMichael Rolnik #include "qemu/qemu-print.h"
23e03feba0SMichael Rolnik #include "tcg/tcg.h"
24e03feba0SMichael Rolnik #include "cpu.h"
25e03feba0SMichael Rolnik #include "exec/exec-all.h"
26e03feba0SMichael Rolnik #include "tcg/tcg-op.h"
27e03feba0SMichael Rolnik #include "exec/cpu_ldst.h"
28e03feba0SMichael Rolnik #include "exec/helper-proto.h"
29e03feba0SMichael Rolnik #include "exec/helper-gen.h"
30e03feba0SMichael Rolnik #include "exec/log.h"
31e03feba0SMichael Rolnik #include "exec/translator.h"
32e03feba0SMichael Rolnik #include "exec/gen-icount.h"
33e03feba0SMichael Rolnik 
34e03feba0SMichael Rolnik /*
35e03feba0SMichael Rolnik  *  Define if you want a BREAK instruction translated to a breakpoint
36e03feba0SMichael Rolnik  *  Active debugging connection is assumed
37e03feba0SMichael Rolnik  *  This is for
38e03feba0SMichael Rolnik  *  https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tests
39e03feba0SMichael Rolnik  *  tests
40e03feba0SMichael Rolnik  */
41e03feba0SMichael Rolnik #undef BREAKPOINT_ON_BREAK
42e03feba0SMichael Rolnik 
43e03feba0SMichael Rolnik static TCGv cpu_pc;
44e03feba0SMichael Rolnik 
45e03feba0SMichael Rolnik static TCGv cpu_Cf;
46e03feba0SMichael Rolnik static TCGv cpu_Zf;
47e03feba0SMichael Rolnik static TCGv cpu_Nf;
48e03feba0SMichael Rolnik static TCGv cpu_Vf;
49e03feba0SMichael Rolnik static TCGv cpu_Sf;
50e03feba0SMichael Rolnik static TCGv cpu_Hf;
51e03feba0SMichael Rolnik static TCGv cpu_Tf;
52e03feba0SMichael Rolnik static TCGv cpu_If;
53e03feba0SMichael Rolnik 
54e03feba0SMichael Rolnik static TCGv cpu_rampD;
55e03feba0SMichael Rolnik static TCGv cpu_rampX;
56e03feba0SMichael Rolnik static TCGv cpu_rampY;
57e03feba0SMichael Rolnik static TCGv cpu_rampZ;
58e03feba0SMichael Rolnik 
59e03feba0SMichael Rolnik static TCGv cpu_r[NUMBER_OF_CPU_REGISTERS];
60e03feba0SMichael Rolnik static TCGv cpu_eind;
61e03feba0SMichael Rolnik static TCGv cpu_sp;
62e03feba0SMichael Rolnik 
63e03feba0SMichael Rolnik static TCGv cpu_skip;
64e03feba0SMichael Rolnik 
65e03feba0SMichael Rolnik static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = {
66e03feba0SMichael Rolnik     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
67e03feba0SMichael Rolnik     "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
68e03feba0SMichael Rolnik     "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
69e03feba0SMichael Rolnik     "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
70e03feba0SMichael Rolnik };
71e03feba0SMichael Rolnik #define REG(x) (cpu_r[x])
72e03feba0SMichael Rolnik 
73e03feba0SMichael Rolnik enum {
74e03feba0SMichael Rolnik     DISAS_EXIT   = DISAS_TARGET_0,  /* We want return to the cpu main loop.  */
75e03feba0SMichael Rolnik     DISAS_LOOKUP = DISAS_TARGET_1,  /* We have a variable condition exit.  */
76e03feba0SMichael Rolnik     DISAS_CHAIN  = DISAS_TARGET_2,  /* We have a single condition exit.  */
77e03feba0SMichael Rolnik };
78e03feba0SMichael Rolnik 
79e03feba0SMichael Rolnik typedef struct DisasContext DisasContext;
80e03feba0SMichael Rolnik 
81e03feba0SMichael Rolnik /* This is the state at translation time. */
82e03feba0SMichael Rolnik struct DisasContext {
83e03feba0SMichael Rolnik     TranslationBlock *tb;
84e03feba0SMichael Rolnik 
85e03feba0SMichael Rolnik     CPUAVRState *env;
86e03feba0SMichael Rolnik     CPUState *cs;
87e03feba0SMichael Rolnik 
88e03feba0SMichael Rolnik     target_long npc;
89e03feba0SMichael Rolnik     uint32_t opcode;
90e03feba0SMichael Rolnik 
91e03feba0SMichael Rolnik     /* Routine used to access memory */
92e03feba0SMichael Rolnik     int memidx;
93e03feba0SMichael Rolnik     int bstate;
94e03feba0SMichael Rolnik     int singlestep;
95e03feba0SMichael Rolnik 
96e03feba0SMichael Rolnik     /*
97e03feba0SMichael Rolnik      * some AVR instructions can make the following instruction to be skipped
98e03feba0SMichael Rolnik      * Let's name those instructions
99e03feba0SMichael Rolnik      *     A   - instruction that can skip the next one
100e03feba0SMichael Rolnik      *     B   - instruction that can be skipped. this depends on execution of A
101e03feba0SMichael Rolnik      * there are two scenarios
102e03feba0SMichael Rolnik      * 1. A and B belong to the same translation block
103e03feba0SMichael Rolnik      * 2. A is the last instruction in the translation block and B is the last
104e03feba0SMichael Rolnik      *
105e03feba0SMichael Rolnik      * following variables are used to simplify the skipping logic, they are
106e03feba0SMichael Rolnik      * used in the following manner (sketch)
107e03feba0SMichael Rolnik      *
108e03feba0SMichael Rolnik      * TCGLabel *skip_label = NULL;
109e03feba0SMichael Rolnik      * if (ctx.skip_cond != TCG_COND_NEVER) {
110e03feba0SMichael Rolnik      *     skip_label = gen_new_label();
111e03feba0SMichael Rolnik      *     tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label);
112e03feba0SMichael Rolnik      * }
113e03feba0SMichael Rolnik      *
114e03feba0SMichael Rolnik      * if (free_skip_var0) {
115e03feba0SMichael Rolnik      *     tcg_temp_free(skip_var0);
116e03feba0SMichael Rolnik      *     free_skip_var0 = false;
117e03feba0SMichael Rolnik      * }
118e03feba0SMichael Rolnik      *
119e03feba0SMichael Rolnik      * translate(&ctx);
120e03feba0SMichael Rolnik      *
121e03feba0SMichael Rolnik      * if (skip_label) {
122e03feba0SMichael Rolnik      *     gen_set_label(skip_label);
123e03feba0SMichael Rolnik      * }
124e03feba0SMichael Rolnik      */
125e03feba0SMichael Rolnik     TCGv skip_var0;
126e03feba0SMichael Rolnik     TCGv skip_var1;
127e03feba0SMichael Rolnik     TCGCond skip_cond;
128e03feba0SMichael Rolnik     bool free_skip_var0;
129e03feba0SMichael Rolnik };
130e03feba0SMichael Rolnik 
131*a107fdb0SMichael Rolnik void avr_cpu_tcg_init(void)
132*a107fdb0SMichael Rolnik {
133*a107fdb0SMichael Rolnik     int i;
134*a107fdb0SMichael Rolnik 
135*a107fdb0SMichael Rolnik #define AVR_REG_OFFS(x) offsetof(CPUAVRState, x)
136*a107fdb0SMichael Rolnik     cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w), "pc");
137*a107fdb0SMichael Rolnik     cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf");
138*a107fdb0SMichael Rolnik     cpu_Zf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf");
139*a107fdb0SMichael Rolnik     cpu_Nf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf");
140*a107fdb0SMichael Rolnik     cpu_Vf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf");
141*a107fdb0SMichael Rolnik     cpu_Sf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf");
142*a107fdb0SMichael Rolnik     cpu_Hf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf");
143*a107fdb0SMichael Rolnik     cpu_Tf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf");
144*a107fdb0SMichael Rolnik     cpu_If = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If");
145*a107fdb0SMichael Rolnik     cpu_rampD = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), "rampD");
146*a107fdb0SMichael Rolnik     cpu_rampX = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), "rampX");
147*a107fdb0SMichael Rolnik     cpu_rampY = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), "rampY");
148*a107fdb0SMichael Rolnik     cpu_rampZ = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), "rampZ");
149*a107fdb0SMichael Rolnik     cpu_eind = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind), "eind");
150*a107fdb0SMichael Rolnik     cpu_sp = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp), "sp");
151*a107fdb0SMichael Rolnik     cpu_skip = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(skip), "skip");
152*a107fdb0SMichael Rolnik 
153*a107fdb0SMichael Rolnik     for (i = 0; i < NUMBER_OF_CPU_REGISTERS; i++) {
154*a107fdb0SMichael Rolnik         cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]),
155*a107fdb0SMichael Rolnik                                           reg_names[i]);
156*a107fdb0SMichael Rolnik     }
157*a107fdb0SMichael Rolnik #undef AVR_REG_OFFS
158*a107fdb0SMichael Rolnik }
159*a107fdb0SMichael Rolnik 
160865f3bb9SMichael Rolnik static int to_regs_16_31_by_one(DisasContext *ctx, int indx)
161865f3bb9SMichael Rolnik {
162865f3bb9SMichael Rolnik     return 16 + (indx % 16);
163865f3bb9SMichael Rolnik }
164865f3bb9SMichael Rolnik 
165865f3bb9SMichael Rolnik static int to_regs_16_23_by_one(DisasContext *ctx, int indx)
166865f3bb9SMichael Rolnik {
167865f3bb9SMichael Rolnik     return 16 + (indx % 8);
168865f3bb9SMichael Rolnik }
169865f3bb9SMichael Rolnik 
170865f3bb9SMichael Rolnik static int to_regs_24_30_by_two(DisasContext *ctx, int indx)
171865f3bb9SMichael Rolnik {
172865f3bb9SMichael Rolnik     return 24 + (indx % 4) * 2;
173865f3bb9SMichael Rolnik }
174865f3bb9SMichael Rolnik 
1759732b024SMichael Rolnik static int to_regs_00_30_by_two(DisasContext *ctx, int indx)
1769732b024SMichael Rolnik {
1779732b024SMichael Rolnik     return (indx % 16) * 2;
1789732b024SMichael Rolnik }
179865f3bb9SMichael Rolnik 
1809d316c75SMichael Rolnik static uint16_t next_word(DisasContext *ctx)
1819d316c75SMichael Rolnik {
1829d316c75SMichael Rolnik     return cpu_lduw_code(ctx->env, ctx->npc++ * 2);
1839d316c75SMichael Rolnik }
1849d316c75SMichael Rolnik 
1859d316c75SMichael Rolnik static int append_16(DisasContext *ctx, int x)
1869d316c75SMichael Rolnik {
1879d316c75SMichael Rolnik     return x << 16 | next_word(ctx);
1889d316c75SMichael Rolnik }
1899d316c75SMichael Rolnik 
190e03feba0SMichael Rolnik static bool avr_have_feature(DisasContext *ctx, int feature)
191e03feba0SMichael Rolnik {
192e03feba0SMichael Rolnik     if (!avr_feature(ctx->env, feature)) {
193e03feba0SMichael Rolnik         gen_helper_unsupported(cpu_env);
194e03feba0SMichael Rolnik         ctx->bstate = DISAS_NORETURN;
195e03feba0SMichael Rolnik         return false;
196e03feba0SMichael Rolnik     }
197e03feba0SMichael Rolnik     return true;
198e03feba0SMichael Rolnik }
199e03feba0SMichael Rolnik 
200e03feba0SMichael Rolnik static bool decode_insn(DisasContext *ctx, uint16_t insn);
201e03feba0SMichael Rolnik #include "decode_insn.inc.c"
202865f3bb9SMichael Rolnik 
203865f3bb9SMichael Rolnik /*
204865f3bb9SMichael Rolnik  * Arithmetic Instructions
205865f3bb9SMichael Rolnik  */
206865f3bb9SMichael Rolnik 
207865f3bb9SMichael Rolnik /*
208865f3bb9SMichael Rolnik  * Utility functions for updating status registers:
209865f3bb9SMichael Rolnik  *
210865f3bb9SMichael Rolnik  *   - gen_add_CHf()
211865f3bb9SMichael Rolnik  *   - gen_add_Vf()
212865f3bb9SMichael Rolnik  *   - gen_sub_CHf()
213865f3bb9SMichael Rolnik  *   - gen_sub_Vf()
214865f3bb9SMichael Rolnik  *   - gen_NSf()
215865f3bb9SMichael Rolnik  *   - gen_ZNSf()
216865f3bb9SMichael Rolnik  *
217865f3bb9SMichael Rolnik  */
218865f3bb9SMichael Rolnik 
219865f3bb9SMichael Rolnik static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr)
220865f3bb9SMichael Rolnik {
221865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
222865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
223865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
224865f3bb9SMichael Rolnik 
225865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */
226865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */
227865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */
228865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */
229865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t3);
230865f3bb9SMichael Rolnik 
231865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */
232865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */
233865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
234865f3bb9SMichael Rolnik 
235865f3bb9SMichael Rolnik     tcg_temp_free_i32(t3);
236865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
237865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
238865f3bb9SMichael Rolnik }
239865f3bb9SMichael Rolnik 
240865f3bb9SMichael Rolnik static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
241865f3bb9SMichael Rolnik {
242865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
243865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
244865f3bb9SMichael Rolnik 
245865f3bb9SMichael Rolnik     /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */
246865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & ~(Rd ^ Rr) */
247865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
248865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
249865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t1, t1, t2);
250865f3bb9SMichael Rolnik 
251865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
252865f3bb9SMichael Rolnik 
253865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
254865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
255865f3bb9SMichael Rolnik }
256865f3bb9SMichael Rolnik 
257865f3bb9SMichael Rolnik static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
258865f3bb9SMichael Rolnik {
259865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
260865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
261865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
262865f3bb9SMichael Rolnik 
263865f3bb9SMichael Rolnik     tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */
264865f3bb9SMichael Rolnik     tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */
265865f3bb9SMichael Rolnik     tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */
266865f3bb9SMichael Rolnik     tcg_gen_and_tl(t3, t3, R);
267865f3bb9SMichael Rolnik     tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */
268865f3bb9SMichael Rolnik 
269865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */
270865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */
271865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
272865f3bb9SMichael Rolnik 
273865f3bb9SMichael Rolnik     tcg_temp_free_i32(t3);
274865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
275865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
276865f3bb9SMichael Rolnik }
277865f3bb9SMichael Rolnik 
278865f3bb9SMichael Rolnik static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
279865f3bb9SMichael Rolnik {
280865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
281865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
282865f3bb9SMichael Rolnik 
283865f3bb9SMichael Rolnik     /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */
284865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & (Rd ^ R) */
285865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
286865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
287865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, t1, t2);
288865f3bb9SMichael Rolnik 
289865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
290865f3bb9SMichael Rolnik 
291865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
292865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
293865f3bb9SMichael Rolnik }
294865f3bb9SMichael Rolnik 
295865f3bb9SMichael Rolnik static void gen_NSf(TCGv R)
296865f3bb9SMichael Rolnik {
297865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
298865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
299865f3bb9SMichael Rolnik }
300865f3bb9SMichael Rolnik 
301865f3bb9SMichael Rolnik static void gen_ZNSf(TCGv R)
302865f3bb9SMichael Rolnik {
303865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
304865f3bb9SMichael Rolnik 
305865f3bb9SMichael Rolnik     /* update status register */
306865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
307865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
308865f3bb9SMichael Rolnik }
309865f3bb9SMichael Rolnik 
310865f3bb9SMichael Rolnik /*
311865f3bb9SMichael Rolnik  *  Adds two registers without the C Flag and places the result in the
312865f3bb9SMichael Rolnik  *  destination register Rd.
313865f3bb9SMichael Rolnik  */
314865f3bb9SMichael Rolnik static bool trans_ADD(DisasContext *ctx, arg_ADD *a)
315865f3bb9SMichael Rolnik {
316865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
317865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
318865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
319865f3bb9SMichael Rolnik 
320865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */
321865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
322865f3bb9SMichael Rolnik 
323865f3bb9SMichael Rolnik     /* update status register */
324865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
325865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
326865f3bb9SMichael Rolnik     gen_ZNSf(R);
327865f3bb9SMichael Rolnik 
328865f3bb9SMichael Rolnik     /* update output registers */
329865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
330865f3bb9SMichael Rolnik 
331865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
332865f3bb9SMichael Rolnik 
333865f3bb9SMichael Rolnik     return true;
334865f3bb9SMichael Rolnik }
335865f3bb9SMichael Rolnik 
336865f3bb9SMichael Rolnik /*
337865f3bb9SMichael Rolnik  *  Adds two registers and the contents of the C Flag and places the result in
338865f3bb9SMichael Rolnik  *  the destination register Rd.
339865f3bb9SMichael Rolnik  */
340865f3bb9SMichael Rolnik static bool trans_ADC(DisasContext *ctx, arg_ADC *a)
341865f3bb9SMichael Rolnik {
342865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
343865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
344865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
345865f3bb9SMichael Rolnik 
346865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */
347865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, R, cpu_Cf);
348865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
349865f3bb9SMichael Rolnik 
350865f3bb9SMichael Rolnik     /* update status register */
351865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
352865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
353865f3bb9SMichael Rolnik     gen_ZNSf(R);
354865f3bb9SMichael Rolnik 
355865f3bb9SMichael Rolnik     /* update output registers */
356865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
357865f3bb9SMichael Rolnik 
358865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
359865f3bb9SMichael Rolnik 
360865f3bb9SMichael Rolnik     return true;
361865f3bb9SMichael Rolnik }
362865f3bb9SMichael Rolnik 
363865f3bb9SMichael Rolnik /*
364865f3bb9SMichael Rolnik  *  Adds an immediate value (0 - 63) to a register pair and places the result
365865f3bb9SMichael Rolnik  *  in the register pair. This instruction operates on the upper four register
366865f3bb9SMichael Rolnik  *  pairs, and is well suited for operations on the pointer registers.  This
367865f3bb9SMichael Rolnik  *  instruction is not available in all devices. Refer to the device specific
368865f3bb9SMichael Rolnik  *  instruction set summary.
369865f3bb9SMichael Rolnik  */
370865f3bb9SMichael Rolnik static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a)
371865f3bb9SMichael Rolnik {
372865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
373865f3bb9SMichael Rolnik         return true;
374865f3bb9SMichael Rolnik     }
375865f3bb9SMichael Rolnik 
376865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
377865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
378865f3bb9SMichael Rolnik     int Imm = (a->imm);
379865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
380865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
381865f3bb9SMichael Rolnik 
382865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
383865f3bb9SMichael Rolnik     tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */
384865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
385865f3bb9SMichael Rolnik 
386865f3bb9SMichael Rolnik     /* update status register */
387865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
388865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15);
389865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */
390865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15);
391865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
392865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
393865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */
394865f3bb9SMichael Rolnik 
395865f3bb9SMichael Rolnik     /* update output registers */
396865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
397865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
398865f3bb9SMichael Rolnik 
399865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rd);
400865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
401865f3bb9SMichael Rolnik 
402865f3bb9SMichael Rolnik     return true;
403865f3bb9SMichael Rolnik }
404865f3bb9SMichael Rolnik 
405865f3bb9SMichael Rolnik /*
406865f3bb9SMichael Rolnik  *  Subtracts two registers and places the result in the destination
407865f3bb9SMichael Rolnik  *  register Rd.
408865f3bb9SMichael Rolnik  */
409865f3bb9SMichael Rolnik static bool trans_SUB(DisasContext *ctx, arg_SUB *a)
410865f3bb9SMichael Rolnik {
411865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
412865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
413865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
414865f3bb9SMichael Rolnik 
415865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
416865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
417865f3bb9SMichael Rolnik 
418865f3bb9SMichael Rolnik     /* update status register */
419865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
420865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
421865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
422865f3bb9SMichael Rolnik     gen_ZNSf(R);
423865f3bb9SMichael Rolnik 
424865f3bb9SMichael Rolnik     /* update output registers */
425865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
426865f3bb9SMichael Rolnik 
427865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
428865f3bb9SMichael Rolnik 
429865f3bb9SMichael Rolnik     return true;
430865f3bb9SMichael Rolnik }
431865f3bb9SMichael Rolnik 
432865f3bb9SMichael Rolnik /*
433865f3bb9SMichael Rolnik  *  Subtracts a register and a constant and places the result in the
434865f3bb9SMichael Rolnik  *  destination register Rd. This instruction is working on Register R16 to R31
435865f3bb9SMichael Rolnik  *  and is very well suited for operations on the X, Y, and Z-pointers.
436865f3bb9SMichael Rolnik  */
437865f3bb9SMichael Rolnik static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a)
438865f3bb9SMichael Rolnik {
439865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
440865f3bb9SMichael Rolnik     TCGv Rr = tcg_const_i32(a->imm);
441865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
442865f3bb9SMichael Rolnik 
443865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */
444865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
445865f3bb9SMichael Rolnik 
446865f3bb9SMichael Rolnik     /* update status register */
447865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
448865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
449865f3bb9SMichael Rolnik     gen_ZNSf(R);
450865f3bb9SMichael Rolnik 
451865f3bb9SMichael Rolnik     /* update output registers */
452865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
453865f3bb9SMichael Rolnik 
454865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
455865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rr);
456865f3bb9SMichael Rolnik 
457865f3bb9SMichael Rolnik     return true;
458865f3bb9SMichael Rolnik }
459865f3bb9SMichael Rolnik 
460865f3bb9SMichael Rolnik /*
461865f3bb9SMichael Rolnik  *  Subtracts two registers and subtracts with the C Flag and places the
462865f3bb9SMichael Rolnik  *  result in the destination register Rd.
463865f3bb9SMichael Rolnik  */
464865f3bb9SMichael Rolnik static bool trans_SBC(DisasContext *ctx, arg_SBC *a)
465865f3bb9SMichael Rolnik {
466865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
467865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
468865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
469865f3bb9SMichael Rolnik     TCGv zero = tcg_const_i32(0);
470865f3bb9SMichael Rolnik 
471865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
472865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
473865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
474865f3bb9SMichael Rolnik 
475865f3bb9SMichael Rolnik     /* update status register */
476865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
477865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
478865f3bb9SMichael Rolnik     gen_NSf(R);
479865f3bb9SMichael Rolnik 
480865f3bb9SMichael Rolnik     /*
481865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
482865f3bb9SMichael Rolnik      * cleared otherwise.
483865f3bb9SMichael Rolnik      */
484865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
485865f3bb9SMichael Rolnik 
486865f3bb9SMichael Rolnik     /* update output registers */
487865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
488865f3bb9SMichael Rolnik 
489865f3bb9SMichael Rolnik     tcg_temp_free_i32(zero);
490865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
491865f3bb9SMichael Rolnik 
492865f3bb9SMichael Rolnik     return true;
493865f3bb9SMichael Rolnik }
494865f3bb9SMichael Rolnik 
495865f3bb9SMichael Rolnik /*
496865f3bb9SMichael Rolnik  *  SBCI -- Subtract Immediate with Carry
497865f3bb9SMichael Rolnik  */
498865f3bb9SMichael Rolnik static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a)
499865f3bb9SMichael Rolnik {
500865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
501865f3bb9SMichael Rolnik     TCGv Rr = tcg_const_i32(a->imm);
502865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
503865f3bb9SMichael Rolnik     TCGv zero = tcg_const_i32(0);
504865f3bb9SMichael Rolnik 
505865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
506865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
507865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
508865f3bb9SMichael Rolnik 
509865f3bb9SMichael Rolnik     /* update status register */
510865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
511865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
512865f3bb9SMichael Rolnik     gen_NSf(R);
513865f3bb9SMichael Rolnik 
514865f3bb9SMichael Rolnik     /*
515865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
516865f3bb9SMichael Rolnik      * cleared otherwise.
517865f3bb9SMichael Rolnik      */
518865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
519865f3bb9SMichael Rolnik 
520865f3bb9SMichael Rolnik     /* update output registers */
521865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
522865f3bb9SMichael Rolnik 
523865f3bb9SMichael Rolnik     tcg_temp_free_i32(zero);
524865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
525865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rr);
526865f3bb9SMichael Rolnik 
527865f3bb9SMichael Rolnik     return true;
528865f3bb9SMichael Rolnik }
529865f3bb9SMichael Rolnik 
530865f3bb9SMichael Rolnik /*
531865f3bb9SMichael Rolnik  *  Subtracts an immediate value (0-63) from a register pair and places the
532865f3bb9SMichael Rolnik  *  result in the register pair. This instruction operates on the upper four
533865f3bb9SMichael Rolnik  *  register pairs, and is well suited for operations on the Pointer Registers.
534865f3bb9SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
535865f3bb9SMichael Rolnik  *  specific instruction set summary.
536865f3bb9SMichael Rolnik  */
537865f3bb9SMichael Rolnik static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a)
538865f3bb9SMichael Rolnik {
539865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
540865f3bb9SMichael Rolnik         return true;
541865f3bb9SMichael Rolnik     }
542865f3bb9SMichael Rolnik 
543865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
544865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
545865f3bb9SMichael Rolnik     int Imm = (a->imm);
546865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
547865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
548865f3bb9SMichael Rolnik 
549865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
550865f3bb9SMichael Rolnik     tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */
551865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
552865f3bb9SMichael Rolnik 
553865f3bb9SMichael Rolnik     /* update status register */
554865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, R, Rd);
555865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */
556865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, Rd, R);
557865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */
558865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
559865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
560865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
561865f3bb9SMichael Rolnik 
562865f3bb9SMichael Rolnik     /* update output registers */
563865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
564865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
565865f3bb9SMichael Rolnik 
566865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rd);
567865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
568865f3bb9SMichael Rolnik 
569865f3bb9SMichael Rolnik     return true;
570865f3bb9SMichael Rolnik }
571865f3bb9SMichael Rolnik 
572865f3bb9SMichael Rolnik /*
573865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and register
574865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
575865f3bb9SMichael Rolnik  */
576865f3bb9SMichael Rolnik static bool trans_AND(DisasContext *ctx, arg_AND *a)
577865f3bb9SMichael Rolnik {
578865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
579865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
580865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
581865f3bb9SMichael Rolnik 
582865f3bb9SMichael Rolnik     tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */
583865f3bb9SMichael Rolnik 
584865f3bb9SMichael Rolnik     /* update status register */
585865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
586865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
587865f3bb9SMichael Rolnik     gen_ZNSf(R);
588865f3bb9SMichael Rolnik 
589865f3bb9SMichael Rolnik     /* update output registers */
590865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
591865f3bb9SMichael Rolnik 
592865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
593865f3bb9SMichael Rolnik 
594865f3bb9SMichael Rolnik     return true;
595865f3bb9SMichael Rolnik }
596865f3bb9SMichael Rolnik 
597865f3bb9SMichael Rolnik /*
598865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and a constant
599865f3bb9SMichael Rolnik  *  and places the result in the destination register Rd.
600865f3bb9SMichael Rolnik  */
601865f3bb9SMichael Rolnik static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a)
602865f3bb9SMichael Rolnik {
603865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
604865f3bb9SMichael Rolnik     int Imm = (a->imm);
605865f3bb9SMichael Rolnik 
606865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */
607865f3bb9SMichael Rolnik 
608865f3bb9SMichael Rolnik     /* update status register */
609865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
610865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
611865f3bb9SMichael Rolnik 
612865f3bb9SMichael Rolnik     return true;
613865f3bb9SMichael Rolnik }
614865f3bb9SMichael Rolnik 
615865f3bb9SMichael Rolnik /*
616865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and register
617865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
618865f3bb9SMichael Rolnik  */
619865f3bb9SMichael Rolnik static bool trans_OR(DisasContext *ctx, arg_OR *a)
620865f3bb9SMichael Rolnik {
621865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
622865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
623865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
624865f3bb9SMichael Rolnik 
625865f3bb9SMichael Rolnik     tcg_gen_or_tl(R, Rd, Rr);
626865f3bb9SMichael Rolnik 
627865f3bb9SMichael Rolnik     /* update status register */
628865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
629865f3bb9SMichael Rolnik     gen_ZNSf(R);
630865f3bb9SMichael Rolnik 
631865f3bb9SMichael Rolnik     /* update output registers */
632865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
633865f3bb9SMichael Rolnik 
634865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
635865f3bb9SMichael Rolnik 
636865f3bb9SMichael Rolnik     return true;
637865f3bb9SMichael Rolnik }
638865f3bb9SMichael Rolnik 
639865f3bb9SMichael Rolnik /*
640865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and a
641865f3bb9SMichael Rolnik  *  constant and places the result in the destination register Rd.
642865f3bb9SMichael Rolnik  */
643865f3bb9SMichael Rolnik static bool trans_ORI(DisasContext *ctx, arg_ORI *a)
644865f3bb9SMichael Rolnik {
645865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
646865f3bb9SMichael Rolnik     int Imm = (a->imm);
647865f3bb9SMichael Rolnik 
648865f3bb9SMichael Rolnik     tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */
649865f3bb9SMichael Rolnik 
650865f3bb9SMichael Rolnik     /* update status register */
651865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
652865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
653865f3bb9SMichael Rolnik 
654865f3bb9SMichael Rolnik     return true;
655865f3bb9SMichael Rolnik }
656865f3bb9SMichael Rolnik 
657865f3bb9SMichael Rolnik /*
658865f3bb9SMichael Rolnik  *  Performs the logical EOR between the contents of register Rd and
659865f3bb9SMichael Rolnik  *  register Rr and places the result in the destination register Rd.
660865f3bb9SMichael Rolnik  */
661865f3bb9SMichael Rolnik static bool trans_EOR(DisasContext *ctx, arg_EOR *a)
662865f3bb9SMichael Rolnik {
663865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
664865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
665865f3bb9SMichael Rolnik 
666865f3bb9SMichael Rolnik     tcg_gen_xor_tl(Rd, Rd, Rr);
667865f3bb9SMichael Rolnik 
668865f3bb9SMichael Rolnik     /* update status register */
669865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
670865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
671865f3bb9SMichael Rolnik 
672865f3bb9SMichael Rolnik     return true;
673865f3bb9SMichael Rolnik }
674865f3bb9SMichael Rolnik 
675865f3bb9SMichael Rolnik /*
676865f3bb9SMichael Rolnik  *  Clears the specified bits in register Rd. Performs the logical AND
677865f3bb9SMichael Rolnik  *  between the contents of register Rd and the complement of the constant mask
678865f3bb9SMichael Rolnik  *  K. The result will be placed in register Rd.
679865f3bb9SMichael Rolnik  */
680865f3bb9SMichael Rolnik static bool trans_COM(DisasContext *ctx, arg_COM *a)
681865f3bb9SMichael Rolnik {
682865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
683865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
684865f3bb9SMichael Rolnik 
685865f3bb9SMichael Rolnik     tcg_gen_xori_tl(Rd, Rd, 0xff);
686865f3bb9SMichael Rolnik 
687865f3bb9SMichael Rolnik     /* update status register */
688865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */
689865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
690865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
691865f3bb9SMichael Rolnik 
692865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
693865f3bb9SMichael Rolnik 
694865f3bb9SMichael Rolnik     return true;
695865f3bb9SMichael Rolnik }
696865f3bb9SMichael Rolnik 
697865f3bb9SMichael Rolnik /*
698865f3bb9SMichael Rolnik  *  Replaces the contents of register Rd with its two's complement; the
699865f3bb9SMichael Rolnik  *  value $80 is left unchanged.
700865f3bb9SMichael Rolnik  */
701865f3bb9SMichael Rolnik static bool trans_NEG(DisasContext *ctx, arg_NEG *a)
702865f3bb9SMichael Rolnik {
703865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
704865f3bb9SMichael Rolnik     TCGv t0 = tcg_const_i32(0);
705865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
706865f3bb9SMichael Rolnik 
707865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */
708865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
709865f3bb9SMichael Rolnik 
710865f3bb9SMichael Rolnik     /* update status register */
711865f3bb9SMichael Rolnik     gen_sub_CHf(R, t0, Rd);
712865f3bb9SMichael Rolnik     gen_sub_Vf(R, t0, Rd);
713865f3bb9SMichael Rolnik     gen_ZNSf(R);
714865f3bb9SMichael Rolnik 
715865f3bb9SMichael Rolnik     /* update output registers */
716865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
717865f3bb9SMichael Rolnik 
718865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
719865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
720865f3bb9SMichael Rolnik 
721865f3bb9SMichael Rolnik     return true;
722865f3bb9SMichael Rolnik }
723865f3bb9SMichael Rolnik 
724865f3bb9SMichael Rolnik /*
725865f3bb9SMichael Rolnik  *  Adds one -1- to the contents of register Rd and places the result in the
726865f3bb9SMichael Rolnik  *  destination register Rd.  The C Flag in SREG is not affected by the
727865f3bb9SMichael Rolnik  *  operation, thus allowing the INC instruction to be used on a loop counter in
728865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned numbers, only
729865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently. When
730865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
731865f3bb9SMichael Rolnik  */
732865f3bb9SMichael Rolnik static bool trans_INC(DisasContext *ctx, arg_INC *a)
733865f3bb9SMichael Rolnik {
734865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
735865f3bb9SMichael Rolnik 
736865f3bb9SMichael Rolnik     tcg_gen_addi_tl(Rd, Rd, 1);
737865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff);
738865f3bb9SMichael Rolnik 
739865f3bb9SMichael Rolnik     /* update status register */
740865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */
741865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
742865f3bb9SMichael Rolnik 
743865f3bb9SMichael Rolnik     return true;
744865f3bb9SMichael Rolnik }
745865f3bb9SMichael Rolnik 
746865f3bb9SMichael Rolnik /*
747865f3bb9SMichael Rolnik  *  Subtracts one -1- from the contents of register Rd and places the result
748865f3bb9SMichael Rolnik  *  in the destination register Rd.  The C Flag in SREG is not affected by the
749865f3bb9SMichael Rolnik  *  operation, thus allowing the DEC instruction to be used on a loop counter in
750865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned values, only
751865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently.  When
752865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
753865f3bb9SMichael Rolnik  */
754865f3bb9SMichael Rolnik static bool trans_DEC(DisasContext *ctx, arg_DEC *a)
755865f3bb9SMichael Rolnik {
756865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
757865f3bb9SMichael Rolnik 
758865f3bb9SMichael Rolnik     tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
759865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
760865f3bb9SMichael Rolnik 
761865f3bb9SMichael Rolnik     /* update status register */
762865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */
763865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
764865f3bb9SMichael Rolnik 
765865f3bb9SMichael Rolnik     return true;
766865f3bb9SMichael Rolnik }
767865f3bb9SMichael Rolnik 
768865f3bb9SMichael Rolnik /*
769865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication.
770865f3bb9SMichael Rolnik  */
771865f3bb9SMichael Rolnik static bool trans_MUL(DisasContext *ctx, arg_MUL *a)
772865f3bb9SMichael Rolnik {
773865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
774865f3bb9SMichael Rolnik         return true;
775865f3bb9SMichael Rolnik     }
776865f3bb9SMichael Rolnik 
777865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
778865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
779865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
780865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
781865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
782865f3bb9SMichael Rolnik 
783865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
784865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
785865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
786865f3bb9SMichael Rolnik 
787865f3bb9SMichael Rolnik     /* update status register */
788865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
789865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
790865f3bb9SMichael Rolnik 
791865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
792865f3bb9SMichael Rolnik 
793865f3bb9SMichael Rolnik     return true;
794865f3bb9SMichael Rolnik }
795865f3bb9SMichael Rolnik 
796865f3bb9SMichael Rolnik /*
797865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication.
798865f3bb9SMichael Rolnik  */
799865f3bb9SMichael Rolnik static bool trans_MULS(DisasContext *ctx, arg_MULS *a)
800865f3bb9SMichael Rolnik {
801865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
802865f3bb9SMichael Rolnik         return true;
803865f3bb9SMichael Rolnik     }
804865f3bb9SMichael Rolnik 
805865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
806865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
807865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
808865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
809865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
810865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
811865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
812865f3bb9SMichael Rolnik 
813865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
814865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
815865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
816865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
817865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
818865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
819865f3bb9SMichael Rolnik 
820865f3bb9SMichael Rolnik     /* update status register */
821865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
822865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
823865f3bb9SMichael Rolnik 
824865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
825865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
826865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
827865f3bb9SMichael Rolnik 
828865f3bb9SMichael Rolnik     return true;
829865f3bb9SMichael Rolnik }
830865f3bb9SMichael Rolnik 
831865f3bb9SMichael Rolnik /*
832865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a
833865f3bb9SMichael Rolnik  *  signed and an unsigned number.
834865f3bb9SMichael Rolnik  */
835865f3bb9SMichael Rolnik static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a)
836865f3bb9SMichael Rolnik {
837865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
838865f3bb9SMichael Rolnik         return true;
839865f3bb9SMichael Rolnik     }
840865f3bb9SMichael Rolnik 
841865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
842865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
843865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
844865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
845865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
846865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
847865f3bb9SMichael Rolnik 
848865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
849865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
850865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */
851865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
852865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
853865f3bb9SMichael Rolnik 
854865f3bb9SMichael Rolnik     /* update status register */
855865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
856865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
857865f3bb9SMichael Rolnik 
858865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
859865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
860865f3bb9SMichael Rolnik 
861865f3bb9SMichael Rolnik     return true;
862865f3bb9SMichael Rolnik }
863865f3bb9SMichael Rolnik 
864865f3bb9SMichael Rolnik /*
865865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned
866865f3bb9SMichael Rolnik  *  multiplication and shifts the result one bit left.
867865f3bb9SMichael Rolnik  */
868865f3bb9SMichael Rolnik static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a)
869865f3bb9SMichael Rolnik {
870865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
871865f3bb9SMichael Rolnik         return true;
872865f3bb9SMichael Rolnik     }
873865f3bb9SMichael Rolnik 
874865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
875865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
876865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
877865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
878865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
879865f3bb9SMichael Rolnik 
880865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
881865f3bb9SMichael Rolnik 
882865f3bb9SMichael Rolnik     /* update status register */
883865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
884865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
885865f3bb9SMichael Rolnik 
886865f3bb9SMichael Rolnik     /* update output registers */
887865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
888865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
889865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
890865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
891865f3bb9SMichael Rolnik 
892865f3bb9SMichael Rolnik 
893865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
894865f3bb9SMichael Rolnik 
895865f3bb9SMichael Rolnik     return true;
896865f3bb9SMichael Rolnik }
897865f3bb9SMichael Rolnik 
898865f3bb9SMichael Rolnik /*
899865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
900865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
901865f3bb9SMichael Rolnik  */
902865f3bb9SMichael Rolnik static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a)
903865f3bb9SMichael Rolnik {
904865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
905865f3bb9SMichael Rolnik         return true;
906865f3bb9SMichael Rolnik     }
907865f3bb9SMichael Rolnik 
908865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
909865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
910865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
911865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
912865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
913865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
914865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
915865f3bb9SMichael Rolnik 
916865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
917865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
918865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
919865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
920865f3bb9SMichael Rolnik 
921865f3bb9SMichael Rolnik     /* update status register */
922865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
923865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
924865f3bb9SMichael Rolnik 
925865f3bb9SMichael Rolnik     /* update output registers */
926865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
927865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
928865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
929865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
930865f3bb9SMichael Rolnik 
931865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
932865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
933865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
934865f3bb9SMichael Rolnik 
935865f3bb9SMichael Rolnik     return true;
936865f3bb9SMichael Rolnik }
937865f3bb9SMichael Rolnik 
938865f3bb9SMichael Rolnik /*
939865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
940865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
941865f3bb9SMichael Rolnik  */
942865f3bb9SMichael Rolnik static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a)
943865f3bb9SMichael Rolnik {
944865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
945865f3bb9SMichael Rolnik         return true;
946865f3bb9SMichael Rolnik     }
947865f3bb9SMichael Rolnik 
948865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
949865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
950865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
951865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
952865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
953865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
954865f3bb9SMichael Rolnik 
955865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
956865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
957865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
958865f3bb9SMichael Rolnik 
959865f3bb9SMichael Rolnik     /* update status register */
960865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
961865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
962865f3bb9SMichael Rolnik 
963865f3bb9SMichael Rolnik     /* update output registers */
964865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
965865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
966865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
967865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
968865f3bb9SMichael Rolnik 
969865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
970865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
971865f3bb9SMichael Rolnik 
972865f3bb9SMichael Rolnik     return true;
973865f3bb9SMichael Rolnik }
974865f3bb9SMichael Rolnik 
975865f3bb9SMichael Rolnik /*
976865f3bb9SMichael Rolnik  *  The module is an instruction set extension to the AVR CPU, performing
977865f3bb9SMichael Rolnik  *  DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in
978865f3bb9SMichael Rolnik  *  the CPU register file, registers R0-R7, where LSB of data is placed in LSB
979865f3bb9SMichael Rolnik  *  of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including
980865f3bb9SMichael Rolnik  *  parity bits) is placed in registers R8- R15, organized in the register file
981865f3bb9SMichael Rolnik  *  with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES
982865f3bb9SMichael Rolnik  *  instruction performs one round in the DES algorithm. Sixteen rounds must be
983865f3bb9SMichael Rolnik  *  executed in increasing order to form the correct DES ciphertext or
984865f3bb9SMichael Rolnik  *  plaintext. Intermediate results are stored in the register file (R0-R15)
985865f3bb9SMichael Rolnik  *  after each DES instruction. The instruction's operand (K) determines which
986865f3bb9SMichael Rolnik  *  round is executed, and the half carry flag (H) determines whether encryption
987865f3bb9SMichael Rolnik  *  or decryption is performed.  The DES algorithm is described in
988865f3bb9SMichael Rolnik  *  "Specifications for the Data Encryption Standard" (Federal Information
989865f3bb9SMichael Rolnik  *  Processing Standards Publication 46). Intermediate results in this
990865f3bb9SMichael Rolnik  *  implementation differ from the standard because the initial permutation and
991865f3bb9SMichael Rolnik  *  the inverse initial permutation are performed each iteration. This does not
992865f3bb9SMichael Rolnik  *  affect the result in the final ciphertext or plaintext, but reduces
993865f3bb9SMichael Rolnik  *  execution time.
994865f3bb9SMichael Rolnik  */
995865f3bb9SMichael Rolnik static bool trans_DES(DisasContext *ctx, arg_DES *a)
996865f3bb9SMichael Rolnik {
997865f3bb9SMichael Rolnik     /* TODO */
998865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_DES)) {
999865f3bb9SMichael Rolnik         return true;
1000865f3bb9SMichael Rolnik     }
1001865f3bb9SMichael Rolnik 
1002865f3bb9SMichael Rolnik     qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
1003865f3bb9SMichael Rolnik 
1004865f3bb9SMichael Rolnik     return true;
1005865f3bb9SMichael Rolnik }
10069d316c75SMichael Rolnik 
10079d316c75SMichael Rolnik /*
10089d316c75SMichael Rolnik  * Branch Instructions
10099d316c75SMichael Rolnik  */
10109d316c75SMichael Rolnik static void gen_jmp_ez(DisasContext *ctx)
10119d316c75SMichael Rolnik {
10129d316c75SMichael Rolnik     tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
10139d316c75SMichael Rolnik     tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind);
10149d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
10159d316c75SMichael Rolnik }
10169d316c75SMichael Rolnik 
10179d316c75SMichael Rolnik static void gen_jmp_z(DisasContext *ctx)
10189d316c75SMichael Rolnik {
10199d316c75SMichael Rolnik     tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
10209d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
10219d316c75SMichael Rolnik }
10229d316c75SMichael Rolnik 
10239d316c75SMichael Rolnik static void gen_push_ret(DisasContext *ctx, int ret)
10249d316c75SMichael Rolnik {
10259d316c75SMichael Rolnik     if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
10269d316c75SMichael Rolnik 
10279d316c75SMichael Rolnik         TCGv t0 = tcg_const_i32((ret & 0x0000ff));
10289d316c75SMichael Rolnik 
10299d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB);
10309d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10319d316c75SMichael Rolnik 
10329d316c75SMichael Rolnik         tcg_temp_free_i32(t0);
10339d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
10349d316c75SMichael Rolnik 
10359d316c75SMichael Rolnik         TCGv t0 = tcg_const_i32((ret & 0x00ffff));
10369d316c75SMichael Rolnik 
10379d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10389d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10399d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10409d316c75SMichael Rolnik 
10419d316c75SMichael Rolnik         tcg_temp_free_i32(t0);
10429d316c75SMichael Rolnik 
10439d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
10449d316c75SMichael Rolnik 
10459d316c75SMichael Rolnik         TCGv lo = tcg_const_i32((ret & 0x0000ff));
10469d316c75SMichael Rolnik         TCGv hi = tcg_const_i32((ret & 0xffff00) >> 8);
10479d316c75SMichael Rolnik 
10489d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
10499d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 2);
10509d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10519d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10529d316c75SMichael Rolnik 
10539d316c75SMichael Rolnik         tcg_temp_free_i32(lo);
10549d316c75SMichael Rolnik         tcg_temp_free_i32(hi);
10559d316c75SMichael Rolnik     }
10569d316c75SMichael Rolnik }
10579d316c75SMichael Rolnik 
10589d316c75SMichael Rolnik static void gen_pop_ret(DisasContext *ctx, TCGv ret)
10599d316c75SMichael Rolnik {
10609d316c75SMichael Rolnik     if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
10619d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10629d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB);
10639d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
10649d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10659d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10669d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10679d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
10689d316c75SMichael Rolnik         TCGv lo = tcg_temp_new_i32();
10699d316c75SMichael Rolnik         TCGv hi = tcg_temp_new_i32();
10709d316c75SMichael Rolnik 
10719d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10729d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10739d316c75SMichael Rolnik 
10749d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 2);
10759d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
10769d316c75SMichael Rolnik 
10779d316c75SMichael Rolnik         tcg_gen_deposit_tl(ret, lo, hi, 8, 16);
10789d316c75SMichael Rolnik 
10799d316c75SMichael Rolnik         tcg_temp_free_i32(lo);
10809d316c75SMichael Rolnik         tcg_temp_free_i32(hi);
10819d316c75SMichael Rolnik     }
10829d316c75SMichael Rolnik }
10839d316c75SMichael Rolnik 
10849d316c75SMichael Rolnik static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
10859d316c75SMichael Rolnik {
10869d316c75SMichael Rolnik     TranslationBlock *tb = ctx->tb;
10879d316c75SMichael Rolnik 
10889d316c75SMichael Rolnik     if (ctx->singlestep == 0) {
10899d316c75SMichael Rolnik         tcg_gen_goto_tb(n);
10909d316c75SMichael Rolnik         tcg_gen_movi_i32(cpu_pc, dest);
10919d316c75SMichael Rolnik         tcg_gen_exit_tb(tb, n);
10929d316c75SMichael Rolnik     } else {
10939d316c75SMichael Rolnik         tcg_gen_movi_i32(cpu_pc, dest);
10949d316c75SMichael Rolnik         gen_helper_debug(cpu_env);
10959d316c75SMichael Rolnik         tcg_gen_exit_tb(NULL, 0);
10969d316c75SMichael Rolnik     }
10979d316c75SMichael Rolnik     ctx->bstate = DISAS_NORETURN;
10989d316c75SMichael Rolnik }
10999d316c75SMichael Rolnik 
11009d316c75SMichael Rolnik /*
11019d316c75SMichael Rolnik  *  Relative jump to an address within PC - 2K +1 and PC + 2K (words). For
11029d316c75SMichael Rolnik  *  AVR microcontrollers with Program memory not exceeding 4K words (8KB) this
11039d316c75SMichael Rolnik  *  instruction can address the entire memory from every address location. See
11049d316c75SMichael Rolnik  *  also JMP.
11059d316c75SMichael Rolnik  */
11069d316c75SMichael Rolnik static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a)
11079d316c75SMichael Rolnik {
11089d316c75SMichael Rolnik     int dst = ctx->npc + a->imm;
11099d316c75SMichael Rolnik 
11109d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, dst);
11119d316c75SMichael Rolnik 
11129d316c75SMichael Rolnik     return true;
11139d316c75SMichael Rolnik }
11149d316c75SMichael Rolnik 
11159d316c75SMichael Rolnik /*
11169d316c75SMichael Rolnik  *  Indirect jump to the address pointed to by the Z (16 bits) Pointer
11179d316c75SMichael Rolnik  *  Register in the Register File. The Z-pointer Register is 16 bits wide and
11189d316c75SMichael Rolnik  *  allows jump within the lowest 64K words (128KB) section of Program memory.
11199d316c75SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
11209d316c75SMichael Rolnik  *  specific instruction set summary.
11219d316c75SMichael Rolnik  */
11229d316c75SMichael Rolnik static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a)
11239d316c75SMichael Rolnik {
11249d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) {
11259d316c75SMichael Rolnik         return true;
11269d316c75SMichael Rolnik     }
11279d316c75SMichael Rolnik 
11289d316c75SMichael Rolnik     gen_jmp_z(ctx);
11299d316c75SMichael Rolnik 
11309d316c75SMichael Rolnik     return true;
11319d316c75SMichael Rolnik }
11329d316c75SMichael Rolnik 
11339d316c75SMichael Rolnik /*
11349d316c75SMichael Rolnik  *  Indirect jump to the address pointed to by the Z (16 bits) Pointer
11359d316c75SMichael Rolnik  *  Register in the Register File and the EIND Register in the I/O space. This
11369d316c75SMichael Rolnik  *  instruction allows for indirect jumps to the entire 4M (words) Program
11379d316c75SMichael Rolnik  *  memory space. See also IJMP.  This instruction is not available in all
11389d316c75SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.
11399d316c75SMichael Rolnik  */
11409d316c75SMichael Rolnik static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a)
11419d316c75SMichael Rolnik {
11429d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) {
11439d316c75SMichael Rolnik         return true;
11449d316c75SMichael Rolnik     }
11459d316c75SMichael Rolnik 
11469d316c75SMichael Rolnik     gen_jmp_ez(ctx);
11479d316c75SMichael Rolnik     return true;
11489d316c75SMichael Rolnik }
11499d316c75SMichael Rolnik 
11509d316c75SMichael Rolnik /*
11519d316c75SMichael Rolnik  *  Jump to an address within the entire 4M (words) Program memory. See also
11529d316c75SMichael Rolnik  *  RJMP.  This instruction is not available in all devices. Refer to the device
11539d316c75SMichael Rolnik  *  specific instruction set summary.0
11549d316c75SMichael Rolnik  */
11559d316c75SMichael Rolnik static bool trans_JMP(DisasContext *ctx, arg_JMP *a)
11569d316c75SMichael Rolnik {
11579d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) {
11589d316c75SMichael Rolnik         return true;
11599d316c75SMichael Rolnik     }
11609d316c75SMichael Rolnik 
11619d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, a->imm);
11629d316c75SMichael Rolnik 
11639d316c75SMichael Rolnik     return true;
11649d316c75SMichael Rolnik }
11659d316c75SMichael Rolnik 
11669d316c75SMichael Rolnik /*
11679d316c75SMichael Rolnik  *  Relative call to an address within PC - 2K + 1 and PC + 2K (words). The
11689d316c75SMichael Rolnik  *  return address (the instruction after the RCALL) is stored onto the Stack.
11699d316c75SMichael Rolnik  *  See also CALL. For AVR microcontrollers with Program memory not exceeding 4K
11709d316c75SMichael Rolnik  *  words (8KB) this instruction can address the entire memory from every
11719d316c75SMichael Rolnik  *  address location. The Stack Pointer uses a post-decrement scheme during
11729d316c75SMichael Rolnik  *  RCALL.
11739d316c75SMichael Rolnik  */
11749d316c75SMichael Rolnik static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a)
11759d316c75SMichael Rolnik {
11769d316c75SMichael Rolnik     int ret = ctx->npc;
11779d316c75SMichael Rolnik     int dst = ctx->npc + a->imm;
11789d316c75SMichael Rolnik 
11799d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
11809d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, dst);
11819d316c75SMichael Rolnik 
11829d316c75SMichael Rolnik     return true;
11839d316c75SMichael Rolnik }
11849d316c75SMichael Rolnik 
11859d316c75SMichael Rolnik /*
11869d316c75SMichael Rolnik  *  Calls to a subroutine within the entire 4M (words) Program memory. The
11879d316c75SMichael Rolnik  *  return address (to the instruction after the CALL) will be stored onto the
11889d316c75SMichael Rolnik  *  Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme during
11899d316c75SMichael Rolnik  *  CALL.  This instruction is not available in all devices. Refer to the device
11909d316c75SMichael Rolnik  *  specific instruction set summary.
11919d316c75SMichael Rolnik  */
11929d316c75SMichael Rolnik static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a)
11939d316c75SMichael Rolnik {
11949d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) {
11959d316c75SMichael Rolnik         return true;
11969d316c75SMichael Rolnik     }
11979d316c75SMichael Rolnik 
11989d316c75SMichael Rolnik     int ret = ctx->npc;
11999d316c75SMichael Rolnik 
12009d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
12019d316c75SMichael Rolnik     gen_jmp_z(ctx);
12029d316c75SMichael Rolnik 
12039d316c75SMichael Rolnik     return true;
12049d316c75SMichael Rolnik }
12059d316c75SMichael Rolnik 
12069d316c75SMichael Rolnik /*
12079d316c75SMichael Rolnik  *  Indirect call of a subroutine pointed to by the Z (16 bits) Pointer
12089d316c75SMichael Rolnik  *  Register in the Register File and the EIND Register in the I/O space. This
12099d316c75SMichael Rolnik  *  instruction allows for indirect calls to the entire 4M (words) Program
12109d316c75SMichael Rolnik  *  memory space. See also ICALL. The Stack Pointer uses a post-decrement scheme
12119d316c75SMichael Rolnik  *  during EICALL.  This instruction is not available in all devices. Refer to
12129d316c75SMichael Rolnik  *  the device specific instruction set summary.
12139d316c75SMichael Rolnik  */
12149d316c75SMichael Rolnik static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a)
12159d316c75SMichael Rolnik {
12169d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) {
12179d316c75SMichael Rolnik         return true;
12189d316c75SMichael Rolnik     }
12199d316c75SMichael Rolnik 
12209d316c75SMichael Rolnik     int ret = ctx->npc;
12219d316c75SMichael Rolnik 
12229d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
12239d316c75SMichael Rolnik     gen_jmp_ez(ctx);
12249d316c75SMichael Rolnik     return true;
12259d316c75SMichael Rolnik }
12269d316c75SMichael Rolnik 
12279d316c75SMichael Rolnik /*
12289d316c75SMichael Rolnik  *  Calls to a subroutine within the entire Program memory. The return
12299d316c75SMichael Rolnik  *  address (to the instruction after the CALL) will be stored onto the Stack.
12309d316c75SMichael Rolnik  *  (See also RCALL). The Stack Pointer uses a post-decrement scheme during
12319d316c75SMichael Rolnik  *  CALL.  This instruction is not available in all devices. Refer to the device
12329d316c75SMichael Rolnik  *  specific instruction set summary.
12339d316c75SMichael Rolnik  */
12349d316c75SMichael Rolnik static bool trans_CALL(DisasContext *ctx, arg_CALL *a)
12359d316c75SMichael Rolnik {
12369d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) {
12379d316c75SMichael Rolnik         return true;
12389d316c75SMichael Rolnik     }
12399d316c75SMichael Rolnik 
12409d316c75SMichael Rolnik     int Imm = a->imm;
12419d316c75SMichael Rolnik     int ret = ctx->npc;
12429d316c75SMichael Rolnik 
12439d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
12449d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, Imm);
12459d316c75SMichael Rolnik 
12469d316c75SMichael Rolnik     return true;
12479d316c75SMichael Rolnik }
12489d316c75SMichael Rolnik 
12499d316c75SMichael Rolnik /*
12509d316c75SMichael Rolnik  *  Returns from subroutine. The return address is loaded from the STACK.
12519d316c75SMichael Rolnik  *  The Stack Pointer uses a preincrement scheme during RET.
12529d316c75SMichael Rolnik  */
12539d316c75SMichael Rolnik static bool trans_RET(DisasContext *ctx, arg_RET *a)
12549d316c75SMichael Rolnik {
12559d316c75SMichael Rolnik     gen_pop_ret(ctx, cpu_pc);
12569d316c75SMichael Rolnik 
12579d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
12589d316c75SMichael Rolnik     return true;
12599d316c75SMichael Rolnik }
12609d316c75SMichael Rolnik 
12619d316c75SMichael Rolnik /*
12629d316c75SMichael Rolnik  *  Returns from interrupt. The return address is loaded from the STACK and
12639d316c75SMichael Rolnik  *  the Global Interrupt Flag is set.  Note that the Status Register is not
12649d316c75SMichael Rolnik  *  automatically stored when entering an interrupt routine, and it is not
12659d316c75SMichael Rolnik  *  restored when returning from an interrupt routine. This must be handled by
12669d316c75SMichael Rolnik  *  the application program. The Stack Pointer uses a pre-increment scheme
12679d316c75SMichael Rolnik  *  during RETI.
12689d316c75SMichael Rolnik  */
12699d316c75SMichael Rolnik static bool trans_RETI(DisasContext *ctx, arg_RETI *a)
12709d316c75SMichael Rolnik {
12719d316c75SMichael Rolnik     gen_pop_ret(ctx, cpu_pc);
12729d316c75SMichael Rolnik     tcg_gen_movi_tl(cpu_If, 1);
12739d316c75SMichael Rolnik 
12749d316c75SMichael Rolnik     /* Need to return to main loop to re-evaluate interrupts.  */
12759d316c75SMichael Rolnik     ctx->bstate = DISAS_EXIT;
12769d316c75SMichael Rolnik     return true;
12779d316c75SMichael Rolnik }
12789d316c75SMichael Rolnik 
12799d316c75SMichael Rolnik /*
12809d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr, and
12819d316c75SMichael Rolnik  *  skips the next instruction if Rd = Rr.
12829d316c75SMichael Rolnik  */
12839d316c75SMichael Rolnik static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a)
12849d316c75SMichael Rolnik {
12859d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
12869d316c75SMichael Rolnik     ctx->skip_var0 = cpu_r[a->rd];
12879d316c75SMichael Rolnik     ctx->skip_var1 = cpu_r[a->rr];
12889d316c75SMichael Rolnik     return true;
12899d316c75SMichael Rolnik }
12909d316c75SMichael Rolnik 
12919d316c75SMichael Rolnik /*
12929d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr.
12939d316c75SMichael Rolnik  *  None of the registers are changed. All conditional branches can be used
12949d316c75SMichael Rolnik  *  after this instruction.
12959d316c75SMichael Rolnik  */
12969d316c75SMichael Rolnik static bool trans_CP(DisasContext *ctx, arg_CP *a)
12979d316c75SMichael Rolnik {
12989d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
12999d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
13009d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
13019d316c75SMichael Rolnik 
13029d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
13039d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
13049d316c75SMichael Rolnik 
13059d316c75SMichael Rolnik     /* update status register */
13069d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
13079d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
13089d316c75SMichael Rolnik     gen_ZNSf(R);
13099d316c75SMichael Rolnik 
13109d316c75SMichael Rolnik     tcg_temp_free_i32(R);
13119d316c75SMichael Rolnik 
13129d316c75SMichael Rolnik     return true;
13139d316c75SMichael Rolnik }
13149d316c75SMichael Rolnik 
13159d316c75SMichael Rolnik /*
13169d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr and
13179d316c75SMichael Rolnik  *  also takes into account the previous carry. None of the registers are
13189d316c75SMichael Rolnik  *  changed. All conditional branches can be used after this instruction.
13199d316c75SMichael Rolnik  */
13209d316c75SMichael Rolnik static bool trans_CPC(DisasContext *ctx, arg_CPC *a)
13219d316c75SMichael Rolnik {
13229d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
13239d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
13249d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
13259d316c75SMichael Rolnik     TCGv zero = tcg_const_i32(0);
13269d316c75SMichael Rolnik 
13279d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
13289d316c75SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
13299d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
13309d316c75SMichael Rolnik     /* update status register */
13319d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
13329d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
13339d316c75SMichael Rolnik     gen_NSf(R);
13349d316c75SMichael Rolnik 
13359d316c75SMichael Rolnik     /*
13369d316c75SMichael Rolnik      * Previous value remains unchanged when the result is zero;
13379d316c75SMichael Rolnik      * cleared otherwise.
13389d316c75SMichael Rolnik      */
13399d316c75SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
13409d316c75SMichael Rolnik 
13419d316c75SMichael Rolnik     tcg_temp_free_i32(zero);
13429d316c75SMichael Rolnik     tcg_temp_free_i32(R);
13439d316c75SMichael Rolnik 
13449d316c75SMichael Rolnik     return true;
13459d316c75SMichael Rolnik }
13469d316c75SMichael Rolnik 
13479d316c75SMichael Rolnik /*
13489d316c75SMichael Rolnik  *  This instruction performs a compare between register Rd and a constant.
13499d316c75SMichael Rolnik  *  The register is not changed. All conditional branches can be used after this
13509d316c75SMichael Rolnik  *  instruction.
13519d316c75SMichael Rolnik  */
13529d316c75SMichael Rolnik static bool trans_CPI(DisasContext *ctx, arg_CPI *a)
13539d316c75SMichael Rolnik {
13549d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
13559d316c75SMichael Rolnik     int Imm = a->imm;
13569d316c75SMichael Rolnik     TCGv Rr = tcg_const_i32(Imm);
13579d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
13589d316c75SMichael Rolnik 
13599d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
13609d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
13619d316c75SMichael Rolnik 
13629d316c75SMichael Rolnik     /* update status register */
13639d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
13649d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
13659d316c75SMichael Rolnik     gen_ZNSf(R);
13669d316c75SMichael Rolnik 
13679d316c75SMichael Rolnik     tcg_temp_free_i32(R);
13689d316c75SMichael Rolnik     tcg_temp_free_i32(Rr);
13699d316c75SMichael Rolnik 
13709d316c75SMichael Rolnik     return true;
13719d316c75SMichael Rolnik }
13729d316c75SMichael Rolnik 
13739d316c75SMichael Rolnik /*
13749d316c75SMichael Rolnik  *  This instruction tests a single bit in a register and skips the next
13759d316c75SMichael Rolnik  *  instruction if the bit is cleared.
13769d316c75SMichael Rolnik  */
13779d316c75SMichael Rolnik static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a)
13789d316c75SMichael Rolnik {
13799d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
13809d316c75SMichael Rolnik 
13819d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
13829d316c75SMichael Rolnik     ctx->skip_var0 = tcg_temp_new();
13839d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
13849d316c75SMichael Rolnik 
13859d316c75SMichael Rolnik     tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
13869d316c75SMichael Rolnik     return true;
13879d316c75SMichael Rolnik }
13889d316c75SMichael Rolnik 
13899d316c75SMichael Rolnik /*
13909d316c75SMichael Rolnik  *  This instruction tests a single bit in a register and skips the next
13919d316c75SMichael Rolnik  *  instruction if the bit is set.
13929d316c75SMichael Rolnik  */
13939d316c75SMichael Rolnik static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a)
13949d316c75SMichael Rolnik {
13959d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
13969d316c75SMichael Rolnik 
13979d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_NE;
13989d316c75SMichael Rolnik     ctx->skip_var0 = tcg_temp_new();
13999d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
14009d316c75SMichael Rolnik 
14019d316c75SMichael Rolnik     tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
14029d316c75SMichael Rolnik     return true;
14039d316c75SMichael Rolnik }
14049d316c75SMichael Rolnik 
14059d316c75SMichael Rolnik /*
14069d316c75SMichael Rolnik  *  This instruction tests a single bit in an I/O Register and skips the
14079d316c75SMichael Rolnik  *  next instruction if the bit is cleared. This instruction operates on the
14089d316c75SMichael Rolnik  *  lower 32 I/O Registers -- addresses 0-31.
14099d316c75SMichael Rolnik  */
14109d316c75SMichael Rolnik static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a)
14119d316c75SMichael Rolnik {
14129d316c75SMichael Rolnik     TCGv temp = tcg_const_i32(a->reg);
14139d316c75SMichael Rolnik 
14149d316c75SMichael Rolnik     gen_helper_inb(temp, cpu_env, temp);
14159d316c75SMichael Rolnik     tcg_gen_andi_tl(temp, temp, 1 << a->bit);
14169d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
14179d316c75SMichael Rolnik     ctx->skip_var0 = temp;
14189d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
14199d316c75SMichael Rolnik 
14209d316c75SMichael Rolnik     return true;
14219d316c75SMichael Rolnik }
14229d316c75SMichael Rolnik 
14239d316c75SMichael Rolnik /*
14249d316c75SMichael Rolnik  *  This instruction tests a single bit in an I/O Register and skips the
14259d316c75SMichael Rolnik  *  next instruction if the bit is set. This instruction operates on the lower
14269d316c75SMichael Rolnik  *  32 I/O Registers -- addresses 0-31.
14279d316c75SMichael Rolnik  */
14289d316c75SMichael Rolnik static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a)
14299d316c75SMichael Rolnik {
14309d316c75SMichael Rolnik     TCGv temp = tcg_const_i32(a->reg);
14319d316c75SMichael Rolnik 
14329d316c75SMichael Rolnik     gen_helper_inb(temp, cpu_env, temp);
14339d316c75SMichael Rolnik     tcg_gen_andi_tl(temp, temp, 1 << a->bit);
14349d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_NE;
14359d316c75SMichael Rolnik     ctx->skip_var0 = temp;
14369d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
14379d316c75SMichael Rolnik 
14389d316c75SMichael Rolnik     return true;
14399d316c75SMichael Rolnik }
14409d316c75SMichael Rolnik 
14419d316c75SMichael Rolnik /*
14429d316c75SMichael Rolnik  *  Conditional relative branch. Tests a single bit in SREG and branches
14439d316c75SMichael Rolnik  *  relatively to PC if the bit is cleared. This instruction branches relatively
14449d316c75SMichael Rolnik  *  to PC in either direction (PC - 63 < = destination <= PC + 64). The
14459d316c75SMichael Rolnik  *  parameter k is the offset from PC and is represented in two's complement
14469d316c75SMichael Rolnik  *  form.
14479d316c75SMichael Rolnik  */
14489d316c75SMichael Rolnik static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a)
14499d316c75SMichael Rolnik {
14509d316c75SMichael Rolnik     TCGLabel *not_taken = gen_new_label();
14519d316c75SMichael Rolnik 
14529d316c75SMichael Rolnik     TCGv var;
14539d316c75SMichael Rolnik 
14549d316c75SMichael Rolnik     switch (a->bit) {
14559d316c75SMichael Rolnik     case 0x00:
14569d316c75SMichael Rolnik         var = cpu_Cf;
14579d316c75SMichael Rolnik         break;
14589d316c75SMichael Rolnik     case 0x01:
14599d316c75SMichael Rolnik         var = cpu_Zf;
14609d316c75SMichael Rolnik         break;
14619d316c75SMichael Rolnik     case 0x02:
14629d316c75SMichael Rolnik         var = cpu_Nf;
14639d316c75SMichael Rolnik         break;
14649d316c75SMichael Rolnik     case 0x03:
14659d316c75SMichael Rolnik         var = cpu_Vf;
14669d316c75SMichael Rolnik         break;
14679d316c75SMichael Rolnik     case 0x04:
14689d316c75SMichael Rolnik         var = cpu_Sf;
14699d316c75SMichael Rolnik         break;
14709d316c75SMichael Rolnik     case 0x05:
14719d316c75SMichael Rolnik         var = cpu_Hf;
14729d316c75SMichael Rolnik         break;
14739d316c75SMichael Rolnik     case 0x06:
14749d316c75SMichael Rolnik         var = cpu_Tf;
14759d316c75SMichael Rolnik         break;
14769d316c75SMichael Rolnik     case 0x07:
14779d316c75SMichael Rolnik         var = cpu_If;
14789d316c75SMichael Rolnik         break;
14799d316c75SMichael Rolnik     default:
14809d316c75SMichael Rolnik         g_assert_not_reached();
14819d316c75SMichael Rolnik     }
14829d316c75SMichael Rolnik 
14839d316c75SMichael Rolnik     tcg_gen_brcondi_i32(TCG_COND_NE, var, 0, not_taken);
14849d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, ctx->npc + a->imm);
14859d316c75SMichael Rolnik     gen_set_label(not_taken);
14869d316c75SMichael Rolnik 
14879d316c75SMichael Rolnik     ctx->bstate = DISAS_CHAIN;
14889d316c75SMichael Rolnik     return true;
14899d316c75SMichael Rolnik }
14909d316c75SMichael Rolnik 
14919d316c75SMichael Rolnik /*
14929d316c75SMichael Rolnik  *  Conditional relative branch. Tests a single bit in SREG and branches
14939d316c75SMichael Rolnik  *  relatively to PC if the bit is set. This instruction branches relatively to
14949d316c75SMichael Rolnik  *  PC in either direction (PC - 63 < = destination <= PC + 64). The parameter k
14959d316c75SMichael Rolnik  *  is the offset from PC and is represented in two's complement form.
14969d316c75SMichael Rolnik  */
14979d316c75SMichael Rolnik static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a)
14989d316c75SMichael Rolnik {
14999d316c75SMichael Rolnik     TCGLabel *not_taken = gen_new_label();
15009d316c75SMichael Rolnik 
15019d316c75SMichael Rolnik     TCGv var;
15029d316c75SMichael Rolnik 
15039d316c75SMichael Rolnik     switch (a->bit) {
15049d316c75SMichael Rolnik     case 0x00:
15059d316c75SMichael Rolnik         var = cpu_Cf;
15069d316c75SMichael Rolnik         break;
15079d316c75SMichael Rolnik     case 0x01:
15089d316c75SMichael Rolnik         var = cpu_Zf;
15099d316c75SMichael Rolnik         break;
15109d316c75SMichael Rolnik     case 0x02:
15119d316c75SMichael Rolnik         var = cpu_Nf;
15129d316c75SMichael Rolnik         break;
15139d316c75SMichael Rolnik     case 0x03:
15149d316c75SMichael Rolnik         var = cpu_Vf;
15159d316c75SMichael Rolnik         break;
15169d316c75SMichael Rolnik     case 0x04:
15179d316c75SMichael Rolnik         var = cpu_Sf;
15189d316c75SMichael Rolnik         break;
15199d316c75SMichael Rolnik     case 0x05:
15209d316c75SMichael Rolnik         var = cpu_Hf;
15219d316c75SMichael Rolnik         break;
15229d316c75SMichael Rolnik     case 0x06:
15239d316c75SMichael Rolnik         var = cpu_Tf;
15249d316c75SMichael Rolnik         break;
15259d316c75SMichael Rolnik     case 0x07:
15269d316c75SMichael Rolnik         var = cpu_If;
15279d316c75SMichael Rolnik         break;
15289d316c75SMichael Rolnik     default:
15299d316c75SMichael Rolnik         g_assert_not_reached();
15309d316c75SMichael Rolnik     }
15319d316c75SMichael Rolnik 
15329d316c75SMichael Rolnik     tcg_gen_brcondi_i32(TCG_COND_EQ, var, 0, not_taken);
15339d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, ctx->npc + a->imm);
15349d316c75SMichael Rolnik     gen_set_label(not_taken);
15359d316c75SMichael Rolnik 
15369d316c75SMichael Rolnik     ctx->bstate = DISAS_CHAIN;
15379d316c75SMichael Rolnik     return true;
15389d316c75SMichael Rolnik }
15399732b024SMichael Rolnik 
15409732b024SMichael Rolnik /*
15419732b024SMichael Rolnik  * Data Transfer Instructions
15429732b024SMichael Rolnik  */
15439732b024SMichael Rolnik 
15449732b024SMichael Rolnik /*
15459732b024SMichael Rolnik  *  in the gen_set_addr & gen_get_addr functions
15469732b024SMichael Rolnik  *  H assumed to be in 0x00ff0000 format
15479732b024SMichael Rolnik  *  M assumed to be in 0x000000ff format
15489732b024SMichael Rolnik  *  L assumed to be in 0x000000ff format
15499732b024SMichael Rolnik  */
15509732b024SMichael Rolnik static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L)
15519732b024SMichael Rolnik {
15529732b024SMichael Rolnik 
15539732b024SMichael Rolnik     tcg_gen_andi_tl(L, addr, 0x000000ff);
15549732b024SMichael Rolnik 
15559732b024SMichael Rolnik     tcg_gen_andi_tl(M, addr, 0x0000ff00);
15569732b024SMichael Rolnik     tcg_gen_shri_tl(M, M, 8);
15579732b024SMichael Rolnik 
15589732b024SMichael Rolnik     tcg_gen_andi_tl(H, addr, 0x00ff0000);
15599732b024SMichael Rolnik }
15609732b024SMichael Rolnik 
15619732b024SMichael Rolnik static void gen_set_xaddr(TCGv addr)
15629732b024SMichael Rolnik {
15639732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]);
15649732b024SMichael Rolnik }
15659732b024SMichael Rolnik 
15669732b024SMichael Rolnik static void gen_set_yaddr(TCGv addr)
15679732b024SMichael Rolnik {
15689732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]);
15699732b024SMichael Rolnik }
15709732b024SMichael Rolnik 
15719732b024SMichael Rolnik static void gen_set_zaddr(TCGv addr)
15729732b024SMichael Rolnik {
15739732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]);
15749732b024SMichael Rolnik }
15759732b024SMichael Rolnik 
15769732b024SMichael Rolnik static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L)
15779732b024SMichael Rolnik {
15789732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
15799732b024SMichael Rolnik 
15809732b024SMichael Rolnik     tcg_gen_deposit_tl(addr, M, H, 8, 8);
15819732b024SMichael Rolnik     tcg_gen_deposit_tl(addr, L, addr, 8, 16);
15829732b024SMichael Rolnik 
15839732b024SMichael Rolnik     return addr;
15849732b024SMichael Rolnik }
15859732b024SMichael Rolnik 
15869732b024SMichael Rolnik static TCGv gen_get_xaddr(void)
15879732b024SMichael Rolnik {
15889732b024SMichael Rolnik     return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]);
15899732b024SMichael Rolnik }
15909732b024SMichael Rolnik 
15919732b024SMichael Rolnik static TCGv gen_get_yaddr(void)
15929732b024SMichael Rolnik {
15939732b024SMichael Rolnik     return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]);
15949732b024SMichael Rolnik }
15959732b024SMichael Rolnik 
15969732b024SMichael Rolnik static TCGv gen_get_zaddr(void)
15979732b024SMichael Rolnik {
15989732b024SMichael Rolnik     return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]);
15999732b024SMichael Rolnik }
16009732b024SMichael Rolnik 
16019732b024SMichael Rolnik /*
16029732b024SMichael Rolnik  *  Load one byte indirect from data space to register and stores an clear
16039732b024SMichael Rolnik  *  the bits in data space specified by the register. The instruction can only
16049732b024SMichael Rolnik  *  be used towards internal SRAM.  The data location is pointed to by the Z (16
16059732b024SMichael Rolnik  *  bits) Pointer Register in the Register File. Memory access is limited to the
16069732b024SMichael Rolnik  *  current data segment of 64KB. To access another data segment in devices with
16079732b024SMichael Rolnik  *  more than 64KB data space, the RAMPZ in register in the I/O area has to be
16089732b024SMichael Rolnik  *  changed.  The Z-pointer Register is left unchanged by the operation. This
16099732b024SMichael Rolnik  *  instruction is especially suited for clearing status bits stored in SRAM.
16109732b024SMichael Rolnik  */
16119732b024SMichael Rolnik static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr)
16129732b024SMichael Rolnik {
16139732b024SMichael Rolnik     if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) {
16149732b024SMichael Rolnik         gen_helper_fullwr(cpu_env, data, addr);
16159732b024SMichael Rolnik     } else {
16169732b024SMichael Rolnik         tcg_gen_qemu_st8(data, addr, MMU_DATA_IDX); /* mem[addr] = data */
16179732b024SMichael Rolnik     }
16189732b024SMichael Rolnik }
16199732b024SMichael Rolnik 
16209732b024SMichael Rolnik static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr)
16219732b024SMichael Rolnik {
16229732b024SMichael Rolnik     if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) {
16239732b024SMichael Rolnik         gen_helper_fullrd(data, cpu_env, addr);
16249732b024SMichael Rolnik     } else {
16259732b024SMichael Rolnik         tcg_gen_qemu_ld8u(data, addr, MMU_DATA_IDX); /* data = mem[addr] */
16269732b024SMichael Rolnik     }
16279732b024SMichael Rolnik }
16289732b024SMichael Rolnik 
16299732b024SMichael Rolnik /*
16309732b024SMichael Rolnik  *  This instruction makes a copy of one register into another. The source
16319732b024SMichael Rolnik  *  register Rr is left unchanged, while the destination register Rd is loaded
16329732b024SMichael Rolnik  *  with a copy of Rr.
16339732b024SMichael Rolnik  */
16349732b024SMichael Rolnik static bool trans_MOV(DisasContext *ctx, arg_MOV *a)
16359732b024SMichael Rolnik {
16369732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16379732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
16389732b024SMichael Rolnik 
16399732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, Rr);
16409732b024SMichael Rolnik 
16419732b024SMichael Rolnik     return true;
16429732b024SMichael Rolnik }
16439732b024SMichael Rolnik 
16449732b024SMichael Rolnik /*
16459732b024SMichael Rolnik  *  This instruction makes a copy of one register pair into another register
16469732b024SMichael Rolnik  *  pair. The source register pair Rr+1:Rr is left unchanged, while the
16479732b024SMichael Rolnik  *  destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr.  This
16489732b024SMichael Rolnik  *  instruction is not available in all devices. Refer to the device specific
16499732b024SMichael Rolnik  *  instruction set summary.
16509732b024SMichael Rolnik  */
16519732b024SMichael Rolnik static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a)
16529732b024SMichael Rolnik {
16539732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MOVW)) {
16549732b024SMichael Rolnik         return true;
16559732b024SMichael Rolnik     }
16569732b024SMichael Rolnik 
16579732b024SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
16589732b024SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
16599732b024SMichael Rolnik     TCGv RrL = cpu_r[a->rr];
16609732b024SMichael Rolnik     TCGv RrH = cpu_r[a->rr + 1];
16619732b024SMichael Rolnik 
16629732b024SMichael Rolnik     tcg_gen_mov_tl(RdH, RrH);
16639732b024SMichael Rolnik     tcg_gen_mov_tl(RdL, RrL);
16649732b024SMichael Rolnik 
16659732b024SMichael Rolnik     return true;
16669732b024SMichael Rolnik }
16679732b024SMichael Rolnik 
16689732b024SMichael Rolnik /*
16699732b024SMichael Rolnik  * Loads an 8 bit constant directly to register 16 to 31.
16709732b024SMichael Rolnik  */
16719732b024SMichael Rolnik static bool trans_LDI(DisasContext *ctx, arg_LDI *a)
16729732b024SMichael Rolnik {
16739732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16749732b024SMichael Rolnik     int imm = a->imm;
16759732b024SMichael Rolnik 
16769732b024SMichael Rolnik     tcg_gen_movi_tl(Rd, imm);
16779732b024SMichael Rolnik 
16789732b024SMichael Rolnik     return true;
16799732b024SMichael Rolnik }
16809732b024SMichael Rolnik 
16819732b024SMichael Rolnik /*
16829732b024SMichael Rolnik  *  Loads one byte from the data space to a register. For parts with SRAM,
16839732b024SMichael Rolnik  *  the data space consists of the Register File, I/O memory and internal SRAM
16849732b024SMichael Rolnik  *  (and external SRAM if applicable). For parts without SRAM, the data space
16859732b024SMichael Rolnik  *  consists of the register file only. The EEPROM has a separate address space.
16869732b024SMichael Rolnik  *  A 16-bit address must be supplied. Memory access is limited to the current
16879732b024SMichael Rolnik  *  data segment of 64KB. The LDS instruction uses the RAMPD Register to access
16889732b024SMichael Rolnik  *  memory above 64KB. To access another data segment in devices with more than
16899732b024SMichael Rolnik  *  64KB data space, the RAMPD in register in the I/O area has to be changed.
16909732b024SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
16919732b024SMichael Rolnik  *  specific instruction set summary.
16929732b024SMichael Rolnik  */
16939732b024SMichael Rolnik static bool trans_LDS(DisasContext *ctx, arg_LDS *a)
16949732b024SMichael Rolnik {
16959732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16969732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
16979732b024SMichael Rolnik     TCGv H = cpu_rampD;
16989732b024SMichael Rolnik     a->imm = next_word(ctx);
16999732b024SMichael Rolnik 
17009732b024SMichael Rolnik     tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
17019732b024SMichael Rolnik     tcg_gen_shli_tl(addr, addr, 16);
17029732b024SMichael Rolnik     tcg_gen_ori_tl(addr, addr, a->imm);
17039732b024SMichael Rolnik 
17049732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17059732b024SMichael Rolnik 
17069732b024SMichael Rolnik     tcg_temp_free_i32(addr);
17079732b024SMichael Rolnik 
17089732b024SMichael Rolnik     return true;
17099732b024SMichael Rolnik }
17109732b024SMichael Rolnik 
17119732b024SMichael Rolnik /*
17129732b024SMichael Rolnik  *  Loads one byte indirect from the data space to a register. For parts
17139732b024SMichael Rolnik  *  with SRAM, the data space consists of the Register File, I/O memory and
17149732b024SMichael Rolnik  *  internal SRAM (and external SRAM if applicable). For parts without SRAM, the
17159732b024SMichael Rolnik  *  data space consists of the Register File only. In some parts the Flash
17169732b024SMichael Rolnik  *  Memory has been mapped to the data space and can be read using this command.
17179732b024SMichael Rolnik  *  The EEPROM has a separate address space.  The data location is pointed to by
17189732b024SMichael Rolnik  *  the X (16 bits) Pointer Register in the Register File. Memory access is
17199732b024SMichael Rolnik  *  limited to the current data segment of 64KB. To access another data segment
17209732b024SMichael Rolnik  *  in devices with more than 64KB data space, the RAMPX in register in the I/O
17219732b024SMichael Rolnik  *  area has to be changed.  The X-pointer Register can either be left unchanged
17229732b024SMichael Rolnik  *  by the operation, or it can be post-incremented or predecremented.  These
17239732b024SMichael Rolnik  *  features are especially suited for accessing arrays, tables, and Stack
17249732b024SMichael Rolnik  *  Pointer usage of the X-pointer Register. Note that only the low byte of the
17259732b024SMichael Rolnik  *  X-pointer is updated in devices with no more than 256 bytes data space. For
17269732b024SMichael Rolnik  *  such devices, the high byte of the pointer is not used by this instruction
17279732b024SMichael Rolnik  *  and can be used for other purposes. The RAMPX Register in the I/O area is
17289732b024SMichael Rolnik  *  updated in parts with more than 64KB data space or more than 64KB Program
17299732b024SMichael Rolnik  *  memory, and the increment/decrement is added to the entire 24-bit address on
17309732b024SMichael Rolnik  *  such devices.  Not all variants of this instruction is available in all
17319732b024SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.  In the
17329732b024SMichael Rolnik  *  Reduced Core tinyAVR the LD instruction can be used to achieve the same
17339732b024SMichael Rolnik  *  operation as LPM since the program memory is mapped to the data memory
17349732b024SMichael Rolnik  *  space.
17359732b024SMichael Rolnik  */
17369732b024SMichael Rolnik static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a)
17379732b024SMichael Rolnik {
17389732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17399732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
17409732b024SMichael Rolnik 
17419732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17429732b024SMichael Rolnik 
17439732b024SMichael Rolnik     tcg_temp_free_i32(addr);
17449732b024SMichael Rolnik 
17459732b024SMichael Rolnik     return true;
17469732b024SMichael Rolnik }
17479732b024SMichael Rolnik 
17489732b024SMichael Rolnik static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a)
17499732b024SMichael Rolnik {
17509732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17519732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
17529732b024SMichael Rolnik 
17539732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17549732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
17559732b024SMichael Rolnik 
17569732b024SMichael Rolnik     gen_set_xaddr(addr);
17579732b024SMichael Rolnik 
17589732b024SMichael Rolnik     tcg_temp_free_i32(addr);
17599732b024SMichael Rolnik 
17609732b024SMichael Rolnik     return true;
17619732b024SMichael Rolnik }
17629732b024SMichael Rolnik 
17639732b024SMichael Rolnik static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a)
17649732b024SMichael Rolnik {
17659732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17669732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
17679732b024SMichael Rolnik 
17689732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
17699732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17709732b024SMichael Rolnik     gen_set_xaddr(addr);
17719732b024SMichael Rolnik 
17729732b024SMichael Rolnik     tcg_temp_free_i32(addr);
17739732b024SMichael Rolnik 
17749732b024SMichael Rolnik     return true;
17759732b024SMichael Rolnik }
17769732b024SMichael Rolnik 
17779732b024SMichael Rolnik /*
17789732b024SMichael Rolnik  *  Loads one byte indirect with or without displacement from the data space
17799732b024SMichael Rolnik  *  to a register. For parts with SRAM, the data space consists of the Register
17809732b024SMichael Rolnik  *  File, I/O memory and internal SRAM (and external SRAM if applicable). For
17819732b024SMichael Rolnik  *  parts without SRAM, the data space consists of the Register File only. In
17829732b024SMichael Rolnik  *  some parts the Flash Memory has been mapped to the data space and can be
17839732b024SMichael Rolnik  *  read using this command. The EEPROM has a separate address space.  The data
17849732b024SMichael Rolnik  *  location is pointed to by the Y (16 bits) Pointer Register in the Register
17859732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
17869732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
17879732b024SMichael Rolnik  *  RAMPY in register in the I/O area has to be changed.  The Y-pointer Register
17889732b024SMichael Rolnik  *  can either be left unchanged by the operation, or it can be post-incremented
17899732b024SMichael Rolnik  *  or predecremented.  These features are especially suited for accessing
17909732b024SMichael Rolnik  *  arrays, tables, and Stack Pointer usage of the Y-pointer Register. Note that
17919732b024SMichael Rolnik  *  only the low byte of the Y-pointer is updated in devices with no more than
17929732b024SMichael Rolnik  *  256 bytes data space. For such devices, the high byte of the pointer is not
17939732b024SMichael Rolnik  *  used by this instruction and can be used for other purposes. The RAMPY
17949732b024SMichael Rolnik  *  Register in the I/O area is updated in parts with more than 64KB data space
17959732b024SMichael Rolnik  *  or more than 64KB Program memory, and the increment/decrement/displacement
17969732b024SMichael Rolnik  *  is added to the entire 24-bit address on such devices.  Not all variants of
17979732b024SMichael Rolnik  *  this instruction is available in all devices. Refer to the device specific
17989732b024SMichael Rolnik  *  instruction set summary.  In the Reduced Core tinyAVR the LD instruction can
17999732b024SMichael Rolnik  *  be used to achieve the same operation as LPM since the program memory is
18009732b024SMichael Rolnik  *  mapped to the data memory space.
18019732b024SMichael Rolnik  */
18029732b024SMichael Rolnik static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a)
18039732b024SMichael Rolnik {
18049732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18059732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
18069732b024SMichael Rolnik 
18079732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
18089732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
18099732b024SMichael Rolnik 
18109732b024SMichael Rolnik     gen_set_yaddr(addr);
18119732b024SMichael Rolnik 
18129732b024SMichael Rolnik     tcg_temp_free_i32(addr);
18139732b024SMichael Rolnik 
18149732b024SMichael Rolnik     return true;
18159732b024SMichael Rolnik }
18169732b024SMichael Rolnik 
18179732b024SMichael Rolnik static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a)
18189732b024SMichael Rolnik {
18199732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18209732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
18219732b024SMichael Rolnik 
18229732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
18239732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
18249732b024SMichael Rolnik     gen_set_yaddr(addr);
18259732b024SMichael Rolnik 
18269732b024SMichael Rolnik     tcg_temp_free_i32(addr);
18279732b024SMichael Rolnik 
18289732b024SMichael Rolnik     return true;
18299732b024SMichael Rolnik }
18309732b024SMichael Rolnik 
18319732b024SMichael Rolnik static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a)
18329732b024SMichael Rolnik {
18339732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18349732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
18359732b024SMichael Rolnik 
18369732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
18379732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
18389732b024SMichael Rolnik 
18399732b024SMichael Rolnik     tcg_temp_free_i32(addr);
18409732b024SMichael Rolnik 
18419732b024SMichael Rolnik     return true;
18429732b024SMichael Rolnik }
18439732b024SMichael Rolnik 
18449732b024SMichael Rolnik /*
18459732b024SMichael Rolnik  *  Loads one byte indirect with or without displacement from the data space
18469732b024SMichael Rolnik  *  to a register. For parts with SRAM, the data space consists of the Register
18479732b024SMichael Rolnik  *  File, I/O memory and internal SRAM (and external SRAM if applicable). For
18489732b024SMichael Rolnik  *  parts without SRAM, the data space consists of the Register File only. In
18499732b024SMichael Rolnik  *  some parts the Flash Memory has been mapped to the data space and can be
18509732b024SMichael Rolnik  *  read using this command. The EEPROM has a separate address space.  The data
18519732b024SMichael Rolnik  *  location is pointed to by the Z (16 bits) Pointer Register in the Register
18529732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
18539732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
18549732b024SMichael Rolnik  *  RAMPZ in register in the I/O area has to be changed.  The Z-pointer Register
18559732b024SMichael Rolnik  *  can either be left unchanged by the operation, or it can be post-incremented
18569732b024SMichael Rolnik  *  or predecremented.  These features are especially suited for Stack Pointer
18579732b024SMichael Rolnik  *  usage of the Z-pointer Register, however because the Z-pointer Register can
18589732b024SMichael Rolnik  *  be used for indirect subroutine calls, indirect jumps and table lookup, it
18599732b024SMichael Rolnik  *  is often more convenient to use the X or Y-pointer as a dedicated Stack
18609732b024SMichael Rolnik  *  Pointer. Note that only the low byte of the Z-pointer is updated in devices
18619732b024SMichael Rolnik  *  with no more than 256 bytes data space. For such devices, the high byte of
18629732b024SMichael Rolnik  *  the pointer is not used by this instruction and can be used for other
18639732b024SMichael Rolnik  *  purposes. The RAMPZ Register in the I/O area is updated in parts with more
18649732b024SMichael Rolnik  *  than 64KB data space or more than 64KB Program memory, and the
18659732b024SMichael Rolnik  *  increment/decrement/displacement is added to the entire 24-bit address on
18669732b024SMichael Rolnik  *  such devices.  Not all variants of this instruction is available in all
18679732b024SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.  In the
18689732b024SMichael Rolnik  *  Reduced Core tinyAVR the LD instruction can be used to achieve the same
18699732b024SMichael Rolnik  *  operation as LPM since the program memory is mapped to the data memory
18709732b024SMichael Rolnik  *  space.  For using the Z-pointer for table lookup in Program memory see the
18719732b024SMichael Rolnik  *  LPM and ELPM instructions.
18729732b024SMichael Rolnik  */
18739732b024SMichael Rolnik static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a)
18749732b024SMichael Rolnik {
18759732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18769732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
18779732b024SMichael Rolnik 
18789732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
18799732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
18809732b024SMichael Rolnik 
18819732b024SMichael Rolnik     gen_set_zaddr(addr);
18829732b024SMichael Rolnik 
18839732b024SMichael Rolnik     tcg_temp_free_i32(addr);
18849732b024SMichael Rolnik 
18859732b024SMichael Rolnik     return true;
18869732b024SMichael Rolnik }
18879732b024SMichael Rolnik 
18889732b024SMichael Rolnik static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a)
18899732b024SMichael Rolnik {
18909732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18919732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
18929732b024SMichael Rolnik 
18939732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
18949732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
18959732b024SMichael Rolnik 
18969732b024SMichael Rolnik     gen_set_zaddr(addr);
18979732b024SMichael Rolnik 
18989732b024SMichael Rolnik     tcg_temp_free_i32(addr);
18999732b024SMichael Rolnik 
19009732b024SMichael Rolnik     return true;
19019732b024SMichael Rolnik }
19029732b024SMichael Rolnik 
19039732b024SMichael Rolnik static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a)
19049732b024SMichael Rolnik {
19059732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
19069732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
19079732b024SMichael Rolnik 
19089732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
19099732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
19109732b024SMichael Rolnik 
19119732b024SMichael Rolnik     tcg_temp_free_i32(addr);
19129732b024SMichael Rolnik 
19139732b024SMichael Rolnik     return true;
19149732b024SMichael Rolnik }
19159732b024SMichael Rolnik 
19169732b024SMichael Rolnik /*
19179732b024SMichael Rolnik  *  Stores one byte from a Register to the data space. For parts with SRAM,
19189732b024SMichael Rolnik  *  the data space consists of the Register File, I/O memory and internal SRAM
19199732b024SMichael Rolnik  *  (and external SRAM if applicable). For parts without SRAM, the data space
19209732b024SMichael Rolnik  *  consists of the Register File only. The EEPROM has a separate address space.
19219732b024SMichael Rolnik  *  A 16-bit address must be supplied. Memory access is limited to the current
19229732b024SMichael Rolnik  *  data segment of 64KB. The STS instruction uses the RAMPD Register to access
19239732b024SMichael Rolnik  *  memory above 64KB. To access another data segment in devices with more than
19249732b024SMichael Rolnik  *  64KB data space, the RAMPD in register in the I/O area has to be changed.
19259732b024SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
19269732b024SMichael Rolnik  *  specific instruction set summary.
19279732b024SMichael Rolnik  */
19289732b024SMichael Rolnik static bool trans_STS(DisasContext *ctx, arg_STS *a)
19299732b024SMichael Rolnik {
19309732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
19319732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
19329732b024SMichael Rolnik     TCGv H = cpu_rampD;
19339732b024SMichael Rolnik     a->imm = next_word(ctx);
19349732b024SMichael Rolnik 
19359732b024SMichael Rolnik     tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
19369732b024SMichael Rolnik     tcg_gen_shli_tl(addr, addr, 16);
19379732b024SMichael Rolnik     tcg_gen_ori_tl(addr, addr, a->imm);
19389732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19399732b024SMichael Rolnik 
19409732b024SMichael Rolnik     tcg_temp_free_i32(addr);
19419732b024SMichael Rolnik 
19429732b024SMichael Rolnik     return true;
19439732b024SMichael Rolnik }
19449732b024SMichael Rolnik 
19459732b024SMichael Rolnik /*
19469732b024SMichael Rolnik  * Stores one byte indirect from a register to data space. For parts with SRAM,
19479732b024SMichael Rolnik  * the data space consists of the Register File, I/O memory, and internal SRAM
19489732b024SMichael Rolnik  * (and external SRAM if applicable). For parts without SRAM, the data space
19499732b024SMichael Rolnik  * consists of the Register File only. The EEPROM has a separate address space.
19509732b024SMichael Rolnik  *
19519732b024SMichael Rolnik  * The data location is pointed to by the X (16 bits) Pointer Register in the
19529732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
19539732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
19549732b024SMichael Rolnik  * RAMPX in register in the I/O area has to be changed.
19559732b024SMichael Rolnik  *
19569732b024SMichael Rolnik  * The X-pointer Register can either be left unchanged by the operation, or it
19579732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
19589732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the
19599732b024SMichael Rolnik  * X-pointer Register. Note that only the low byte of the X-pointer is updated
19609732b024SMichael Rolnik  * in devices with no more than 256 bytes data space. For such devices, the high
19619732b024SMichael Rolnik  * byte of the pointer is not used by this instruction and can be used for other
19629732b024SMichael Rolnik  * purposes. The RAMPX Register in the I/O area is updated in parts with more
19639732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
19649732b024SMichael Rolnik  * decrement is added to the entire 24-bit address on such devices.
19659732b024SMichael Rolnik  */
19669732b024SMichael Rolnik static bool trans_STX1(DisasContext *ctx, arg_STX1 *a)
19679732b024SMichael Rolnik {
19689732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
19699732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
19709732b024SMichael Rolnik 
19719732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19729732b024SMichael Rolnik 
19739732b024SMichael Rolnik     tcg_temp_free_i32(addr);
19749732b024SMichael Rolnik 
19759732b024SMichael Rolnik     return true;
19769732b024SMichael Rolnik }
19779732b024SMichael Rolnik 
19789732b024SMichael Rolnik static bool trans_STX2(DisasContext *ctx, arg_STX2 *a)
19799732b024SMichael Rolnik {
19809732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
19819732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
19829732b024SMichael Rolnik 
19839732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19849732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
19859732b024SMichael Rolnik     gen_set_xaddr(addr);
19869732b024SMichael Rolnik 
19879732b024SMichael Rolnik     tcg_temp_free_i32(addr);
19889732b024SMichael Rolnik 
19899732b024SMichael Rolnik     return true;
19909732b024SMichael Rolnik }
19919732b024SMichael Rolnik 
19929732b024SMichael Rolnik static bool trans_STX3(DisasContext *ctx, arg_STX3 *a)
19939732b024SMichael Rolnik {
19949732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
19959732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
19969732b024SMichael Rolnik 
19979732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
19989732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19999732b024SMichael Rolnik     gen_set_xaddr(addr);
20009732b024SMichael Rolnik 
20019732b024SMichael Rolnik     tcg_temp_free_i32(addr);
20029732b024SMichael Rolnik 
20039732b024SMichael Rolnik     return true;
20049732b024SMichael Rolnik }
20059732b024SMichael Rolnik 
20069732b024SMichael Rolnik /*
20079732b024SMichael Rolnik  * Stores one byte indirect with or without displacement from a register to data
20089732b024SMichael Rolnik  * space. For parts with SRAM, the data space consists of the Register File, I/O
20099732b024SMichael Rolnik  * memory, and internal SRAM (and external SRAM if applicable). For parts
20109732b024SMichael Rolnik  * without SRAM, the data space consists of the Register File only. The EEPROM
20119732b024SMichael Rolnik  * has a separate address space.
20129732b024SMichael Rolnik  *
20139732b024SMichael Rolnik  * The data location is pointed to by the Y (16 bits) Pointer Register in the
20149732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
20159732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
20169732b024SMichael Rolnik  * RAMPY in register in the I/O area has to be changed.
20179732b024SMichael Rolnik  *
20189732b024SMichael Rolnik  * The Y-pointer Register can either be left unchanged by the operation, or it
20199732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
20209732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer
20219732b024SMichael Rolnik  * Register. Note that only the low byte of the Y-pointer is updated in devices
20229732b024SMichael Rolnik  * with no more than 256 bytes data space. For such devices, the high byte of
20239732b024SMichael Rolnik  * the pointer is not used by this instruction and can be used for other
20249732b024SMichael Rolnik  * purposes. The RAMPY Register in the I/O area is updated in parts with more
20259732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
20269732b024SMichael Rolnik  * decrement / displacement is added to the entire 24-bit address on such
20279732b024SMichael Rolnik  * devices.
20289732b024SMichael Rolnik  */
20299732b024SMichael Rolnik static bool trans_STY2(DisasContext *ctx, arg_STY2 *a)
20309732b024SMichael Rolnik {
20319732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20329732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
20339732b024SMichael Rolnik 
20349732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
20359732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
20369732b024SMichael Rolnik     gen_set_yaddr(addr);
20379732b024SMichael Rolnik 
20389732b024SMichael Rolnik     tcg_temp_free_i32(addr);
20399732b024SMichael Rolnik 
20409732b024SMichael Rolnik     return true;
20419732b024SMichael Rolnik }
20429732b024SMichael Rolnik 
20439732b024SMichael Rolnik static bool trans_STY3(DisasContext *ctx, arg_STY3 *a)
20449732b024SMichael Rolnik {
20459732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20469732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
20479732b024SMichael Rolnik 
20489732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
20499732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
20509732b024SMichael Rolnik     gen_set_yaddr(addr);
20519732b024SMichael Rolnik 
20529732b024SMichael Rolnik     tcg_temp_free_i32(addr);
20539732b024SMichael Rolnik 
20549732b024SMichael Rolnik     return true;
20559732b024SMichael Rolnik }
20569732b024SMichael Rolnik 
20579732b024SMichael Rolnik static bool trans_STDY(DisasContext *ctx, arg_STDY *a)
20589732b024SMichael Rolnik {
20599732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20609732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
20619732b024SMichael Rolnik 
20629732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
20639732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
20649732b024SMichael Rolnik 
20659732b024SMichael Rolnik     tcg_temp_free_i32(addr);
20669732b024SMichael Rolnik 
20679732b024SMichael Rolnik     return true;
20689732b024SMichael Rolnik }
20699732b024SMichael Rolnik 
20709732b024SMichael Rolnik /*
20719732b024SMichael Rolnik  * Stores one byte indirect with or without displacement from a register to data
20729732b024SMichael Rolnik  * space. For parts with SRAM, the data space consists of the Register File, I/O
20739732b024SMichael Rolnik  * memory, and internal SRAM (and external SRAM if applicable). For parts
20749732b024SMichael Rolnik  * without SRAM, the data space consists of the Register File only. The EEPROM
20759732b024SMichael Rolnik  * has a separate address space.
20769732b024SMichael Rolnik  *
20779732b024SMichael Rolnik  * The data location is pointed to by the Y (16 bits) Pointer Register in the
20789732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
20799732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
20809732b024SMichael Rolnik  * RAMPY in register in the I/O area has to be changed.
20819732b024SMichael Rolnik  *
20829732b024SMichael Rolnik  * The Y-pointer Register can either be left unchanged by the operation, or it
20839732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
20849732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer
20859732b024SMichael Rolnik  * Register. Note that only the low byte of the Y-pointer is updated in devices
20869732b024SMichael Rolnik  * with no more than 256 bytes data space. For such devices, the high byte of
20879732b024SMichael Rolnik  * the pointer is not used by this instruction and can be used for other
20889732b024SMichael Rolnik  * purposes. The RAMPY Register in the I/O area is updated in parts with more
20899732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
20909732b024SMichael Rolnik  * decrement / displacement is added to the entire 24-bit address on such
20919732b024SMichael Rolnik  * devices.
20929732b024SMichael Rolnik  */
20939732b024SMichael Rolnik static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a)
20949732b024SMichael Rolnik {
20959732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20969732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
20979732b024SMichael Rolnik 
20989732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
20999732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
21009732b024SMichael Rolnik 
21019732b024SMichael Rolnik     gen_set_zaddr(addr);
21029732b024SMichael Rolnik 
21039732b024SMichael Rolnik     tcg_temp_free_i32(addr);
21049732b024SMichael Rolnik 
21059732b024SMichael Rolnik     return true;
21069732b024SMichael Rolnik }
21079732b024SMichael Rolnik 
21089732b024SMichael Rolnik static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a)
21099732b024SMichael Rolnik {
21109732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
21119732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
21129732b024SMichael Rolnik 
21139732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
21149732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
21159732b024SMichael Rolnik 
21169732b024SMichael Rolnik     gen_set_zaddr(addr);
21179732b024SMichael Rolnik 
21189732b024SMichael Rolnik     tcg_temp_free_i32(addr);
21199732b024SMichael Rolnik 
21209732b024SMichael Rolnik     return true;
21219732b024SMichael Rolnik }
21229732b024SMichael Rolnik 
21239732b024SMichael Rolnik static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a)
21249732b024SMichael Rolnik {
21259732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
21269732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
21279732b024SMichael Rolnik 
21289732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
21299732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
21309732b024SMichael Rolnik 
21319732b024SMichael Rolnik     tcg_temp_free_i32(addr);
21329732b024SMichael Rolnik 
21339732b024SMichael Rolnik     return true;
21349732b024SMichael Rolnik }
21359732b024SMichael Rolnik 
21369732b024SMichael Rolnik /*
21379732b024SMichael Rolnik  *  Loads one byte pointed to by the Z-register into the destination
21389732b024SMichael Rolnik  *  register Rd. This instruction features a 100% space effective constant
21399732b024SMichael Rolnik  *  initialization or constant data fetch. The Program memory is organized in
21409732b024SMichael Rolnik  *  16-bit words while the Z-pointer is a byte address. Thus, the least
21419732b024SMichael Rolnik  *  significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high
21429732b024SMichael Rolnik  *  byte (ZLSB = 1). This instruction can address the first 64KB (32K words) of
21439732b024SMichael Rolnik  *  Program memory. The Zpointer Register can either be left unchanged by the
21449732b024SMichael Rolnik  *  operation, or it can be incremented. The incrementation does not apply to
21459732b024SMichael Rolnik  *  the RAMPZ Register.
21469732b024SMichael Rolnik  *
21479732b024SMichael Rolnik  *  Devices with Self-Programming capability can use the LPM instruction to read
21489732b024SMichael Rolnik  *  the Fuse and Lock bit values.
21499732b024SMichael Rolnik  */
21509732b024SMichael Rolnik static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a)
21519732b024SMichael Rolnik {
21529732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) {
21539732b024SMichael Rolnik         return true;
21549732b024SMichael Rolnik     }
21559732b024SMichael Rolnik 
21569732b024SMichael Rolnik     TCGv Rd = cpu_r[0];
21579732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
21589732b024SMichael Rolnik     TCGv H = cpu_r[31];
21599732b024SMichael Rolnik     TCGv L = cpu_r[30];
21609732b024SMichael Rolnik 
21619732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
21629732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
21639732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
21649732b024SMichael Rolnik 
21659732b024SMichael Rolnik     tcg_temp_free_i32(addr);
21669732b024SMichael Rolnik 
21679732b024SMichael Rolnik     return true;
21689732b024SMichael Rolnik }
21699732b024SMichael Rolnik 
21709732b024SMichael Rolnik static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a)
21719732b024SMichael Rolnik {
21729732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) {
21739732b024SMichael Rolnik         return true;
21749732b024SMichael Rolnik     }
21759732b024SMichael Rolnik 
21769732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
21779732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
21789732b024SMichael Rolnik     TCGv H = cpu_r[31];
21799732b024SMichael Rolnik     TCGv L = cpu_r[30];
21809732b024SMichael Rolnik 
21819732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
21829732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
21839732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
21849732b024SMichael Rolnik 
21859732b024SMichael Rolnik     tcg_temp_free_i32(addr);
21869732b024SMichael Rolnik 
21879732b024SMichael Rolnik     return true;
21889732b024SMichael Rolnik }
21899732b024SMichael Rolnik 
21909732b024SMichael Rolnik static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a)
21919732b024SMichael Rolnik {
21929732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPMX)) {
21939732b024SMichael Rolnik         return true;
21949732b024SMichael Rolnik     }
21959732b024SMichael Rolnik 
21969732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
21979732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
21989732b024SMichael Rolnik     TCGv H = cpu_r[31];
21999732b024SMichael Rolnik     TCGv L = cpu_r[30];
22009732b024SMichael Rolnik 
22019732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
22029732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
22039732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
22049732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
22059732b024SMichael Rolnik     tcg_gen_andi_tl(L, addr, 0xff);
22069732b024SMichael Rolnik     tcg_gen_shri_tl(addr, addr, 8);
22079732b024SMichael Rolnik     tcg_gen_andi_tl(H, addr, 0xff);
22089732b024SMichael Rolnik 
22099732b024SMichael Rolnik     tcg_temp_free_i32(addr);
22109732b024SMichael Rolnik 
22119732b024SMichael Rolnik     return true;
22129732b024SMichael Rolnik }
22139732b024SMichael Rolnik 
22149732b024SMichael Rolnik /*
22159732b024SMichael Rolnik  *  Loads one byte pointed to by the Z-register and the RAMPZ Register in
22169732b024SMichael Rolnik  *  the I/O space, and places this byte in the destination register Rd. This
22179732b024SMichael Rolnik  *  instruction features a 100% space effective constant initialization or
22189732b024SMichael Rolnik  *  constant data fetch. The Program memory is organized in 16-bit words while
22199732b024SMichael Rolnik  *  the Z-pointer is a byte address. Thus, the least significant bit of the
22209732b024SMichael Rolnik  *  Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This
22219732b024SMichael Rolnik  *  instruction can address the entire Program memory space. The Z-pointer
22229732b024SMichael Rolnik  *  Register can either be left unchanged by the operation, or it can be
22239732b024SMichael Rolnik  *  incremented. The incrementation applies to the entire 24-bit concatenation
22249732b024SMichael Rolnik  *  of the RAMPZ and Z-pointer Registers.
22259732b024SMichael Rolnik  *
22269732b024SMichael Rolnik  *  Devices with Self-Programming capability can use the ELPM instruction to
22279732b024SMichael Rolnik  *  read the Fuse and Lock bit value.
22289732b024SMichael Rolnik  */
22299732b024SMichael Rolnik static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a)
22309732b024SMichael Rolnik {
22319732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) {
22329732b024SMichael Rolnik         return true;
22339732b024SMichael Rolnik     }
22349732b024SMichael Rolnik 
22359732b024SMichael Rolnik     TCGv Rd = cpu_r[0];
22369732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
22379732b024SMichael Rolnik 
22389732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
22399732b024SMichael Rolnik 
22409732b024SMichael Rolnik     tcg_temp_free_i32(addr);
22419732b024SMichael Rolnik 
22429732b024SMichael Rolnik     return true;
22439732b024SMichael Rolnik }
22449732b024SMichael Rolnik 
22459732b024SMichael Rolnik static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a)
22469732b024SMichael Rolnik {
22479732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) {
22489732b024SMichael Rolnik         return true;
22499732b024SMichael Rolnik     }
22509732b024SMichael Rolnik 
22519732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
22529732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
22539732b024SMichael Rolnik 
22549732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
22559732b024SMichael Rolnik 
22569732b024SMichael Rolnik     tcg_temp_free_i32(addr);
22579732b024SMichael Rolnik 
22589732b024SMichael Rolnik     return true;
22599732b024SMichael Rolnik }
22609732b024SMichael Rolnik 
22619732b024SMichael Rolnik static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a)
22629732b024SMichael Rolnik {
22639732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPMX)) {
22649732b024SMichael Rolnik         return true;
22659732b024SMichael Rolnik     }
22669732b024SMichael Rolnik 
22679732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
22689732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
22699732b024SMichael Rolnik 
22709732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
22719732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
22729732b024SMichael Rolnik     gen_set_zaddr(addr);
22739732b024SMichael Rolnik 
22749732b024SMichael Rolnik     tcg_temp_free_i32(addr);
22759732b024SMichael Rolnik 
22769732b024SMichael Rolnik     return true;
22779732b024SMichael Rolnik }
22789732b024SMichael Rolnik 
22799732b024SMichael Rolnik /*
22809732b024SMichael Rolnik  *  SPM can be used to erase a page in the Program memory, to write a page
22819732b024SMichael Rolnik  *  in the Program memory (that is already erased), and to set Boot Loader Lock
22829732b024SMichael Rolnik  *  bits. In some devices, the Program memory can be written one word at a time,
22839732b024SMichael Rolnik  *  in other devices an entire page can be programmed simultaneously after first
22849732b024SMichael Rolnik  *  filling a temporary page buffer. In all cases, the Program memory must be
22859732b024SMichael Rolnik  *  erased one page at a time. When erasing the Program memory, the RAMPZ and
22869732b024SMichael Rolnik  *  Z-register are used as page address. When writing the Program memory, the
22879732b024SMichael Rolnik  *  RAMPZ and Z-register are used as page or word address, and the R1:R0
22889732b024SMichael Rolnik  *  register pair is used as data(1). When setting the Boot Loader Lock bits,
22899732b024SMichael Rolnik  *  the R1:R0 register pair is used as data. Refer to the device documentation
22909732b024SMichael Rolnik  *  for detailed description of SPM usage. This instruction can address the
22919732b024SMichael Rolnik  *  entire Program memory.
22929732b024SMichael Rolnik  *
22939732b024SMichael Rolnik  *  The SPM instruction is not available in all devices. Refer to the device
22949732b024SMichael Rolnik  *  specific instruction set summary.
22959732b024SMichael Rolnik  *
22969732b024SMichael Rolnik  *  Note: 1. R1 determines the instruction high byte, and R0 determines the
22979732b024SMichael Rolnik  *  instruction low byte.
22989732b024SMichael Rolnik  */
22999732b024SMichael Rolnik static bool trans_SPM(DisasContext *ctx, arg_SPM *a)
23009732b024SMichael Rolnik {
23019732b024SMichael Rolnik     /* TODO */
23029732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_SPM)) {
23039732b024SMichael Rolnik         return true;
23049732b024SMichael Rolnik     }
23059732b024SMichael Rolnik 
23069732b024SMichael Rolnik     return true;
23079732b024SMichael Rolnik }
23089732b024SMichael Rolnik 
23099732b024SMichael Rolnik static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a)
23109732b024SMichael Rolnik {
23119732b024SMichael Rolnik     /* TODO */
23129732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_SPMX)) {
23139732b024SMichael Rolnik         return true;
23149732b024SMichael Rolnik     }
23159732b024SMichael Rolnik 
23169732b024SMichael Rolnik     return true;
23179732b024SMichael Rolnik }
23189732b024SMichael Rolnik 
23199732b024SMichael Rolnik /*
23209732b024SMichael Rolnik  *  Loads data from the I/O Space (Ports, Timers, Configuration Registers,
23219732b024SMichael Rolnik  *  etc.) into register Rd in the Register File.
23229732b024SMichael Rolnik  */
23239732b024SMichael Rolnik static bool trans_IN(DisasContext *ctx, arg_IN *a)
23249732b024SMichael Rolnik {
23259732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23269732b024SMichael Rolnik     TCGv port = tcg_const_i32(a->imm);
23279732b024SMichael Rolnik 
23289732b024SMichael Rolnik     gen_helper_inb(Rd, cpu_env, port);
23299732b024SMichael Rolnik 
23309732b024SMichael Rolnik     tcg_temp_free_i32(port);
23319732b024SMichael Rolnik 
23329732b024SMichael Rolnik     return true;
23339732b024SMichael Rolnik }
23349732b024SMichael Rolnik 
23359732b024SMichael Rolnik /*
23369732b024SMichael Rolnik  *  Stores data from register Rr in the Register File to I/O Space (Ports,
23379732b024SMichael Rolnik  *  Timers, Configuration Registers, etc.).
23389732b024SMichael Rolnik  */
23399732b024SMichael Rolnik static bool trans_OUT(DisasContext *ctx, arg_OUT *a)
23409732b024SMichael Rolnik {
23419732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23429732b024SMichael Rolnik     TCGv port = tcg_const_i32(a->imm);
23439732b024SMichael Rolnik 
23449732b024SMichael Rolnik     gen_helper_outb(cpu_env, port, Rd);
23459732b024SMichael Rolnik 
23469732b024SMichael Rolnik     tcg_temp_free_i32(port);
23479732b024SMichael Rolnik 
23489732b024SMichael Rolnik     return true;
23499732b024SMichael Rolnik }
23509732b024SMichael Rolnik 
23519732b024SMichael Rolnik /*
23529732b024SMichael Rolnik  *  This instruction stores the contents of register Rr on the STACK. The
23539732b024SMichael Rolnik  *  Stack Pointer is post-decremented by 1 after the PUSH.  This instruction is
23549732b024SMichael Rolnik  *  not available in all devices. Refer to the device specific instruction set
23559732b024SMichael Rolnik  *  summary.
23569732b024SMichael Rolnik  */
23579732b024SMichael Rolnik static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a)
23589732b024SMichael Rolnik {
23599732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23609732b024SMichael Rolnik 
23619732b024SMichael Rolnik     gen_data_store(ctx, Rd, cpu_sp);
23629732b024SMichael Rolnik     tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
23639732b024SMichael Rolnik 
23649732b024SMichael Rolnik     return true;
23659732b024SMichael Rolnik }
23669732b024SMichael Rolnik 
23679732b024SMichael Rolnik /*
23689732b024SMichael Rolnik  *  This instruction loads register Rd with a byte from the STACK. The Stack
23699732b024SMichael Rolnik  *  Pointer is pre-incremented by 1 before the POP.  This instruction is not
23709732b024SMichael Rolnik  *  available in all devices. Refer to the device specific instruction set
23719732b024SMichael Rolnik  *  summary.
23729732b024SMichael Rolnik  */
23739732b024SMichael Rolnik static bool trans_POP(DisasContext *ctx, arg_POP *a)
23749732b024SMichael Rolnik {
23759732b024SMichael Rolnik     /*
23769732b024SMichael Rolnik      * Using a temp to work around some strange behaviour:
23779732b024SMichael Rolnik      * tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
23789732b024SMichael Rolnik      * gen_data_load(ctx, Rd, cpu_sp);
23799732b024SMichael Rolnik      * seems to cause the add to happen twice.
23809732b024SMichael Rolnik      * This doesn't happen if either the add or the load is removed.
23819732b024SMichael Rolnik      */
23829732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
23839732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23849732b024SMichael Rolnik 
23859732b024SMichael Rolnik     tcg_gen_addi_tl(t1, cpu_sp, 1);
23869732b024SMichael Rolnik     gen_data_load(ctx, Rd, t1);
23879732b024SMichael Rolnik     tcg_gen_mov_tl(cpu_sp, t1);
23889732b024SMichael Rolnik 
23899732b024SMichael Rolnik     return true;
23909732b024SMichael Rolnik }
23919732b024SMichael Rolnik 
23929732b024SMichael Rolnik /*
23939732b024SMichael Rolnik  *  Exchanges one byte indirect between register and data space.  The data
23949732b024SMichael Rolnik  *  location is pointed to by the Z (16 bits) Pointer Register in the Register
23959732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
23969732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
23979732b024SMichael Rolnik  *  RAMPZ in register in the I/O area has to be changed.
23989732b024SMichael Rolnik  *
23999732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
24009732b024SMichael Rolnik  *  is especially suited for writing/reading status bits stored in SRAM.
24019732b024SMichael Rolnik  */
24029732b024SMichael Rolnik static bool trans_XCH(DisasContext *ctx, arg_XCH *a)
24039732b024SMichael Rolnik {
24049732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
24059732b024SMichael Rolnik         return true;
24069732b024SMichael Rolnik     }
24079732b024SMichael Rolnik 
24089732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
24099732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
24109732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
24119732b024SMichael Rolnik 
24129732b024SMichael Rolnik     gen_data_load(ctx, t0, addr);
24139732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
24149732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, t0);
24159732b024SMichael Rolnik 
24169732b024SMichael Rolnik     tcg_temp_free_i32(t0);
24179732b024SMichael Rolnik     tcg_temp_free_i32(addr);
24189732b024SMichael Rolnik 
24199732b024SMichael Rolnik     return true;
24209732b024SMichael Rolnik }
24219732b024SMichael Rolnik 
24229732b024SMichael Rolnik /*
24239732b024SMichael Rolnik  *  Load one byte indirect from data space to register and set bits in data
24249732b024SMichael Rolnik  *  space specified by the register. The instruction can only be used towards
24259732b024SMichael Rolnik  *  internal SRAM.  The data location is pointed to by the Z (16 bits) Pointer
24269732b024SMichael Rolnik  *  Register in the Register File. Memory access is limited to the current data
24279732b024SMichael Rolnik  *  segment of 64KB. To access another data segment in devices with more than
24289732b024SMichael Rolnik  *  64KB data space, the RAMPZ in register in the I/O area has to be changed.
24299732b024SMichael Rolnik  *
24309732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
24319732b024SMichael Rolnik  *  is especially suited for setting status bits stored in SRAM.
24329732b024SMichael Rolnik  */
24339732b024SMichael Rolnik static bool trans_LAS(DisasContext *ctx, arg_LAS *a)
24349732b024SMichael Rolnik {
24359732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
24369732b024SMichael Rolnik         return true;
24379732b024SMichael Rolnik     }
24389732b024SMichael Rolnik 
24399732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rd];
24409732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
24419732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
24429732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
24439732b024SMichael Rolnik 
24449732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
24459732b024SMichael Rolnik     tcg_gen_or_tl(t1, t0, Rr);
24469732b024SMichael Rolnik     tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
24479732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
24489732b024SMichael Rolnik 
24499732b024SMichael Rolnik     tcg_temp_free_i32(t1);
24509732b024SMichael Rolnik     tcg_temp_free_i32(t0);
24519732b024SMichael Rolnik     tcg_temp_free_i32(addr);
24529732b024SMichael Rolnik 
24539732b024SMichael Rolnik     return true;
24549732b024SMichael Rolnik }
24559732b024SMichael Rolnik 
24569732b024SMichael Rolnik /*
24579732b024SMichael Rolnik  *  Load one byte indirect from data space to register and stores and clear
24589732b024SMichael Rolnik  *  the bits in data space specified by the register. The instruction can
24599732b024SMichael Rolnik  *  only be used towards internal SRAM.  The data location is pointed to by
24609732b024SMichael Rolnik  *  the Z (16 bits) Pointer Register in the Register File. Memory access is
24619732b024SMichael Rolnik  *  limited to the current data segment of 64KB. To access another data
24629732b024SMichael Rolnik  *  segment in devices with more than 64KB data space, the RAMPZ in register
24639732b024SMichael Rolnik  *  in the I/O area has to be changed.
24649732b024SMichael Rolnik  *
24659732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
24669732b024SMichael Rolnik  *  is especially suited for clearing status bits stored in SRAM.
24679732b024SMichael Rolnik  */
24689732b024SMichael Rolnik static bool trans_LAC(DisasContext *ctx, arg_LAC *a)
24699732b024SMichael Rolnik {
24709732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
24719732b024SMichael Rolnik         return true;
24729732b024SMichael Rolnik     }
24739732b024SMichael Rolnik 
24749732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rd];
24759732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
24769732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
24779732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
24789732b024SMichael Rolnik 
24799732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
24809732b024SMichael Rolnik     tcg_gen_andc_tl(t1, t0, Rr); /* t1 = t0 & (0xff - Rr) = t0 & ~Rr */
24819732b024SMichael Rolnik     tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
24829732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
24839732b024SMichael Rolnik 
24849732b024SMichael Rolnik     tcg_temp_free_i32(t1);
24859732b024SMichael Rolnik     tcg_temp_free_i32(t0);
24869732b024SMichael Rolnik     tcg_temp_free_i32(addr);
24879732b024SMichael Rolnik 
24889732b024SMichael Rolnik     return true;
24899732b024SMichael Rolnik }
24909732b024SMichael Rolnik 
24919732b024SMichael Rolnik 
24929732b024SMichael Rolnik /*
24939732b024SMichael Rolnik  *  Load one byte indirect from data space to register and toggles bits in
24949732b024SMichael Rolnik  *  the data space specified by the register.  The instruction can only be used
24959732b024SMichael Rolnik  *  towards SRAM.  The data location is pointed to by the Z (16 bits) Pointer
24969732b024SMichael Rolnik  *  Register in the Register File. Memory access is limited to the current data
24979732b024SMichael Rolnik  *  segment of 64KB. To access another data segment in devices with more than
24989732b024SMichael Rolnik  *  64KB data space, the RAMPZ in register in the I/O area has to be changed.
24999732b024SMichael Rolnik  *
25009732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
25019732b024SMichael Rolnik  *  is especially suited for changing status bits stored in SRAM.
25029732b024SMichael Rolnik  */
25039732b024SMichael Rolnik static bool trans_LAT(DisasContext *ctx, arg_LAT *a)
25049732b024SMichael Rolnik {
25059732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
25069732b024SMichael Rolnik         return true;
25079732b024SMichael Rolnik     }
25089732b024SMichael Rolnik 
25099732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
25109732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
25119732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
25129732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
25139732b024SMichael Rolnik 
25149732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
25159732b024SMichael Rolnik     tcg_gen_xor_tl(t1, t0, Rd);
25169732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, t0); /* Rd = t0 */
25179732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
25189732b024SMichael Rolnik 
25199732b024SMichael Rolnik     tcg_temp_free_i32(t1);
25209732b024SMichael Rolnik     tcg_temp_free_i32(t0);
25219732b024SMichael Rolnik     tcg_temp_free_i32(addr);
25229732b024SMichael Rolnik 
25239732b024SMichael Rolnik     return true;
25249732b024SMichael Rolnik }
25255718cef0SMichael Rolnik 
25265718cef0SMichael Rolnik /*
25275718cef0SMichael Rolnik  * Bit and Bit-test Instructions
25285718cef0SMichael Rolnik  */
25295718cef0SMichael Rolnik static void gen_rshift_ZNVSf(TCGv R)
25305718cef0SMichael Rolnik {
25315718cef0SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
25325718cef0SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
25335718cef0SMichael Rolnik     tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf);
25345718cef0SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
25355718cef0SMichael Rolnik }
25365718cef0SMichael Rolnik 
25375718cef0SMichael Rolnik /*
25385718cef0SMichael Rolnik  *  Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is
25395718cef0SMichael Rolnik  *  loaded into the C Flag of the SREG. This operation effectively divides an
25405718cef0SMichael Rolnik  *  unsigned value by two. The C Flag can be used to round the result.
25415718cef0SMichael Rolnik  */
25425718cef0SMichael Rolnik static bool trans_LSR(DisasContext *ctx, arg_LSR *a)
25435718cef0SMichael Rolnik {
25445718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
25455718cef0SMichael Rolnik 
25465718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Cf, Rd, 1);
25475718cef0SMichael Rolnik     tcg_gen_shri_tl(Rd, Rd, 1);
25485718cef0SMichael Rolnik 
25495718cef0SMichael Rolnik     /* update status register */
25505718cef0SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, Rd, 0); /* Zf = Rd == 0 */
25515718cef0SMichael Rolnik     tcg_gen_movi_tl(cpu_Nf, 0);
25525718cef0SMichael Rolnik     tcg_gen_mov_tl(cpu_Vf, cpu_Cf);
25535718cef0SMichael Rolnik     tcg_gen_mov_tl(cpu_Sf, cpu_Vf);
25545718cef0SMichael Rolnik 
25555718cef0SMichael Rolnik     return true;
25565718cef0SMichael Rolnik }
25575718cef0SMichael Rolnik 
25585718cef0SMichael Rolnik /*
25595718cef0SMichael Rolnik  *  Shifts all bits in Rd one place to the right. The C Flag is shifted into
25605718cef0SMichael Rolnik  *  bit 7 of Rd. Bit 0 is shifted into the C Flag.  This operation, combined
25615718cef0SMichael Rolnik  *  with ASR, effectively divides multi-byte signed values by two. Combined with
25625718cef0SMichael Rolnik  *  LSR it effectively divides multi-byte unsigned values by two. The Carry Flag
25635718cef0SMichael Rolnik  *  can be used to round the result.
25645718cef0SMichael Rolnik  */
25655718cef0SMichael Rolnik static bool trans_ROR(DisasContext *ctx, arg_ROR *a)
25665718cef0SMichael Rolnik {
25675718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
25685718cef0SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
25695718cef0SMichael Rolnik 
25705718cef0SMichael Rolnik     tcg_gen_shli_tl(t0, cpu_Cf, 7);
25715718cef0SMichael Rolnik 
25725718cef0SMichael Rolnik     /* update status register */
25735718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Cf, Rd, 1);
25745718cef0SMichael Rolnik 
25755718cef0SMichael Rolnik     /* update output register */
25765718cef0SMichael Rolnik     tcg_gen_shri_tl(Rd, Rd, 1);
25775718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, Rd, t0);
25785718cef0SMichael Rolnik 
25795718cef0SMichael Rolnik     /* update status register */
25805718cef0SMichael Rolnik     gen_rshift_ZNVSf(Rd);
25815718cef0SMichael Rolnik 
25825718cef0SMichael Rolnik     tcg_temp_free_i32(t0);
25835718cef0SMichael Rolnik 
25845718cef0SMichael Rolnik     return true;
25855718cef0SMichael Rolnik }
25865718cef0SMichael Rolnik 
25875718cef0SMichael Rolnik /*
25885718cef0SMichael Rolnik  *  Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0
25895718cef0SMichael Rolnik  *  is loaded into the C Flag of the SREG. This operation effectively divides a
25905718cef0SMichael Rolnik  *  signed value by two without changing its sign. The Carry Flag can be used to
25915718cef0SMichael Rolnik  *  round the result.
25925718cef0SMichael Rolnik  */
25935718cef0SMichael Rolnik static bool trans_ASR(DisasContext *ctx, arg_ASR *a)
25945718cef0SMichael Rolnik {
25955718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
25965718cef0SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
25975718cef0SMichael Rolnik 
25985718cef0SMichael Rolnik     /* update status register */
25995718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */
26005718cef0SMichael Rolnik 
26015718cef0SMichael Rolnik     /* update output register */
26025718cef0SMichael Rolnik     tcg_gen_andi_tl(t0, Rd, 0x80); /* Rd = (Rd & 0x80) | (Rd >> 1) */
26035718cef0SMichael Rolnik     tcg_gen_shri_tl(Rd, Rd, 1);
26045718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, Rd, t0);
26055718cef0SMichael Rolnik 
26065718cef0SMichael Rolnik     /* update status register */
26075718cef0SMichael Rolnik     gen_rshift_ZNVSf(Rd);
26085718cef0SMichael Rolnik 
26095718cef0SMichael Rolnik     tcg_temp_free_i32(t0);
26105718cef0SMichael Rolnik 
26115718cef0SMichael Rolnik     return true;
26125718cef0SMichael Rolnik }
26135718cef0SMichael Rolnik 
26145718cef0SMichael Rolnik /*
26155718cef0SMichael Rolnik  *  Swaps high and low nibbles in a register.
26165718cef0SMichael Rolnik  */
26175718cef0SMichael Rolnik static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a)
26185718cef0SMichael Rolnik {
26195718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
26205718cef0SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
26215718cef0SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
26225718cef0SMichael Rolnik 
26235718cef0SMichael Rolnik     tcg_gen_andi_tl(t0, Rd, 0x0f);
26245718cef0SMichael Rolnik     tcg_gen_shli_tl(t0, t0, 4);
26255718cef0SMichael Rolnik     tcg_gen_andi_tl(t1, Rd, 0xf0);
26265718cef0SMichael Rolnik     tcg_gen_shri_tl(t1, t1, 4);
26275718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, t0, t1);
26285718cef0SMichael Rolnik 
26295718cef0SMichael Rolnik     tcg_temp_free_i32(t1);
26305718cef0SMichael Rolnik     tcg_temp_free_i32(t0);
26315718cef0SMichael Rolnik 
26325718cef0SMichael Rolnik     return true;
26335718cef0SMichael Rolnik }
26345718cef0SMichael Rolnik 
26355718cef0SMichael Rolnik /*
26365718cef0SMichael Rolnik  *  Sets a specified bit in an I/O Register. This instruction operates on
26375718cef0SMichael Rolnik  *  the lower 32 I/O Registers -- addresses 0-31.
26385718cef0SMichael Rolnik  */
26395718cef0SMichael Rolnik static bool trans_SBI(DisasContext *ctx, arg_SBI *a)
26405718cef0SMichael Rolnik {
26415718cef0SMichael Rolnik     TCGv data = tcg_temp_new_i32();
26425718cef0SMichael Rolnik     TCGv port = tcg_const_i32(a->reg);
26435718cef0SMichael Rolnik 
26445718cef0SMichael Rolnik     gen_helper_inb(data, cpu_env, port);
26455718cef0SMichael Rolnik     tcg_gen_ori_tl(data, data, 1 << a->bit);
26465718cef0SMichael Rolnik     gen_helper_outb(cpu_env, port, data);
26475718cef0SMichael Rolnik 
26485718cef0SMichael Rolnik     tcg_temp_free_i32(port);
26495718cef0SMichael Rolnik     tcg_temp_free_i32(data);
26505718cef0SMichael Rolnik 
26515718cef0SMichael Rolnik     return true;
26525718cef0SMichael Rolnik }
26535718cef0SMichael Rolnik 
26545718cef0SMichael Rolnik /*
26555718cef0SMichael Rolnik  *  Clears a specified bit in an I/O Register. This instruction operates on
26565718cef0SMichael Rolnik  *  the lower 32 I/O Registers -- addresses 0-31.
26575718cef0SMichael Rolnik  */
26585718cef0SMichael Rolnik static bool trans_CBI(DisasContext *ctx, arg_CBI *a)
26595718cef0SMichael Rolnik {
26605718cef0SMichael Rolnik     TCGv data = tcg_temp_new_i32();
26615718cef0SMichael Rolnik     TCGv port = tcg_const_i32(a->reg);
26625718cef0SMichael Rolnik 
26635718cef0SMichael Rolnik     gen_helper_inb(data, cpu_env, port);
26645718cef0SMichael Rolnik     tcg_gen_andi_tl(data, data, ~(1 << a->bit));
26655718cef0SMichael Rolnik     gen_helper_outb(cpu_env, port, data);
26665718cef0SMichael Rolnik 
26675718cef0SMichael Rolnik     tcg_temp_free_i32(data);
26685718cef0SMichael Rolnik     tcg_temp_free_i32(port);
26695718cef0SMichael Rolnik 
26705718cef0SMichael Rolnik     return true;
26715718cef0SMichael Rolnik }
26725718cef0SMichael Rolnik 
26735718cef0SMichael Rolnik /*
26745718cef0SMichael Rolnik  *  Stores bit b from Rd to the T Flag in SREG (Status Register).
26755718cef0SMichael Rolnik  */
26765718cef0SMichael Rolnik static bool trans_BST(DisasContext *ctx, arg_BST *a)
26775718cef0SMichael Rolnik {
26785718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
26795718cef0SMichael Rolnik 
26805718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit);
26815718cef0SMichael Rolnik     tcg_gen_shri_tl(cpu_Tf, cpu_Tf, a->bit);
26825718cef0SMichael Rolnik 
26835718cef0SMichael Rolnik     return true;
26845718cef0SMichael Rolnik }
26855718cef0SMichael Rolnik 
26865718cef0SMichael Rolnik /*
26875718cef0SMichael Rolnik  *  Copies the T Flag in the SREG (Status Register) to bit b in register Rd.
26885718cef0SMichael Rolnik  */
26895718cef0SMichael Rolnik static bool trans_BLD(DisasContext *ctx, arg_BLD *a)
26905718cef0SMichael Rolnik {
26915718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
26925718cef0SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
26935718cef0SMichael Rolnik 
26945718cef0SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */
26955718cef0SMichael Rolnik     tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */
26965718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, Rd, t1);
26975718cef0SMichael Rolnik 
26985718cef0SMichael Rolnik     tcg_temp_free_i32(t1);
26995718cef0SMichael Rolnik 
27005718cef0SMichael Rolnik     return true;
27015718cef0SMichael Rolnik }
27025718cef0SMichael Rolnik 
27035718cef0SMichael Rolnik /*
27045718cef0SMichael Rolnik  *  Sets a single Flag or bit in SREG.
27055718cef0SMichael Rolnik  */
27065718cef0SMichael Rolnik static bool trans_BSET(DisasContext *ctx, arg_BSET *a)
27075718cef0SMichael Rolnik {
27085718cef0SMichael Rolnik     switch (a->bit) {
27095718cef0SMichael Rolnik     case 0x00:
27105718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Cf, 0x01);
27115718cef0SMichael Rolnik         break;
27125718cef0SMichael Rolnik     case 0x01:
27135718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Zf, 0x01);
27145718cef0SMichael Rolnik         break;
27155718cef0SMichael Rolnik     case 0x02:
27165718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Nf, 0x01);
27175718cef0SMichael Rolnik         break;
27185718cef0SMichael Rolnik     case 0x03:
27195718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Vf, 0x01);
27205718cef0SMichael Rolnik         break;
27215718cef0SMichael Rolnik     case 0x04:
27225718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Sf, 0x01);
27235718cef0SMichael Rolnik         break;
27245718cef0SMichael Rolnik     case 0x05:
27255718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Hf, 0x01);
27265718cef0SMichael Rolnik         break;
27275718cef0SMichael Rolnik     case 0x06:
27285718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Tf, 0x01);
27295718cef0SMichael Rolnik         break;
27305718cef0SMichael Rolnik     case 0x07:
27315718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_If, 0x01);
27325718cef0SMichael Rolnik         break;
27335718cef0SMichael Rolnik     }
27345718cef0SMichael Rolnik 
27355718cef0SMichael Rolnik     return true;
27365718cef0SMichael Rolnik }
27375718cef0SMichael Rolnik 
27385718cef0SMichael Rolnik /*
27395718cef0SMichael Rolnik  *  Clears a single Flag in SREG.
27405718cef0SMichael Rolnik  */
27415718cef0SMichael Rolnik static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a)
27425718cef0SMichael Rolnik {
27435718cef0SMichael Rolnik     switch (a->bit) {
27445718cef0SMichael Rolnik     case 0x00:
27455718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Cf, 0x00);
27465718cef0SMichael Rolnik         break;
27475718cef0SMichael Rolnik     case 0x01:
27485718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Zf, 0x00);
27495718cef0SMichael Rolnik         break;
27505718cef0SMichael Rolnik     case 0x02:
27515718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Nf, 0x00);
27525718cef0SMichael Rolnik         break;
27535718cef0SMichael Rolnik     case 0x03:
27545718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Vf, 0x00);
27555718cef0SMichael Rolnik         break;
27565718cef0SMichael Rolnik     case 0x04:
27575718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Sf, 0x00);
27585718cef0SMichael Rolnik         break;
27595718cef0SMichael Rolnik     case 0x05:
27605718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Hf, 0x00);
27615718cef0SMichael Rolnik         break;
27625718cef0SMichael Rolnik     case 0x06:
27635718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Tf, 0x00);
27645718cef0SMichael Rolnik         break;
27655718cef0SMichael Rolnik     case 0x07:
27665718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_If, 0x00);
27675718cef0SMichael Rolnik         break;
27685718cef0SMichael Rolnik     }
27695718cef0SMichael Rolnik 
27705718cef0SMichael Rolnik     return true;
27715718cef0SMichael Rolnik }
277246188cabSMichael Rolnik 
277346188cabSMichael Rolnik /*
277446188cabSMichael Rolnik  * MCU Control Instructions
277546188cabSMichael Rolnik  */
277646188cabSMichael Rolnik 
277746188cabSMichael Rolnik /*
277846188cabSMichael Rolnik  *  The BREAK instruction is used by the On-chip Debug system, and is
277946188cabSMichael Rolnik  *  normally not used in the application software. When the BREAK instruction is
278046188cabSMichael Rolnik  *  executed, the AVR CPU is set in the Stopped Mode. This gives the On-chip
278146188cabSMichael Rolnik  *  Debugger access to internal resources.  If any Lock bits are set, or either
278246188cabSMichael Rolnik  *  the JTAGEN or OCDEN Fuses are unprogrammed, the CPU will treat the BREAK
278346188cabSMichael Rolnik  *  instruction as a NOP and will not enter the Stopped mode.  This instruction
278446188cabSMichael Rolnik  *  is not available in all devices. Refer to the device specific instruction
278546188cabSMichael Rolnik  *  set summary.
278646188cabSMichael Rolnik  */
278746188cabSMichael Rolnik static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a)
278846188cabSMichael Rolnik {
278946188cabSMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_BREAK)) {
279046188cabSMichael Rolnik         return true;
279146188cabSMichael Rolnik     }
279246188cabSMichael Rolnik 
279346188cabSMichael Rolnik #ifdef BREAKPOINT_ON_BREAK
279446188cabSMichael Rolnik     tcg_gen_movi_tl(cpu_pc, ctx->npc - 1);
279546188cabSMichael Rolnik     gen_helper_debug(cpu_env);
279646188cabSMichael Rolnik     ctx->bstate = DISAS_EXIT;
279746188cabSMichael Rolnik #else
279846188cabSMichael Rolnik     /* NOP */
279946188cabSMichael Rolnik #endif
280046188cabSMichael Rolnik 
280146188cabSMichael Rolnik     return true;
280246188cabSMichael Rolnik }
280346188cabSMichael Rolnik 
280446188cabSMichael Rolnik /*
280546188cabSMichael Rolnik  *  This instruction performs a single cycle No Operation.
280646188cabSMichael Rolnik  */
280746188cabSMichael Rolnik static bool trans_NOP(DisasContext *ctx, arg_NOP *a)
280846188cabSMichael Rolnik {
280946188cabSMichael Rolnik 
281046188cabSMichael Rolnik     /* NOP */
281146188cabSMichael Rolnik 
281246188cabSMichael Rolnik     return true;
281346188cabSMichael Rolnik }
281446188cabSMichael Rolnik 
281546188cabSMichael Rolnik /*
281646188cabSMichael Rolnik  *  This instruction sets the circuit in sleep mode defined by the MCU
281746188cabSMichael Rolnik  *  Control Register.
281846188cabSMichael Rolnik  */
281946188cabSMichael Rolnik static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a)
282046188cabSMichael Rolnik {
282146188cabSMichael Rolnik     gen_helper_sleep(cpu_env);
282246188cabSMichael Rolnik     ctx->bstate = DISAS_NORETURN;
282346188cabSMichael Rolnik     return true;
282446188cabSMichael Rolnik }
282546188cabSMichael Rolnik 
282646188cabSMichael Rolnik /*
282746188cabSMichael Rolnik  *  This instruction resets the Watchdog Timer. This instruction must be
282846188cabSMichael Rolnik  *  executed within a limited time given by the WD prescaler. See the Watchdog
282946188cabSMichael Rolnik  *  Timer hardware specification.
283046188cabSMichael Rolnik  */
283146188cabSMichael Rolnik static bool trans_WDR(DisasContext *ctx, arg_WDR *a)
283246188cabSMichael Rolnik {
283346188cabSMichael Rolnik     gen_helper_wdr(cpu_env);
283446188cabSMichael Rolnik 
283546188cabSMichael Rolnik     return true;
283646188cabSMichael Rolnik }
28379baade8dSMichael Rolnik 
28389baade8dSMichael Rolnik /*
28399baade8dSMichael Rolnik  *  Core translation mechanism functions:
28409baade8dSMichael Rolnik  *
28419baade8dSMichael Rolnik  *    - translate()
28429baade8dSMichael Rolnik  *    - canonicalize_skip()
28439baade8dSMichael Rolnik  *    - gen_intermediate_code()
28449baade8dSMichael Rolnik  *    - restore_state_to_opc()
28459baade8dSMichael Rolnik  *
28469baade8dSMichael Rolnik  */
28479baade8dSMichael Rolnik static void translate(DisasContext *ctx)
28489baade8dSMichael Rolnik {
28499baade8dSMichael Rolnik     uint32_t opcode = next_word(ctx);
28509baade8dSMichael Rolnik 
28519baade8dSMichael Rolnik     if (!decode_insn(ctx, opcode)) {
28529baade8dSMichael Rolnik         gen_helper_unsupported(cpu_env);
28539baade8dSMichael Rolnik         ctx->bstate = DISAS_NORETURN;
28549baade8dSMichael Rolnik     }
28559baade8dSMichael Rolnik }
28569baade8dSMichael Rolnik 
28579baade8dSMichael Rolnik /* Standardize the cpu_skip condition to NE.  */
28589baade8dSMichael Rolnik static bool canonicalize_skip(DisasContext *ctx)
28599baade8dSMichael Rolnik {
28609baade8dSMichael Rolnik     switch (ctx->skip_cond) {
28619baade8dSMichael Rolnik     case TCG_COND_NEVER:
28629baade8dSMichael Rolnik         /* Normal case: cpu_skip is known to be false.  */
28639baade8dSMichael Rolnik         return false;
28649baade8dSMichael Rolnik 
28659baade8dSMichael Rolnik     case TCG_COND_ALWAYS:
28669baade8dSMichael Rolnik         /*
28679baade8dSMichael Rolnik          * Breakpoint case: cpu_skip is known to be true, via TB_FLAGS_SKIP.
28689baade8dSMichael Rolnik          * The breakpoint is on the instruction being skipped, at the start
28699baade8dSMichael Rolnik          * of the TranslationBlock.  No need to update.
28709baade8dSMichael Rolnik          */
28719baade8dSMichael Rolnik         return false;
28729baade8dSMichael Rolnik 
28739baade8dSMichael Rolnik     case TCG_COND_NE:
28749baade8dSMichael Rolnik         if (ctx->skip_var1 == NULL) {
28759baade8dSMichael Rolnik             tcg_gen_mov_tl(cpu_skip, ctx->skip_var0);
28769baade8dSMichael Rolnik         } else {
28779baade8dSMichael Rolnik             tcg_gen_xor_tl(cpu_skip, ctx->skip_var0, ctx->skip_var1);
28789baade8dSMichael Rolnik             ctx->skip_var1 = NULL;
28799baade8dSMichael Rolnik         }
28809baade8dSMichael Rolnik         break;
28819baade8dSMichael Rolnik 
28829baade8dSMichael Rolnik     default:
28839baade8dSMichael Rolnik         /* Convert to a NE condition vs 0. */
28849baade8dSMichael Rolnik         if (ctx->skip_var1 == NULL) {
28859baade8dSMichael Rolnik             tcg_gen_setcondi_tl(ctx->skip_cond, cpu_skip, ctx->skip_var0, 0);
28869baade8dSMichael Rolnik         } else {
28879baade8dSMichael Rolnik             tcg_gen_setcond_tl(ctx->skip_cond, cpu_skip,
28889baade8dSMichael Rolnik                                ctx->skip_var0, ctx->skip_var1);
28899baade8dSMichael Rolnik             ctx->skip_var1 = NULL;
28909baade8dSMichael Rolnik         }
28919baade8dSMichael Rolnik         ctx->skip_cond = TCG_COND_NE;
28929baade8dSMichael Rolnik         break;
28939baade8dSMichael Rolnik     }
28949baade8dSMichael Rolnik     if (ctx->free_skip_var0) {
28959baade8dSMichael Rolnik         tcg_temp_free(ctx->skip_var0);
28969baade8dSMichael Rolnik         ctx->free_skip_var0 = false;
28979baade8dSMichael Rolnik     }
28989baade8dSMichael Rolnik     ctx->skip_var0 = cpu_skip;
28999baade8dSMichael Rolnik     return true;
29009baade8dSMichael Rolnik }
29019baade8dSMichael Rolnik 
29029baade8dSMichael Rolnik void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns)
29039baade8dSMichael Rolnik {
29049baade8dSMichael Rolnik     CPUAVRState *env = cs->env_ptr;
29059baade8dSMichael Rolnik     DisasContext ctx = {
29069baade8dSMichael Rolnik         .tb = tb,
29079baade8dSMichael Rolnik         .cs = cs,
29089baade8dSMichael Rolnik         .env = env,
29099baade8dSMichael Rolnik         .memidx = 0,
29109baade8dSMichael Rolnik         .bstate = DISAS_NEXT,
29119baade8dSMichael Rolnik         .skip_cond = TCG_COND_NEVER,
29129baade8dSMichael Rolnik         .singlestep = cs->singlestep_enabled,
29139baade8dSMichael Rolnik     };
29149baade8dSMichael Rolnik     target_ulong pc_start = tb->pc / 2;
29159baade8dSMichael Rolnik     int num_insns = 0;
29169baade8dSMichael Rolnik 
29179baade8dSMichael Rolnik     if (tb->flags & TB_FLAGS_FULL_ACCESS) {
29189baade8dSMichael Rolnik         /*
29199baade8dSMichael Rolnik          * This flag is set by ST/LD instruction we will regenerate it ONLY
29209baade8dSMichael Rolnik          * with mem/cpu memory access instead of mem access
29219baade8dSMichael Rolnik          */
29229baade8dSMichael Rolnik         max_insns = 1;
29239baade8dSMichael Rolnik     }
29249baade8dSMichael Rolnik     if (ctx.singlestep) {
29259baade8dSMichael Rolnik         max_insns = 1;
29269baade8dSMichael Rolnik     }
29279baade8dSMichael Rolnik 
29289baade8dSMichael Rolnik     gen_tb_start(tb);
29299baade8dSMichael Rolnik 
29309baade8dSMichael Rolnik     ctx.npc = pc_start;
29319baade8dSMichael Rolnik     if (tb->flags & TB_FLAGS_SKIP) {
29329baade8dSMichael Rolnik         ctx.skip_cond = TCG_COND_ALWAYS;
29339baade8dSMichael Rolnik         ctx.skip_var0 = cpu_skip;
29349baade8dSMichael Rolnik     }
29359baade8dSMichael Rolnik 
29369baade8dSMichael Rolnik     do {
29379baade8dSMichael Rolnik         TCGLabel *skip_label = NULL;
29389baade8dSMichael Rolnik 
29399baade8dSMichael Rolnik         /* translate current instruction */
29409baade8dSMichael Rolnik         tcg_gen_insn_start(ctx.npc);
29419baade8dSMichael Rolnik         num_insns++;
29429baade8dSMichael Rolnik 
29439baade8dSMichael Rolnik         /*
29449baade8dSMichael Rolnik          * this is due to some strange GDB behavior
29459baade8dSMichael Rolnik          * let's assume main has address 0x100
29469baade8dSMichael Rolnik          * b main   - sets breakpoint at address 0x00000100 (code)
29479baade8dSMichael Rolnik          * b *0x100 - sets breakpoint at address 0x00800100 (data)
29489baade8dSMichael Rolnik          */
29499baade8dSMichael Rolnik         if (unlikely(!ctx.singlestep &&
29509baade8dSMichael Rolnik                 (cpu_breakpoint_test(cs, OFFSET_CODE + ctx.npc * 2, BP_ANY) ||
29519baade8dSMichael Rolnik                  cpu_breakpoint_test(cs, OFFSET_DATA + ctx.npc * 2, BP_ANY)))) {
29529baade8dSMichael Rolnik             canonicalize_skip(&ctx);
29539baade8dSMichael Rolnik             tcg_gen_movi_tl(cpu_pc, ctx.npc);
29549baade8dSMichael Rolnik             gen_helper_debug(cpu_env);
29559baade8dSMichael Rolnik             goto done_generating;
29569baade8dSMichael Rolnik         }
29579baade8dSMichael Rolnik 
29589baade8dSMichael Rolnik         /* Conditionally skip the next instruction, if indicated.  */
29599baade8dSMichael Rolnik         if (ctx.skip_cond != TCG_COND_NEVER) {
29609baade8dSMichael Rolnik             skip_label = gen_new_label();
29619baade8dSMichael Rolnik             if (ctx.skip_var0 == cpu_skip) {
29629baade8dSMichael Rolnik                 /*
29639baade8dSMichael Rolnik                  * Copy cpu_skip so that we may zero it before the branch.
29649baade8dSMichael Rolnik                  * This ensures that cpu_skip is non-zero after the label
29659baade8dSMichael Rolnik                  * if and only if the skipped insn itself sets a skip.
29669baade8dSMichael Rolnik                  */
29679baade8dSMichael Rolnik                 ctx.free_skip_var0 = true;
29689baade8dSMichael Rolnik                 ctx.skip_var0 = tcg_temp_new();
29699baade8dSMichael Rolnik                 tcg_gen_mov_tl(ctx.skip_var0, cpu_skip);
29709baade8dSMichael Rolnik                 tcg_gen_movi_tl(cpu_skip, 0);
29719baade8dSMichael Rolnik             }
29729baade8dSMichael Rolnik             if (ctx.skip_var1 == NULL) {
29739baade8dSMichael Rolnik                 tcg_gen_brcondi_tl(ctx.skip_cond, ctx.skip_var0, 0, skip_label);
29749baade8dSMichael Rolnik             } else {
29759baade8dSMichael Rolnik                 tcg_gen_brcond_tl(ctx.skip_cond, ctx.skip_var0,
29769baade8dSMichael Rolnik                                   ctx.skip_var1, skip_label);
29779baade8dSMichael Rolnik                 ctx.skip_var1 = NULL;
29789baade8dSMichael Rolnik             }
29799baade8dSMichael Rolnik             if (ctx.free_skip_var0) {
29809baade8dSMichael Rolnik                 tcg_temp_free(ctx.skip_var0);
29819baade8dSMichael Rolnik                 ctx.free_skip_var0 = false;
29829baade8dSMichael Rolnik             }
29839baade8dSMichael Rolnik             ctx.skip_cond = TCG_COND_NEVER;
29849baade8dSMichael Rolnik             ctx.skip_var0 = NULL;
29859baade8dSMichael Rolnik         }
29869baade8dSMichael Rolnik 
29879baade8dSMichael Rolnik         translate(&ctx);
29889baade8dSMichael Rolnik 
29899baade8dSMichael Rolnik         if (skip_label) {
29909baade8dSMichael Rolnik             canonicalize_skip(&ctx);
29919baade8dSMichael Rolnik             gen_set_label(skip_label);
29929baade8dSMichael Rolnik             if (ctx.bstate == DISAS_NORETURN) {
29939baade8dSMichael Rolnik                 ctx.bstate = DISAS_CHAIN;
29949baade8dSMichael Rolnik             }
29959baade8dSMichael Rolnik         }
29969baade8dSMichael Rolnik     } while (ctx.bstate == DISAS_NEXT
29979baade8dSMichael Rolnik              && num_insns < max_insns
29989baade8dSMichael Rolnik              && (ctx.npc - pc_start) * 2 < TARGET_PAGE_SIZE - 4
29999baade8dSMichael Rolnik              && !tcg_op_buf_full());
30009baade8dSMichael Rolnik 
30019baade8dSMichael Rolnik     if (tb->cflags & CF_LAST_IO) {
30029baade8dSMichael Rolnik         gen_io_end();
30039baade8dSMichael Rolnik     }
30049baade8dSMichael Rolnik 
30059baade8dSMichael Rolnik     bool nonconst_skip = canonicalize_skip(&ctx);
30069baade8dSMichael Rolnik 
30079baade8dSMichael Rolnik     switch (ctx.bstate) {
30089baade8dSMichael Rolnik     case DISAS_NORETURN:
30099baade8dSMichael Rolnik         assert(!nonconst_skip);
30109baade8dSMichael Rolnik         break;
30119baade8dSMichael Rolnik     case DISAS_NEXT:
30129baade8dSMichael Rolnik     case DISAS_TOO_MANY:
30139baade8dSMichael Rolnik     case DISAS_CHAIN:
30149baade8dSMichael Rolnik         if (!nonconst_skip) {
30159baade8dSMichael Rolnik             /* Note gen_goto_tb checks singlestep.  */
30169baade8dSMichael Rolnik             gen_goto_tb(&ctx, 1, ctx.npc);
30179baade8dSMichael Rolnik             break;
30189baade8dSMichael Rolnik         }
30199baade8dSMichael Rolnik         tcg_gen_movi_tl(cpu_pc, ctx.npc);
30209baade8dSMichael Rolnik         /* fall through */
30219baade8dSMichael Rolnik     case DISAS_LOOKUP:
30229baade8dSMichael Rolnik         if (!ctx.singlestep) {
30239baade8dSMichael Rolnik             tcg_gen_lookup_and_goto_ptr();
30249baade8dSMichael Rolnik             break;
30259baade8dSMichael Rolnik         }
30269baade8dSMichael Rolnik         /* fall through */
30279baade8dSMichael Rolnik     case DISAS_EXIT:
30289baade8dSMichael Rolnik         if (ctx.singlestep) {
30299baade8dSMichael Rolnik             gen_helper_debug(cpu_env);
30309baade8dSMichael Rolnik         } else {
30319baade8dSMichael Rolnik             tcg_gen_exit_tb(NULL, 0);
30329baade8dSMichael Rolnik         }
30339baade8dSMichael Rolnik         break;
30349baade8dSMichael Rolnik     default:
30359baade8dSMichael Rolnik         g_assert_not_reached();
30369baade8dSMichael Rolnik     }
30379baade8dSMichael Rolnik 
30389baade8dSMichael Rolnik done_generating:
30399baade8dSMichael Rolnik     gen_tb_end(tb, num_insns);
30409baade8dSMichael Rolnik 
30419baade8dSMichael Rolnik     tb->size = (ctx.npc - pc_start) * 2;
30429baade8dSMichael Rolnik     tb->icount = num_insns;
30439baade8dSMichael Rolnik }
30449baade8dSMichael Rolnik 
30459baade8dSMichael Rolnik void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb,
30469baade8dSMichael Rolnik                             target_ulong *data)
30479baade8dSMichael Rolnik {
30489baade8dSMichael Rolnik     env->pc_w = data[0];
30499baade8dSMichael Rolnik }
3050