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