xref: /openbmc/qemu/target/avr/translate.c (revision b77af26e)
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 
33d53106c9SRichard Henderson #define HELPER_H "helper.h"
34d53106c9SRichard Henderson #include "exec/helper-info.c.inc"
35d53106c9SRichard Henderson #undef  HELPER_H
36d53106c9SRichard Henderson 
37d53106c9SRichard Henderson 
38e03feba0SMichael Rolnik /*
39e03feba0SMichael Rolnik  *  Define if you want a BREAK instruction translated to a breakpoint
40e03feba0SMichael Rolnik  *  Active debugging connection is assumed
41e03feba0SMichael Rolnik  *  This is for
42e03feba0SMichael Rolnik  *  https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tests
43e03feba0SMichael Rolnik  *  tests
44e03feba0SMichael Rolnik  */
45e03feba0SMichael Rolnik #undef BREAKPOINT_ON_BREAK
46e03feba0SMichael Rolnik 
47e03feba0SMichael Rolnik static TCGv cpu_pc;
48e03feba0SMichael Rolnik 
49e03feba0SMichael Rolnik static TCGv cpu_Cf;
50e03feba0SMichael Rolnik static TCGv cpu_Zf;
51e03feba0SMichael Rolnik static TCGv cpu_Nf;
52e03feba0SMichael Rolnik static TCGv cpu_Vf;
53e03feba0SMichael Rolnik static TCGv cpu_Sf;
54e03feba0SMichael Rolnik static TCGv cpu_Hf;
55e03feba0SMichael Rolnik static TCGv cpu_Tf;
56e03feba0SMichael Rolnik static TCGv cpu_If;
57e03feba0SMichael Rolnik 
58e03feba0SMichael Rolnik static TCGv cpu_rampD;
59e03feba0SMichael Rolnik static TCGv cpu_rampX;
60e03feba0SMichael Rolnik static TCGv cpu_rampY;
61e03feba0SMichael Rolnik static TCGv cpu_rampZ;
62e03feba0SMichael Rolnik 
63e03feba0SMichael Rolnik static TCGv cpu_r[NUMBER_OF_CPU_REGISTERS];
64e03feba0SMichael Rolnik static TCGv cpu_eind;
65e03feba0SMichael Rolnik static TCGv cpu_sp;
66e03feba0SMichael Rolnik 
67e03feba0SMichael Rolnik static TCGv cpu_skip;
68e03feba0SMichael Rolnik 
69e03feba0SMichael Rolnik static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = {
70e03feba0SMichael Rolnik     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
71e03feba0SMichael Rolnik     "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
72e03feba0SMichael Rolnik     "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
73e03feba0SMichael Rolnik     "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
74e03feba0SMichael Rolnik };
75e03feba0SMichael Rolnik #define REG(x) (cpu_r[x])
76e03feba0SMichael Rolnik 
77eba6814aSStefan Weil #define DISAS_EXIT   DISAS_TARGET_0  /* We want return to the cpu main loop.  */
78eba6814aSStefan Weil #define DISAS_LOOKUP DISAS_TARGET_1  /* We have a variable condition exit.  */
79eba6814aSStefan Weil #define DISAS_CHAIN  DISAS_TARGET_2  /* We have a single condition exit.  */
80e03feba0SMichael Rolnik 
81e03feba0SMichael Rolnik typedef struct DisasContext DisasContext;
82e03feba0SMichael Rolnik 
83e03feba0SMichael Rolnik /* This is the state at translation time. */
84e03feba0SMichael Rolnik struct DisasContext {
8593d4d5e4SRichard Henderson     DisasContextBase base;
86e03feba0SMichael Rolnik 
87e03feba0SMichael Rolnik     CPUAVRState *env;
88e03feba0SMichael Rolnik     CPUState *cs;
89e03feba0SMichael Rolnik 
90e03feba0SMichael Rolnik     target_long npc;
91e03feba0SMichael Rolnik     uint32_t opcode;
92e03feba0SMichael Rolnik 
93e03feba0SMichael Rolnik     /* Routine used to access memory */
94e03feba0SMichael Rolnik     int memidx;
95e03feba0SMichael Rolnik 
96e03feba0SMichael Rolnik     /*
97e03feba0SMichael Rolnik      * some AVR instructions can make the following instruction to be skipped
98e03feba0SMichael Rolnik      * Let's name those instructions
99e03feba0SMichael Rolnik      *     A   - instruction that can skip the next one
100e03feba0SMichael Rolnik      *     B   - instruction that can be skipped. this depends on execution of A
101e03feba0SMichael Rolnik      * there are two scenarios
102e03feba0SMichael Rolnik      * 1. A and B belong to the same translation block
103e03feba0SMichael Rolnik      * 2. A is the last instruction in the translation block and B is the last
104e03feba0SMichael Rolnik      *
105e03feba0SMichael Rolnik      * following variables are used to simplify the skipping logic, they are
106e03feba0SMichael Rolnik      * used in the following manner (sketch)
107e03feba0SMichael Rolnik      *
108e03feba0SMichael Rolnik      * TCGLabel *skip_label = NULL;
109bcef6d76SRichard Henderson      * if (ctx->skip_cond != TCG_COND_NEVER) {
110e03feba0SMichael Rolnik      *     skip_label = gen_new_label();
111e03feba0SMichael Rolnik      *     tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label);
112e03feba0SMichael Rolnik      * }
113e03feba0SMichael Rolnik      *
114bcef6d76SRichard Henderson      * translate(ctx);
115e03feba0SMichael Rolnik      *
116e03feba0SMichael Rolnik      * if (skip_label) {
117e03feba0SMichael Rolnik      *     gen_set_label(skip_label);
118e03feba0SMichael Rolnik      * }
119e03feba0SMichael Rolnik      */
120e03feba0SMichael Rolnik     TCGv skip_var0;
121e03feba0SMichael Rolnik     TCGv skip_var1;
122e03feba0SMichael Rolnik     TCGCond skip_cond;
123e03feba0SMichael Rolnik };
124e03feba0SMichael Rolnik 
avr_cpu_tcg_init(void)125a107fdb0SMichael Rolnik void avr_cpu_tcg_init(void)
126a107fdb0SMichael Rolnik {
127a107fdb0SMichael Rolnik     int i;
128a107fdb0SMichael Rolnik 
129a107fdb0SMichael Rolnik #define AVR_REG_OFFS(x) offsetof(CPUAVRState, x)
130ad75a51eSRichard Henderson     cpu_pc = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(pc_w), "pc");
131ad75a51eSRichard Henderson     cpu_Cf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregC), "Cf");
132ad75a51eSRichard Henderson     cpu_Zf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregZ), "Zf");
133ad75a51eSRichard Henderson     cpu_Nf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregN), "Nf");
134ad75a51eSRichard Henderson     cpu_Vf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregV), "Vf");
135ad75a51eSRichard Henderson     cpu_Sf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregS), "Sf");
136ad75a51eSRichard Henderson     cpu_Hf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregH), "Hf");
137ad75a51eSRichard Henderson     cpu_Tf = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregT), "Tf");
138ad75a51eSRichard Henderson     cpu_If = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sregI), "If");
139ad75a51eSRichard Henderson     cpu_rampD = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampD), "rampD");
140ad75a51eSRichard Henderson     cpu_rampX = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampX), "rampX");
141ad75a51eSRichard Henderson     cpu_rampY = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampY), "rampY");
142ad75a51eSRichard Henderson     cpu_rampZ = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(rampZ), "rampZ");
143ad75a51eSRichard Henderson     cpu_eind = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(eind), "eind");
144ad75a51eSRichard Henderson     cpu_sp = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(sp), "sp");
145ad75a51eSRichard Henderson     cpu_skip = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(skip), "skip");
146a107fdb0SMichael Rolnik 
147a107fdb0SMichael Rolnik     for (i = 0; i < NUMBER_OF_CPU_REGISTERS; i++) {
148ad75a51eSRichard Henderson         cpu_r[i] = tcg_global_mem_new_i32(tcg_env, AVR_REG_OFFS(r[i]),
149a107fdb0SMichael Rolnik                                           reg_names[i]);
150a107fdb0SMichael Rolnik     }
151a107fdb0SMichael Rolnik #undef AVR_REG_OFFS
152a107fdb0SMichael Rolnik }
153a107fdb0SMichael Rolnik 
to_regs_16_31_by_one(DisasContext * ctx,int indx)154865f3bb9SMichael Rolnik static int to_regs_16_31_by_one(DisasContext *ctx, int indx)
155865f3bb9SMichael Rolnik {
156865f3bb9SMichael Rolnik     return 16 + (indx % 16);
157865f3bb9SMichael Rolnik }
158865f3bb9SMichael Rolnik 
to_regs_16_23_by_one(DisasContext * ctx,int indx)159865f3bb9SMichael Rolnik static int to_regs_16_23_by_one(DisasContext *ctx, int indx)
160865f3bb9SMichael Rolnik {
161865f3bb9SMichael Rolnik     return 16 + (indx % 8);
162865f3bb9SMichael Rolnik }
163865f3bb9SMichael Rolnik 
to_regs_24_30_by_two(DisasContext * ctx,int indx)164865f3bb9SMichael Rolnik static int to_regs_24_30_by_two(DisasContext *ctx, int indx)
165865f3bb9SMichael Rolnik {
166865f3bb9SMichael Rolnik     return 24 + (indx % 4) * 2;
167865f3bb9SMichael Rolnik }
168865f3bb9SMichael Rolnik 
to_regs_00_30_by_two(DisasContext * ctx,int indx)1699732b024SMichael Rolnik static int to_regs_00_30_by_two(DisasContext *ctx, int indx)
1709732b024SMichael Rolnik {
1719732b024SMichael Rolnik     return (indx % 16) * 2;
1729732b024SMichael Rolnik }
173865f3bb9SMichael Rolnik 
next_word(DisasContext * ctx)1749d316c75SMichael Rolnik static uint16_t next_word(DisasContext *ctx)
1759d316c75SMichael Rolnik {
1769d316c75SMichael Rolnik     return cpu_lduw_code(ctx->env, ctx->npc++ * 2);
1779d316c75SMichael Rolnik }
1789d316c75SMichael Rolnik 
append_16(DisasContext * ctx,int x)1799d316c75SMichael Rolnik static int append_16(DisasContext *ctx, int x)
1809d316c75SMichael Rolnik {
1819d316c75SMichael Rolnik     return x << 16 | next_word(ctx);
1829d316c75SMichael Rolnik }
1839d316c75SMichael Rolnik 
avr_have_feature(DisasContext * ctx,int feature)184e03feba0SMichael Rolnik static bool avr_have_feature(DisasContext *ctx, int feature)
185e03feba0SMichael Rolnik {
186e03feba0SMichael Rolnik     if (!avr_feature(ctx->env, feature)) {
187ad75a51eSRichard Henderson         gen_helper_unsupported(tcg_env);
18893d4d5e4SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
189e03feba0SMichael Rolnik         return false;
190e03feba0SMichael Rolnik     }
191e03feba0SMichael Rolnik     return true;
192e03feba0SMichael Rolnik }
193e03feba0SMichael Rolnik 
194e03feba0SMichael Rolnik static bool decode_insn(DisasContext *ctx, uint16_t insn);
195abff1abfSPaolo Bonzini #include "decode-insn.c.inc"
196865f3bb9SMichael Rolnik 
197865f3bb9SMichael Rolnik /*
198865f3bb9SMichael Rolnik  * Arithmetic Instructions
199865f3bb9SMichael Rolnik  */
200865f3bb9SMichael Rolnik 
201865f3bb9SMichael Rolnik /*
202865f3bb9SMichael Rolnik  * Utility functions for updating status registers:
203865f3bb9SMichael Rolnik  *
204865f3bb9SMichael Rolnik  *   - gen_add_CHf()
205865f3bb9SMichael Rolnik  *   - gen_add_Vf()
206865f3bb9SMichael Rolnik  *   - gen_sub_CHf()
207865f3bb9SMichael Rolnik  *   - gen_sub_Vf()
208865f3bb9SMichael Rolnik  *   - gen_NSf()
209865f3bb9SMichael Rolnik  *   - gen_ZNSf()
210865f3bb9SMichael Rolnik  *
211865f3bb9SMichael Rolnik  */
212865f3bb9SMichael Rolnik 
gen_add_CHf(TCGv R,TCGv Rd,TCGv Rr)213865f3bb9SMichael Rolnik static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr)
214865f3bb9SMichael Rolnik {
215865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
216865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
217865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
218865f3bb9SMichael Rolnik 
219865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */
220865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */
221865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */
222865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */
223865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t3);
224865f3bb9SMichael Rolnik 
225865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */
226865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */
227865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
228865f3bb9SMichael Rolnik }
229865f3bb9SMichael Rolnik 
gen_add_Vf(TCGv R,TCGv Rd,TCGv Rr)230865f3bb9SMichael Rolnik static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
231865f3bb9SMichael Rolnik {
232865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
233865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
234865f3bb9SMichael Rolnik 
235865f3bb9SMichael Rolnik     /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */
236865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & ~(Rd ^ Rr) */
237865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
238865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
239865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t1, t1, t2);
240865f3bb9SMichael Rolnik 
241865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
242865f3bb9SMichael Rolnik }
243865f3bb9SMichael Rolnik 
gen_sub_CHf(TCGv R,TCGv Rd,TCGv Rr)244865f3bb9SMichael Rolnik static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
245865f3bb9SMichael Rolnik {
246865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
247865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
248865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
249865f3bb9SMichael Rolnik 
250865f3bb9SMichael Rolnik     tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */
251865f3bb9SMichael Rolnik     tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */
252865f3bb9SMichael Rolnik     tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */
253865f3bb9SMichael Rolnik     tcg_gen_and_tl(t3, t3, R);
254865f3bb9SMichael Rolnik     tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */
255865f3bb9SMichael Rolnik 
256865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */
257865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */
258865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
259865f3bb9SMichael Rolnik }
260865f3bb9SMichael Rolnik 
gen_sub_Vf(TCGv R,TCGv Rd,TCGv Rr)261865f3bb9SMichael Rolnik static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
262865f3bb9SMichael Rolnik {
263865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
264865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
265865f3bb9SMichael Rolnik 
266865f3bb9SMichael Rolnik     /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */
267865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & (Rd ^ R) */
268865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
269865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
270865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, t1, t2);
271865f3bb9SMichael Rolnik 
272865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
273865f3bb9SMichael Rolnik }
274865f3bb9SMichael Rolnik 
gen_NSf(TCGv R)275865f3bb9SMichael Rolnik static void gen_NSf(TCGv R)
276865f3bb9SMichael Rolnik {
277865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
278865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
279865f3bb9SMichael Rolnik }
280865f3bb9SMichael Rolnik 
gen_ZNSf(TCGv R)281865f3bb9SMichael Rolnik static void gen_ZNSf(TCGv R)
282865f3bb9SMichael Rolnik {
283865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
284865f3bb9SMichael Rolnik 
285865f3bb9SMichael Rolnik     /* update status register */
286865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
287865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
288865f3bb9SMichael Rolnik }
289865f3bb9SMichael Rolnik 
290865f3bb9SMichael Rolnik /*
291865f3bb9SMichael Rolnik  *  Adds two registers without the C Flag and places the result in the
292865f3bb9SMichael Rolnik  *  destination register Rd.
293865f3bb9SMichael Rolnik  */
trans_ADD(DisasContext * ctx,arg_ADD * a)294865f3bb9SMichael Rolnik static bool trans_ADD(DisasContext *ctx, arg_ADD *a)
295865f3bb9SMichael Rolnik {
296865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
297865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
298865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
299865f3bb9SMichael Rolnik 
300865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */
301865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
302865f3bb9SMichael Rolnik 
303865f3bb9SMichael Rolnik     /* update status register */
304865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
305865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
306865f3bb9SMichael Rolnik     gen_ZNSf(R);
307865f3bb9SMichael Rolnik 
308865f3bb9SMichael Rolnik     /* update output registers */
309865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
310865f3bb9SMichael Rolnik     return true;
311865f3bb9SMichael Rolnik }
312865f3bb9SMichael Rolnik 
313865f3bb9SMichael Rolnik /*
314865f3bb9SMichael Rolnik  *  Adds two registers and the contents of the C Flag and places the result in
315865f3bb9SMichael Rolnik  *  the destination register Rd.
316865f3bb9SMichael Rolnik  */
trans_ADC(DisasContext * ctx,arg_ADC * a)317865f3bb9SMichael Rolnik static bool trans_ADC(DisasContext *ctx, arg_ADC *a)
318865f3bb9SMichael Rolnik {
319865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
320865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
321865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
322865f3bb9SMichael Rolnik 
323865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */
324865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, R, cpu_Cf);
325865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
326865f3bb9SMichael Rolnik 
327865f3bb9SMichael Rolnik     /* update status register */
328865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
329865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
330865f3bb9SMichael Rolnik     gen_ZNSf(R);
331865f3bb9SMichael Rolnik 
332865f3bb9SMichael Rolnik     /* update output registers */
333865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
334865f3bb9SMichael Rolnik     return true;
335865f3bb9SMichael Rolnik }
336865f3bb9SMichael Rolnik 
337865f3bb9SMichael Rolnik /*
338865f3bb9SMichael Rolnik  *  Adds an immediate value (0 - 63) to a register pair and places the result
339865f3bb9SMichael Rolnik  *  in the register pair. This instruction operates on the upper four register
340865f3bb9SMichael Rolnik  *  pairs, and is well suited for operations on the pointer registers.  This
341865f3bb9SMichael Rolnik  *  instruction is not available in all devices. Refer to the device specific
342865f3bb9SMichael Rolnik  *  instruction set summary.
343865f3bb9SMichael Rolnik  */
trans_ADIW(DisasContext * ctx,arg_ADIW * a)344865f3bb9SMichael Rolnik static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a)
345865f3bb9SMichael Rolnik {
346865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
347865f3bb9SMichael Rolnik         return true;
348865f3bb9SMichael Rolnik     }
349865f3bb9SMichael Rolnik 
350865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
351865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
352865f3bb9SMichael Rolnik     int Imm = (a->imm);
353865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
354865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
355865f3bb9SMichael Rolnik 
356865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
357865f3bb9SMichael Rolnik     tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */
358865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
359865f3bb9SMichael Rolnik 
360865f3bb9SMichael Rolnik     /* update status register */
361865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
362865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15);
363865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */
364865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15);
365865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
366865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
367865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */
368865f3bb9SMichael Rolnik 
369865f3bb9SMichael Rolnik     /* update output registers */
370865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
371865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
372865f3bb9SMichael Rolnik     return true;
373865f3bb9SMichael Rolnik }
374865f3bb9SMichael Rolnik 
375865f3bb9SMichael Rolnik /*
376865f3bb9SMichael Rolnik  *  Subtracts two registers and places the result in the destination
377865f3bb9SMichael Rolnik  *  register Rd.
378865f3bb9SMichael Rolnik  */
trans_SUB(DisasContext * ctx,arg_SUB * a)379865f3bb9SMichael Rolnik static bool trans_SUB(DisasContext *ctx, arg_SUB *a)
380865f3bb9SMichael Rolnik {
381865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
382865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
383865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
384865f3bb9SMichael Rolnik 
385865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
386865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
387865f3bb9SMichael Rolnik 
388865f3bb9SMichael Rolnik     /* update status register */
389865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
390865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
391865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
392865f3bb9SMichael Rolnik     gen_ZNSf(R);
393865f3bb9SMichael Rolnik 
394865f3bb9SMichael Rolnik     /* update output registers */
395865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
396865f3bb9SMichael Rolnik     return true;
397865f3bb9SMichael Rolnik }
398865f3bb9SMichael Rolnik 
399865f3bb9SMichael Rolnik /*
400865f3bb9SMichael Rolnik  *  Subtracts a register and a constant and places the result in the
401865f3bb9SMichael Rolnik  *  destination register Rd. This instruction is working on Register R16 to R31
402865f3bb9SMichael Rolnik  *  and is very well suited for operations on the X, Y, and Z-pointers.
403865f3bb9SMichael Rolnik  */
trans_SUBI(DisasContext * ctx,arg_SUBI * a)404865f3bb9SMichael Rolnik static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a)
405865f3bb9SMichael Rolnik {
406865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
4076d27bb55SRichard Henderson     TCGv Rr = tcg_constant_i32(a->imm);
408865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
409865f3bb9SMichael Rolnik 
410865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */
411865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
412865f3bb9SMichael Rolnik 
413865f3bb9SMichael Rolnik     /* update status register */
414865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
415865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
416865f3bb9SMichael Rolnik     gen_ZNSf(R);
417865f3bb9SMichael Rolnik 
418865f3bb9SMichael Rolnik     /* update output registers */
419865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
420865f3bb9SMichael Rolnik     return true;
421865f3bb9SMichael Rolnik }
422865f3bb9SMichael Rolnik 
423865f3bb9SMichael Rolnik /*
424865f3bb9SMichael Rolnik  *  Subtracts two registers and subtracts with the C Flag and places the
425865f3bb9SMichael Rolnik  *  result in the destination register Rd.
426865f3bb9SMichael Rolnik  */
trans_SBC(DisasContext * ctx,arg_SBC * a)427865f3bb9SMichael Rolnik static bool trans_SBC(DisasContext *ctx, arg_SBC *a)
428865f3bb9SMichael Rolnik {
429865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
430865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
431865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
4326d27bb55SRichard Henderson     TCGv zero = tcg_constant_i32(0);
433865f3bb9SMichael Rolnik 
434865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
435865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
436865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
437865f3bb9SMichael Rolnik 
438865f3bb9SMichael Rolnik     /* update status register */
439865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
440865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
441865f3bb9SMichael Rolnik     gen_NSf(R);
442865f3bb9SMichael Rolnik 
443865f3bb9SMichael Rolnik     /*
444865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
445865f3bb9SMichael Rolnik      * cleared otherwise.
446865f3bb9SMichael Rolnik      */
447865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
448865f3bb9SMichael Rolnik 
449865f3bb9SMichael Rolnik     /* update output registers */
450865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
451865f3bb9SMichael Rolnik     return true;
452865f3bb9SMichael Rolnik }
453865f3bb9SMichael Rolnik 
454865f3bb9SMichael Rolnik /*
455865f3bb9SMichael Rolnik  *  SBCI -- Subtract Immediate with Carry
456865f3bb9SMichael Rolnik  */
trans_SBCI(DisasContext * ctx,arg_SBCI * a)457865f3bb9SMichael Rolnik static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a)
458865f3bb9SMichael Rolnik {
459865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
4606d27bb55SRichard Henderson     TCGv Rr = tcg_constant_i32(a->imm);
461865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
4626d27bb55SRichard Henderson     TCGv zero = tcg_constant_i32(0);
463865f3bb9SMichael Rolnik 
464865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
465865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
466865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
467865f3bb9SMichael Rolnik 
468865f3bb9SMichael Rolnik     /* update status register */
469865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
470865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
471865f3bb9SMichael Rolnik     gen_NSf(R);
472865f3bb9SMichael Rolnik 
473865f3bb9SMichael Rolnik     /*
474865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
475865f3bb9SMichael Rolnik      * cleared otherwise.
476865f3bb9SMichael Rolnik      */
477865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
478865f3bb9SMichael Rolnik 
479865f3bb9SMichael Rolnik     /* update output registers */
480865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
481865f3bb9SMichael Rolnik     return true;
482865f3bb9SMichael Rolnik }
483865f3bb9SMichael Rolnik 
484865f3bb9SMichael Rolnik /*
485865f3bb9SMichael Rolnik  *  Subtracts an immediate value (0-63) from a register pair and places the
486865f3bb9SMichael Rolnik  *  result in the register pair. This instruction operates on the upper four
487865f3bb9SMichael Rolnik  *  register pairs, and is well suited for operations on the Pointer Registers.
488865f3bb9SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
489865f3bb9SMichael Rolnik  *  specific instruction set summary.
490865f3bb9SMichael Rolnik  */
trans_SBIW(DisasContext * ctx,arg_SBIW * a)491865f3bb9SMichael Rolnik static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a)
492865f3bb9SMichael Rolnik {
493865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
494865f3bb9SMichael Rolnik         return true;
495865f3bb9SMichael Rolnik     }
496865f3bb9SMichael Rolnik 
497865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
498865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
499865f3bb9SMichael Rolnik     int Imm = (a->imm);
500865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
501865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
502865f3bb9SMichael Rolnik 
503865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
504865f3bb9SMichael Rolnik     tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */
505865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
506865f3bb9SMichael Rolnik 
507865f3bb9SMichael Rolnik     /* update status register */
508865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, R, Rd);
509865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */
510865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, Rd, R);
511865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */
512865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
513865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
514865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
515865f3bb9SMichael Rolnik 
516865f3bb9SMichael Rolnik     /* update output registers */
517865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
518865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
519865f3bb9SMichael Rolnik     return true;
520865f3bb9SMichael Rolnik }
521865f3bb9SMichael Rolnik 
522865f3bb9SMichael Rolnik /*
523865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and register
524865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
525865f3bb9SMichael Rolnik  */
trans_AND(DisasContext * ctx,arg_AND * a)526865f3bb9SMichael Rolnik static bool trans_AND(DisasContext *ctx, arg_AND *a)
527865f3bb9SMichael Rolnik {
528865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
529865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
530865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
531865f3bb9SMichael Rolnik 
532865f3bb9SMichael Rolnik     tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */
533865f3bb9SMichael Rolnik 
534865f3bb9SMichael Rolnik     /* update status register */
535865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
536865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
537865f3bb9SMichael Rolnik     gen_ZNSf(R);
538865f3bb9SMichael Rolnik 
539865f3bb9SMichael Rolnik     /* update output registers */
540865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
541865f3bb9SMichael Rolnik     return true;
542865f3bb9SMichael Rolnik }
543865f3bb9SMichael Rolnik 
544865f3bb9SMichael Rolnik /*
545865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and a constant
546865f3bb9SMichael Rolnik  *  and places the result in the destination register Rd.
547865f3bb9SMichael Rolnik  */
trans_ANDI(DisasContext * ctx,arg_ANDI * a)548865f3bb9SMichael Rolnik static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a)
549865f3bb9SMichael Rolnik {
550865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
551865f3bb9SMichael Rolnik     int Imm = (a->imm);
552865f3bb9SMichael Rolnik 
553865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */
554865f3bb9SMichael Rolnik 
555865f3bb9SMichael Rolnik     /* update status register */
556865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
557865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
558865f3bb9SMichael Rolnik 
559865f3bb9SMichael Rolnik     return true;
560865f3bb9SMichael Rolnik }
561865f3bb9SMichael Rolnik 
562865f3bb9SMichael Rolnik /*
563865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and register
564865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
565865f3bb9SMichael Rolnik  */
trans_OR(DisasContext * ctx,arg_OR * a)566865f3bb9SMichael Rolnik static bool trans_OR(DisasContext *ctx, arg_OR *a)
567865f3bb9SMichael Rolnik {
568865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
569865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
570865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
571865f3bb9SMichael Rolnik 
572865f3bb9SMichael Rolnik     tcg_gen_or_tl(R, Rd, Rr);
573865f3bb9SMichael Rolnik 
574865f3bb9SMichael Rolnik     /* update status register */
575865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
576865f3bb9SMichael Rolnik     gen_ZNSf(R);
577865f3bb9SMichael Rolnik 
578865f3bb9SMichael Rolnik     /* update output registers */
579865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
580865f3bb9SMichael Rolnik     return true;
581865f3bb9SMichael Rolnik }
582865f3bb9SMichael Rolnik 
583865f3bb9SMichael Rolnik /*
584865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and a
585865f3bb9SMichael Rolnik  *  constant and places the result in the destination register Rd.
586865f3bb9SMichael Rolnik  */
trans_ORI(DisasContext * ctx,arg_ORI * a)587865f3bb9SMichael Rolnik static bool trans_ORI(DisasContext *ctx, arg_ORI *a)
588865f3bb9SMichael Rolnik {
589865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
590865f3bb9SMichael Rolnik     int Imm = (a->imm);
591865f3bb9SMichael Rolnik 
592865f3bb9SMichael Rolnik     tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */
593865f3bb9SMichael Rolnik 
594865f3bb9SMichael Rolnik     /* update status register */
595865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
596865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
597865f3bb9SMichael Rolnik 
598865f3bb9SMichael Rolnik     return true;
599865f3bb9SMichael Rolnik }
600865f3bb9SMichael Rolnik 
601865f3bb9SMichael Rolnik /*
602865f3bb9SMichael Rolnik  *  Performs the logical EOR between the contents of register Rd and
603865f3bb9SMichael Rolnik  *  register Rr and places the result in the destination register Rd.
604865f3bb9SMichael Rolnik  */
trans_EOR(DisasContext * ctx,arg_EOR * a)605865f3bb9SMichael Rolnik static bool trans_EOR(DisasContext *ctx, arg_EOR *a)
606865f3bb9SMichael Rolnik {
607865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
608865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
609865f3bb9SMichael Rolnik 
610865f3bb9SMichael Rolnik     tcg_gen_xor_tl(Rd, Rd, Rr);
611865f3bb9SMichael Rolnik 
612865f3bb9SMichael Rolnik     /* update status register */
613865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
614865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
615865f3bb9SMichael Rolnik 
616865f3bb9SMichael Rolnik     return true;
617865f3bb9SMichael Rolnik }
618865f3bb9SMichael Rolnik 
619865f3bb9SMichael Rolnik /*
620865f3bb9SMichael Rolnik  *  Clears the specified bits in register Rd. Performs the logical AND
621865f3bb9SMichael Rolnik  *  between the contents of register Rd and the complement of the constant mask
622865f3bb9SMichael Rolnik  *  K. The result will be placed in register Rd.
623865f3bb9SMichael Rolnik  */
trans_COM(DisasContext * ctx,arg_COM * a)624865f3bb9SMichael Rolnik static bool trans_COM(DisasContext *ctx, arg_COM *a)
625865f3bb9SMichael Rolnik {
626865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
627865f3bb9SMichael Rolnik 
628865f3bb9SMichael Rolnik     tcg_gen_xori_tl(Rd, Rd, 0xff);
629865f3bb9SMichael Rolnik 
630865f3bb9SMichael Rolnik     /* update status register */
631865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */
632865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
633865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
634865f3bb9SMichael Rolnik     return true;
635865f3bb9SMichael Rolnik }
636865f3bb9SMichael Rolnik 
637865f3bb9SMichael Rolnik /*
638865f3bb9SMichael Rolnik  *  Replaces the contents of register Rd with its two's complement; the
639865f3bb9SMichael Rolnik  *  value $80 is left unchanged.
640865f3bb9SMichael Rolnik  */
trans_NEG(DisasContext * ctx,arg_NEG * a)641865f3bb9SMichael Rolnik static bool trans_NEG(DisasContext *ctx, arg_NEG *a)
642865f3bb9SMichael Rolnik {
643865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
6446d27bb55SRichard Henderson     TCGv t0 = tcg_constant_i32(0);
645865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
646865f3bb9SMichael Rolnik 
647865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */
648865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
649865f3bb9SMichael Rolnik 
650865f3bb9SMichael Rolnik     /* update status register */
651865f3bb9SMichael Rolnik     gen_sub_CHf(R, t0, Rd);
652865f3bb9SMichael Rolnik     gen_sub_Vf(R, t0, Rd);
653865f3bb9SMichael Rolnik     gen_ZNSf(R);
654865f3bb9SMichael Rolnik 
655865f3bb9SMichael Rolnik     /* update output registers */
656865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
657865f3bb9SMichael Rolnik     return true;
658865f3bb9SMichael Rolnik }
659865f3bb9SMichael Rolnik 
660865f3bb9SMichael Rolnik /*
661865f3bb9SMichael Rolnik  *  Adds one -1- to the contents of register Rd and places the result in the
662865f3bb9SMichael Rolnik  *  destination register Rd.  The C Flag in SREG is not affected by the
663865f3bb9SMichael Rolnik  *  operation, thus allowing the INC instruction to be used on a loop counter in
664865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned numbers, only
665865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently. When
666865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
667865f3bb9SMichael Rolnik  */
trans_INC(DisasContext * ctx,arg_INC * a)668865f3bb9SMichael Rolnik static bool trans_INC(DisasContext *ctx, arg_INC *a)
669865f3bb9SMichael Rolnik {
670865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
671865f3bb9SMichael Rolnik 
672865f3bb9SMichael Rolnik     tcg_gen_addi_tl(Rd, Rd, 1);
673865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff);
674865f3bb9SMichael Rolnik 
675865f3bb9SMichael Rolnik     /* update status register */
676865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */
677865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
678865f3bb9SMichael Rolnik 
679865f3bb9SMichael Rolnik     return true;
680865f3bb9SMichael Rolnik }
681865f3bb9SMichael Rolnik 
682865f3bb9SMichael Rolnik /*
683865f3bb9SMichael Rolnik  *  Subtracts one -1- from the contents of register Rd and places the result
684865f3bb9SMichael Rolnik  *  in the destination register Rd.  The C Flag in SREG is not affected by the
685865f3bb9SMichael Rolnik  *  operation, thus allowing the DEC instruction to be used on a loop counter in
686865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned values, only
687865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently.  When
688865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
689865f3bb9SMichael Rolnik  */
trans_DEC(DisasContext * ctx,arg_DEC * a)690865f3bb9SMichael Rolnik static bool trans_DEC(DisasContext *ctx, arg_DEC *a)
691865f3bb9SMichael Rolnik {
692865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
693865f3bb9SMichael Rolnik 
694865f3bb9SMichael Rolnik     tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
695865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
696865f3bb9SMichael Rolnik 
697865f3bb9SMichael Rolnik     /* update status register */
698865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */
699865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
700865f3bb9SMichael Rolnik 
701865f3bb9SMichael Rolnik     return true;
702865f3bb9SMichael Rolnik }
703865f3bb9SMichael Rolnik 
704865f3bb9SMichael Rolnik /*
705865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication.
706865f3bb9SMichael Rolnik  */
trans_MUL(DisasContext * ctx,arg_MUL * a)707865f3bb9SMichael Rolnik static bool trans_MUL(DisasContext *ctx, arg_MUL *a)
708865f3bb9SMichael Rolnik {
709865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
710865f3bb9SMichael Rolnik         return true;
711865f3bb9SMichael Rolnik     }
712865f3bb9SMichael Rolnik 
713865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
714865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
715865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
716865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
717865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
718865f3bb9SMichael Rolnik 
719865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
720865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
721865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
722865f3bb9SMichael Rolnik 
723865f3bb9SMichael Rolnik     /* update status register */
724865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
725865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
726865f3bb9SMichael Rolnik     return true;
727865f3bb9SMichael Rolnik }
728865f3bb9SMichael Rolnik 
729865f3bb9SMichael Rolnik /*
730865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication.
731865f3bb9SMichael Rolnik  */
trans_MULS(DisasContext * ctx,arg_MULS * a)732865f3bb9SMichael Rolnik static bool trans_MULS(DisasContext *ctx, arg_MULS *a)
733865f3bb9SMichael Rolnik {
734865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
735865f3bb9SMichael Rolnik         return true;
736865f3bb9SMichael Rolnik     }
737865f3bb9SMichael Rolnik 
738865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
739865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
740865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
741865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
742865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
743865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
744865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
745865f3bb9SMichael Rolnik 
746865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
747865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
748865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
749865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
750865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
751865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
752865f3bb9SMichael Rolnik 
753865f3bb9SMichael Rolnik     /* update status register */
754865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
755865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
756865f3bb9SMichael Rolnik     return true;
757865f3bb9SMichael Rolnik }
758865f3bb9SMichael Rolnik 
759865f3bb9SMichael Rolnik /*
760865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a
761865f3bb9SMichael Rolnik  *  signed and an unsigned number.
762865f3bb9SMichael Rolnik  */
trans_MULSU(DisasContext * ctx,arg_MULSU * a)763865f3bb9SMichael Rolnik static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a)
764865f3bb9SMichael Rolnik {
765865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
766865f3bb9SMichael Rolnik         return true;
767865f3bb9SMichael Rolnik     }
768865f3bb9SMichael Rolnik 
769865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
770865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
771865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
772865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
773865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
774865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
775865f3bb9SMichael Rolnik 
776865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
777865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
778865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */
779865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
780865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
781865f3bb9SMichael Rolnik 
782865f3bb9SMichael Rolnik     /* update status register */
783865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
784865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
785865f3bb9SMichael Rolnik     return true;
786865f3bb9SMichael Rolnik }
787865f3bb9SMichael Rolnik 
788865f3bb9SMichael Rolnik /*
789865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned
790865f3bb9SMichael Rolnik  *  multiplication and shifts the result one bit left.
791865f3bb9SMichael Rolnik  */
trans_FMUL(DisasContext * ctx,arg_FMUL * a)792865f3bb9SMichael Rolnik static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a)
793865f3bb9SMichael Rolnik {
794865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
795865f3bb9SMichael Rolnik         return true;
796865f3bb9SMichael Rolnik     }
797865f3bb9SMichael Rolnik 
798865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
799865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
800865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
801865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
802865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
803865f3bb9SMichael Rolnik 
804865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
805865f3bb9SMichael Rolnik 
806865f3bb9SMichael Rolnik     /* update status register */
807865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
808865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
809865f3bb9SMichael Rolnik 
810865f3bb9SMichael Rolnik     /* update output registers */
811865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
812865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
813865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
814865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
815865f3bb9SMichael Rolnik     return true;
816865f3bb9SMichael Rolnik }
817865f3bb9SMichael Rolnik 
818865f3bb9SMichael Rolnik /*
819865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
820865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
821865f3bb9SMichael Rolnik  */
trans_FMULS(DisasContext * ctx,arg_FMULS * a)822865f3bb9SMichael Rolnik static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a)
823865f3bb9SMichael Rolnik {
824865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
825865f3bb9SMichael Rolnik         return true;
826865f3bb9SMichael Rolnik     }
827865f3bb9SMichael Rolnik 
828865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
829865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
830865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
831865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
832865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
833865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
834865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
835865f3bb9SMichael Rolnik 
836865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
837865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
838865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
839865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
840865f3bb9SMichael Rolnik 
841865f3bb9SMichael Rolnik     /* update status register */
842865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
843865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
844865f3bb9SMichael Rolnik 
845865f3bb9SMichael Rolnik     /* update output registers */
846865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
847865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
848865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
849865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
850865f3bb9SMichael Rolnik     return true;
851865f3bb9SMichael Rolnik }
852865f3bb9SMichael Rolnik 
853865f3bb9SMichael Rolnik /*
854865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
855865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
856865f3bb9SMichael Rolnik  */
trans_FMULSU(DisasContext * ctx,arg_FMULSU * a)857865f3bb9SMichael Rolnik static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a)
858865f3bb9SMichael Rolnik {
859865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
860865f3bb9SMichael Rolnik         return true;
861865f3bb9SMichael Rolnik     }
862865f3bb9SMichael Rolnik 
863865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
864865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
865865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
866865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
867865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
868865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
869865f3bb9SMichael Rolnik 
870865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
871865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
872865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
873865f3bb9SMichael Rolnik 
874865f3bb9SMichael Rolnik     /* update status register */
875865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
876865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
877865f3bb9SMichael Rolnik 
878865f3bb9SMichael Rolnik     /* update output registers */
879865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
880865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
881865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
882865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
883865f3bb9SMichael Rolnik     return true;
884865f3bb9SMichael Rolnik }
885865f3bb9SMichael Rolnik 
886865f3bb9SMichael Rolnik /*
887865f3bb9SMichael Rolnik  *  The module is an instruction set extension to the AVR CPU, performing
888865f3bb9SMichael Rolnik  *  DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in
889865f3bb9SMichael Rolnik  *  the CPU register file, registers R0-R7, where LSB of data is placed in LSB
890865f3bb9SMichael Rolnik  *  of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including
891865f3bb9SMichael Rolnik  *  parity bits) is placed in registers R8- R15, organized in the register file
892865f3bb9SMichael Rolnik  *  with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES
893865f3bb9SMichael Rolnik  *  instruction performs one round in the DES algorithm. Sixteen rounds must be
894865f3bb9SMichael Rolnik  *  executed in increasing order to form the correct DES ciphertext or
895865f3bb9SMichael Rolnik  *  plaintext. Intermediate results are stored in the register file (R0-R15)
896865f3bb9SMichael Rolnik  *  after each DES instruction. The instruction's operand (K) determines which
897865f3bb9SMichael Rolnik  *  round is executed, and the half carry flag (H) determines whether encryption
898865f3bb9SMichael Rolnik  *  or decryption is performed.  The DES algorithm is described in
899865f3bb9SMichael Rolnik  *  "Specifications for the Data Encryption Standard" (Federal Information
900865f3bb9SMichael Rolnik  *  Processing Standards Publication 46). Intermediate results in this
901865f3bb9SMichael Rolnik  *  implementation differ from the standard because the initial permutation and
902865f3bb9SMichael Rolnik  *  the inverse initial permutation are performed each iteration. This does not
903865f3bb9SMichael Rolnik  *  affect the result in the final ciphertext or plaintext, but reduces
904865f3bb9SMichael Rolnik  *  execution time.
905865f3bb9SMichael Rolnik  */
trans_DES(DisasContext * ctx,arg_DES * a)906865f3bb9SMichael Rolnik static bool trans_DES(DisasContext *ctx, arg_DES *a)
907865f3bb9SMichael Rolnik {
908865f3bb9SMichael Rolnik     /* TODO */
909865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_DES)) {
910865f3bb9SMichael Rolnik         return true;
911865f3bb9SMichael Rolnik     }
912865f3bb9SMichael Rolnik 
913865f3bb9SMichael Rolnik     qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
914865f3bb9SMichael Rolnik 
915865f3bb9SMichael Rolnik     return true;
916865f3bb9SMichael Rolnik }
9179d316c75SMichael Rolnik 
9189d316c75SMichael Rolnik /*
9199d316c75SMichael Rolnik  * Branch Instructions
9209d316c75SMichael Rolnik  */
gen_jmp_ez(DisasContext * ctx)9219d316c75SMichael Rolnik static void gen_jmp_ez(DisasContext *ctx)
9229d316c75SMichael Rolnik {
9239d316c75SMichael Rolnik     tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
9249d316c75SMichael Rolnik     tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind);
92593d4d5e4SRichard Henderson     ctx->base.is_jmp = DISAS_LOOKUP;
9269d316c75SMichael Rolnik }
9279d316c75SMichael Rolnik 
gen_jmp_z(DisasContext * ctx)9289d316c75SMichael Rolnik static void gen_jmp_z(DisasContext *ctx)
9299d316c75SMichael Rolnik {
9309d316c75SMichael Rolnik     tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
93193d4d5e4SRichard Henderson     ctx->base.is_jmp = DISAS_LOOKUP;
9329d316c75SMichael Rolnik }
9339d316c75SMichael Rolnik 
gen_push_ret(DisasContext * ctx,int ret)9349d316c75SMichael Rolnik static void gen_push_ret(DisasContext *ctx, int ret)
9359d316c75SMichael Rolnik {
9369d316c75SMichael Rolnik     if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
9376d27bb55SRichard Henderson         TCGv t0 = tcg_constant_i32(ret & 0x0000ff);
9389d316c75SMichael Rolnik 
9399d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB);
9409d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
9419d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
9426d27bb55SRichard Henderson         TCGv t0 = tcg_constant_i32(ret & 0x00ffff);
9439d316c75SMichael Rolnik 
9449d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
9459d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW);
9469d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
9479d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
9486d27bb55SRichard Henderson         TCGv lo = tcg_constant_i32(ret & 0x0000ff);
9496d27bb55SRichard Henderson         TCGv hi = tcg_constant_i32((ret & 0xffff00) >> 8);
9509d316c75SMichael Rolnik 
9519d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
9529d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 2);
9539d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
9549d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
9559d316c75SMichael Rolnik     }
9569d316c75SMichael Rolnik }
9579d316c75SMichael Rolnik 
gen_pop_ret(DisasContext * ctx,TCGv ret)9589d316c75SMichael Rolnik static void gen_pop_ret(DisasContext *ctx, TCGv ret)
9599d316c75SMichael Rolnik {
9609d316c75SMichael Rolnik     if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
9619d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
9629d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB);
9639d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
9649d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
9659d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW);
9669d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
9679d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
9689d316c75SMichael Rolnik         TCGv lo = tcg_temp_new_i32();
9699d316c75SMichael Rolnik         TCGv hi = tcg_temp_new_i32();
9709d316c75SMichael Rolnik 
9719d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
9729d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
9739d316c75SMichael Rolnik 
9749d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 2);
9759d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
9769d316c75SMichael Rolnik 
9779d316c75SMichael Rolnik         tcg_gen_deposit_tl(ret, lo, hi, 8, 16);
9789d316c75SMichael Rolnik     }
9799d316c75SMichael Rolnik }
9809d316c75SMichael Rolnik 
gen_goto_tb(DisasContext * ctx,int n,target_ulong dest)9819d316c75SMichael Rolnik static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
9829d316c75SMichael Rolnik {
98393d4d5e4SRichard Henderson     const TranslationBlock *tb = ctx->base.tb;
9849d316c75SMichael Rolnik 
985a50d52bcSRichard Henderson     if (translator_use_goto_tb(&ctx->base, dest)) {
9869d316c75SMichael Rolnik         tcg_gen_goto_tb(n);
9879d316c75SMichael Rolnik         tcg_gen_movi_i32(cpu_pc, dest);
9889d316c75SMichael Rolnik         tcg_gen_exit_tb(tb, n);
9899d316c75SMichael Rolnik     } else {
9909d316c75SMichael Rolnik         tcg_gen_movi_i32(cpu_pc, dest);
991a50d52bcSRichard Henderson         tcg_gen_lookup_and_goto_ptr();
992a50d52bcSRichard Henderson     }
99393d4d5e4SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
9949d316c75SMichael Rolnik }
9959d316c75SMichael Rolnik 
9969d316c75SMichael Rolnik /*
9979d316c75SMichael Rolnik  *  Relative jump to an address within PC - 2K +1 and PC + 2K (words). For
9989d316c75SMichael Rolnik  *  AVR microcontrollers with Program memory not exceeding 4K words (8KB) this
9999d316c75SMichael Rolnik  *  instruction can address the entire memory from every address location. See
10009d316c75SMichael Rolnik  *  also JMP.
10019d316c75SMichael Rolnik  */
trans_RJMP(DisasContext * ctx,arg_RJMP * a)10029d316c75SMichael Rolnik static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a)
10039d316c75SMichael Rolnik {
10049d316c75SMichael Rolnik     int dst = ctx->npc + a->imm;
10059d316c75SMichael Rolnik 
10069d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, dst);
10079d316c75SMichael Rolnik 
10089d316c75SMichael Rolnik     return true;
10099d316c75SMichael Rolnik }
10109d316c75SMichael Rolnik 
10119d316c75SMichael Rolnik /*
10129d316c75SMichael Rolnik  *  Indirect jump to the address pointed to by the Z (16 bits) Pointer
10139d316c75SMichael Rolnik  *  Register in the Register File. The Z-pointer Register is 16 bits wide and
10149d316c75SMichael Rolnik  *  allows jump within the lowest 64K words (128KB) section of Program memory.
10159d316c75SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
10169d316c75SMichael Rolnik  *  specific instruction set summary.
10179d316c75SMichael Rolnik  */
trans_IJMP(DisasContext * ctx,arg_IJMP * a)10189d316c75SMichael Rolnik static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a)
10199d316c75SMichael Rolnik {
10209d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) {
10219d316c75SMichael Rolnik         return true;
10229d316c75SMichael Rolnik     }
10239d316c75SMichael Rolnik 
10249d316c75SMichael Rolnik     gen_jmp_z(ctx);
10259d316c75SMichael Rolnik 
10269d316c75SMichael Rolnik     return true;
10279d316c75SMichael Rolnik }
10289d316c75SMichael Rolnik 
10299d316c75SMichael Rolnik /*
10309d316c75SMichael Rolnik  *  Indirect jump to the address pointed to by the Z (16 bits) Pointer
10319d316c75SMichael Rolnik  *  Register in the Register File and the EIND Register in the I/O space. This
10329d316c75SMichael Rolnik  *  instruction allows for indirect jumps to the entire 4M (words) Program
10339d316c75SMichael Rolnik  *  memory space. See also IJMP.  This instruction is not available in all
10349d316c75SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.
10359d316c75SMichael Rolnik  */
trans_EIJMP(DisasContext * ctx,arg_EIJMP * a)10369d316c75SMichael Rolnik static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a)
10379d316c75SMichael Rolnik {
10389d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) {
10399d316c75SMichael Rolnik         return true;
10409d316c75SMichael Rolnik     }
10419d316c75SMichael Rolnik 
10429d316c75SMichael Rolnik     gen_jmp_ez(ctx);
10439d316c75SMichael Rolnik     return true;
10449d316c75SMichael Rolnik }
10459d316c75SMichael Rolnik 
10469d316c75SMichael Rolnik /*
10479d316c75SMichael Rolnik  *  Jump to an address within the entire 4M (words) Program memory. See also
10489d316c75SMichael Rolnik  *  RJMP.  This instruction is not available in all devices. Refer to the device
10499d316c75SMichael Rolnik  *  specific instruction set summary.0
10509d316c75SMichael Rolnik  */
trans_JMP(DisasContext * ctx,arg_JMP * a)10519d316c75SMichael Rolnik static bool trans_JMP(DisasContext *ctx, arg_JMP *a)
10529d316c75SMichael Rolnik {
10539d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) {
10549d316c75SMichael Rolnik         return true;
10559d316c75SMichael Rolnik     }
10569d316c75SMichael Rolnik 
10579d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, a->imm);
10589d316c75SMichael Rolnik 
10599d316c75SMichael Rolnik     return true;
10609d316c75SMichael Rolnik }
10619d316c75SMichael Rolnik 
10629d316c75SMichael Rolnik /*
10639d316c75SMichael Rolnik  *  Relative call to an address within PC - 2K + 1 and PC + 2K (words). The
10649d316c75SMichael Rolnik  *  return address (the instruction after the RCALL) is stored onto the Stack.
10659d316c75SMichael Rolnik  *  See also CALL. For AVR microcontrollers with Program memory not exceeding 4K
10669d316c75SMichael Rolnik  *  words (8KB) this instruction can address the entire memory from every
10679d316c75SMichael Rolnik  *  address location. The Stack Pointer uses a post-decrement scheme during
10689d316c75SMichael Rolnik  *  RCALL.
10699d316c75SMichael Rolnik  */
trans_RCALL(DisasContext * ctx,arg_RCALL * a)10709d316c75SMichael Rolnik static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a)
10719d316c75SMichael Rolnik {
10729d316c75SMichael Rolnik     int ret = ctx->npc;
10739d316c75SMichael Rolnik     int dst = ctx->npc + a->imm;
10749d316c75SMichael Rolnik 
10759d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
10769d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, dst);
10779d316c75SMichael Rolnik 
10789d316c75SMichael Rolnik     return true;
10799d316c75SMichael Rolnik }
10809d316c75SMichael Rolnik 
10819d316c75SMichael Rolnik /*
10829d316c75SMichael Rolnik  *  Calls to a subroutine within the entire 4M (words) Program memory. The
10839d316c75SMichael Rolnik  *  return address (to the instruction after the CALL) will be stored onto the
10849d316c75SMichael Rolnik  *  Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme during
10859d316c75SMichael Rolnik  *  CALL.  This instruction is not available in all devices. Refer to the device
10869d316c75SMichael Rolnik  *  specific instruction set summary.
10879d316c75SMichael Rolnik  */
trans_ICALL(DisasContext * ctx,arg_ICALL * a)10889d316c75SMichael Rolnik static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a)
10899d316c75SMichael Rolnik {
10909d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) {
10919d316c75SMichael Rolnik         return true;
10929d316c75SMichael Rolnik     }
10939d316c75SMichael Rolnik 
10949d316c75SMichael Rolnik     int ret = ctx->npc;
10959d316c75SMichael Rolnik 
10969d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
10979d316c75SMichael Rolnik     gen_jmp_z(ctx);
10989d316c75SMichael Rolnik 
10999d316c75SMichael Rolnik     return true;
11009d316c75SMichael Rolnik }
11019d316c75SMichael Rolnik 
11029d316c75SMichael Rolnik /*
11039d316c75SMichael Rolnik  *  Indirect call of a subroutine pointed to by the Z (16 bits) Pointer
11049d316c75SMichael Rolnik  *  Register in the Register File and the EIND Register in the I/O space. This
11059d316c75SMichael Rolnik  *  instruction allows for indirect calls to the entire 4M (words) Program
11069d316c75SMichael Rolnik  *  memory space. See also ICALL. The Stack Pointer uses a post-decrement scheme
11079d316c75SMichael Rolnik  *  during EICALL.  This instruction is not available in all devices. Refer to
11089d316c75SMichael Rolnik  *  the device specific instruction set summary.
11099d316c75SMichael Rolnik  */
trans_EICALL(DisasContext * ctx,arg_EICALL * a)11109d316c75SMichael Rolnik static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a)
11119d316c75SMichael Rolnik {
11129d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) {
11139d316c75SMichael Rolnik         return true;
11149d316c75SMichael Rolnik     }
11159d316c75SMichael Rolnik 
11169d316c75SMichael Rolnik     int ret = ctx->npc;
11179d316c75SMichael Rolnik 
11189d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
11199d316c75SMichael Rolnik     gen_jmp_ez(ctx);
11209d316c75SMichael Rolnik     return true;
11219d316c75SMichael Rolnik }
11229d316c75SMichael Rolnik 
11239d316c75SMichael Rolnik /*
11249d316c75SMichael Rolnik  *  Calls to a subroutine within the entire Program memory. The return
11259d316c75SMichael Rolnik  *  address (to the instruction after the CALL) will be stored onto the Stack.
11269d316c75SMichael Rolnik  *  (See also RCALL). The Stack Pointer uses a post-decrement scheme during
11279d316c75SMichael Rolnik  *  CALL.  This instruction is not available in all devices. Refer to the device
11289d316c75SMichael Rolnik  *  specific instruction set summary.
11299d316c75SMichael Rolnik  */
trans_CALL(DisasContext * ctx,arg_CALL * a)11309d316c75SMichael Rolnik static bool trans_CALL(DisasContext *ctx, arg_CALL *a)
11319d316c75SMichael Rolnik {
11329d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) {
11339d316c75SMichael Rolnik         return true;
11349d316c75SMichael Rolnik     }
11359d316c75SMichael Rolnik 
11369d316c75SMichael Rolnik     int Imm = a->imm;
11379d316c75SMichael Rolnik     int ret = ctx->npc;
11389d316c75SMichael Rolnik 
11399d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
11409d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, Imm);
11419d316c75SMichael Rolnik 
11429d316c75SMichael Rolnik     return true;
11439d316c75SMichael Rolnik }
11449d316c75SMichael Rolnik 
11459d316c75SMichael Rolnik /*
11469d316c75SMichael Rolnik  *  Returns from subroutine. The return address is loaded from the STACK.
11479d316c75SMichael Rolnik  *  The Stack Pointer uses a preincrement scheme during RET.
11489d316c75SMichael Rolnik  */
trans_RET(DisasContext * ctx,arg_RET * a)11499d316c75SMichael Rolnik static bool trans_RET(DisasContext *ctx, arg_RET *a)
11509d316c75SMichael Rolnik {
11519d316c75SMichael Rolnik     gen_pop_ret(ctx, cpu_pc);
11529d316c75SMichael Rolnik 
115393d4d5e4SRichard Henderson     ctx->base.is_jmp = DISAS_LOOKUP;
11549d316c75SMichael Rolnik     return true;
11559d316c75SMichael Rolnik }
11569d316c75SMichael Rolnik 
11579d316c75SMichael Rolnik /*
11589d316c75SMichael Rolnik  *  Returns from interrupt. The return address is loaded from the STACK and
11599d316c75SMichael Rolnik  *  the Global Interrupt Flag is set.  Note that the Status Register is not
11609d316c75SMichael Rolnik  *  automatically stored when entering an interrupt routine, and it is not
11619d316c75SMichael Rolnik  *  restored when returning from an interrupt routine. This must be handled by
11629d316c75SMichael Rolnik  *  the application program. The Stack Pointer uses a pre-increment scheme
11639d316c75SMichael Rolnik  *  during RETI.
11649d316c75SMichael Rolnik  */
trans_RETI(DisasContext * ctx,arg_RETI * a)11659d316c75SMichael Rolnik static bool trans_RETI(DisasContext *ctx, arg_RETI *a)
11669d316c75SMichael Rolnik {
11679d316c75SMichael Rolnik     gen_pop_ret(ctx, cpu_pc);
11689d316c75SMichael Rolnik     tcg_gen_movi_tl(cpu_If, 1);
11699d316c75SMichael Rolnik 
11709d316c75SMichael Rolnik     /* Need to return to main loop to re-evaluate interrupts.  */
117193d4d5e4SRichard Henderson     ctx->base.is_jmp = DISAS_EXIT;
11729d316c75SMichael Rolnik     return true;
11739d316c75SMichael Rolnik }
11749d316c75SMichael Rolnik 
11759d316c75SMichael Rolnik /*
11769d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr, and
11779d316c75SMichael Rolnik  *  skips the next instruction if Rd = Rr.
11789d316c75SMichael Rolnik  */
trans_CPSE(DisasContext * ctx,arg_CPSE * a)11799d316c75SMichael Rolnik static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a)
11809d316c75SMichael Rolnik {
11819d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
11829d316c75SMichael Rolnik     ctx->skip_var0 = cpu_r[a->rd];
11839d316c75SMichael Rolnik     ctx->skip_var1 = cpu_r[a->rr];
11849d316c75SMichael Rolnik     return true;
11859d316c75SMichael Rolnik }
11869d316c75SMichael Rolnik 
11879d316c75SMichael Rolnik /*
11889d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr.
11899d316c75SMichael Rolnik  *  None of the registers are changed. All conditional branches can be used
11909d316c75SMichael Rolnik  *  after this instruction.
11919d316c75SMichael Rolnik  */
trans_CP(DisasContext * ctx,arg_CP * a)11929d316c75SMichael Rolnik static bool trans_CP(DisasContext *ctx, arg_CP *a)
11939d316c75SMichael Rolnik {
11949d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
11959d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
11969d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
11979d316c75SMichael Rolnik 
11989d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
11999d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
12009d316c75SMichael Rolnik 
12019d316c75SMichael Rolnik     /* update status register */
12029d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
12039d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
12049d316c75SMichael Rolnik     gen_ZNSf(R);
12059d316c75SMichael Rolnik     return true;
12069d316c75SMichael Rolnik }
12079d316c75SMichael Rolnik 
12089d316c75SMichael Rolnik /*
12099d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr and
12109d316c75SMichael Rolnik  *  also takes into account the previous carry. None of the registers are
12119d316c75SMichael Rolnik  *  changed. All conditional branches can be used after this instruction.
12129d316c75SMichael Rolnik  */
trans_CPC(DisasContext * ctx,arg_CPC * a)12139d316c75SMichael Rolnik static bool trans_CPC(DisasContext *ctx, arg_CPC *a)
12149d316c75SMichael Rolnik {
12159d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
12169d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
12179d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
12186d27bb55SRichard Henderson     TCGv zero = tcg_constant_i32(0);
12199d316c75SMichael Rolnik 
12209d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
12219d316c75SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
12229d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
12239d316c75SMichael Rolnik     /* update status register */
12249d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
12259d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
12269d316c75SMichael Rolnik     gen_NSf(R);
12279d316c75SMichael Rolnik 
12289d316c75SMichael Rolnik     /*
12299d316c75SMichael Rolnik      * Previous value remains unchanged when the result is zero;
12309d316c75SMichael Rolnik      * cleared otherwise.
12319d316c75SMichael Rolnik      */
12329d316c75SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
12339d316c75SMichael Rolnik     return true;
12349d316c75SMichael Rolnik }
12359d316c75SMichael Rolnik 
12369d316c75SMichael Rolnik /*
12379d316c75SMichael Rolnik  *  This instruction performs a compare between register Rd and a constant.
12389d316c75SMichael Rolnik  *  The register is not changed. All conditional branches can be used after this
12399d316c75SMichael Rolnik  *  instruction.
12409d316c75SMichael Rolnik  */
trans_CPI(DisasContext * ctx,arg_CPI * a)12419d316c75SMichael Rolnik static bool trans_CPI(DisasContext *ctx, arg_CPI *a)
12429d316c75SMichael Rolnik {
12439d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
12449d316c75SMichael Rolnik     int Imm = a->imm;
12456d27bb55SRichard Henderson     TCGv Rr = tcg_constant_i32(Imm);
12469d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
12479d316c75SMichael Rolnik 
12489d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
12499d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
12509d316c75SMichael Rolnik 
12519d316c75SMichael Rolnik     /* update status register */
12529d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
12539d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
12549d316c75SMichael Rolnik     gen_ZNSf(R);
12559d316c75SMichael Rolnik     return true;
12569d316c75SMichael Rolnik }
12579d316c75SMichael Rolnik 
12589d316c75SMichael Rolnik /*
12599d316c75SMichael Rolnik  *  This instruction tests a single bit in a register and skips the next
12609d316c75SMichael Rolnik  *  instruction if the bit is cleared.
12619d316c75SMichael Rolnik  */
trans_SBRC(DisasContext * ctx,arg_SBRC * a)12629d316c75SMichael Rolnik static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a)
12639d316c75SMichael Rolnik {
12649d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
12659d316c75SMichael Rolnik 
12669d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
12679d316c75SMichael Rolnik     ctx->skip_var0 = tcg_temp_new();
12689d316c75SMichael Rolnik 
12699d316c75SMichael Rolnik     tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
12709d316c75SMichael Rolnik     return true;
12719d316c75SMichael Rolnik }
12729d316c75SMichael Rolnik 
12739d316c75SMichael Rolnik /*
12749d316c75SMichael Rolnik  *  This instruction tests a single bit in a register and skips the next
12759d316c75SMichael Rolnik  *  instruction if the bit is set.
12769d316c75SMichael Rolnik  */
trans_SBRS(DisasContext * ctx,arg_SBRS * a)12779d316c75SMichael Rolnik static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a)
12789d316c75SMichael Rolnik {
12799d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
12809d316c75SMichael Rolnik 
12819d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_NE;
12829d316c75SMichael Rolnik     ctx->skip_var0 = tcg_temp_new();
12839d316c75SMichael Rolnik 
12849d316c75SMichael Rolnik     tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
12859d316c75SMichael Rolnik     return true;
12869d316c75SMichael Rolnik }
12879d316c75SMichael Rolnik 
12889d316c75SMichael Rolnik /*
12899d316c75SMichael Rolnik  *  This instruction tests a single bit in an I/O Register and skips the
12909d316c75SMichael Rolnik  *  next instruction if the bit is cleared. This instruction operates on the
12919d316c75SMichael Rolnik  *  lower 32 I/O Registers -- addresses 0-31.
12929d316c75SMichael Rolnik  */
trans_SBIC(DisasContext * ctx,arg_SBIC * a)12939d316c75SMichael Rolnik static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a)
12949d316c75SMichael Rolnik {
1295353c18dcSRichard Henderson     TCGv data = tcg_temp_new_i32();
1296353c18dcSRichard Henderson     TCGv port = tcg_constant_i32(a->reg);
12979d316c75SMichael Rolnik 
1298ad75a51eSRichard Henderson     gen_helper_inb(data, tcg_env, port);
1299353c18dcSRichard Henderson     tcg_gen_andi_tl(data, data, 1 << a->bit);
13009d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
1301353c18dcSRichard Henderson     ctx->skip_var0 = data;
13029d316c75SMichael Rolnik 
13039d316c75SMichael Rolnik     return true;
13049d316c75SMichael Rolnik }
13059d316c75SMichael Rolnik 
13069d316c75SMichael Rolnik /*
13079d316c75SMichael Rolnik  *  This instruction tests a single bit in an I/O Register and skips the
13089d316c75SMichael Rolnik  *  next instruction if the bit is set. This instruction operates on the lower
13099d316c75SMichael Rolnik  *  32 I/O Registers -- addresses 0-31.
13109d316c75SMichael Rolnik  */
trans_SBIS(DisasContext * ctx,arg_SBIS * a)13119d316c75SMichael Rolnik static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a)
13129d316c75SMichael Rolnik {
1313353c18dcSRichard Henderson     TCGv data = tcg_temp_new_i32();
1314353c18dcSRichard Henderson     TCGv port = tcg_constant_i32(a->reg);
13159d316c75SMichael Rolnik 
1316ad75a51eSRichard Henderson     gen_helper_inb(data, tcg_env, port);
1317353c18dcSRichard Henderson     tcg_gen_andi_tl(data, data, 1 << a->bit);
13189d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_NE;
1319353c18dcSRichard Henderson     ctx->skip_var0 = data;
13209d316c75SMichael Rolnik 
13219d316c75SMichael Rolnik     return true;
13229d316c75SMichael Rolnik }
13239d316c75SMichael Rolnik 
13249d316c75SMichael Rolnik /*
13259d316c75SMichael Rolnik  *  Conditional relative branch. Tests a single bit in SREG and branches
13269d316c75SMichael Rolnik  *  relatively to PC if the bit is cleared. This instruction branches relatively
13279d316c75SMichael Rolnik  *  to PC in either direction (PC - 63 < = destination <= PC + 64). The
13289d316c75SMichael Rolnik  *  parameter k is the offset from PC and is represented in two's complement
13299d316c75SMichael Rolnik  *  form.
13309d316c75SMichael Rolnik  */
trans_BRBC(DisasContext * ctx,arg_BRBC * a)13319d316c75SMichael Rolnik static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a)
13329d316c75SMichael Rolnik {
13339d316c75SMichael Rolnik     TCGLabel *not_taken = gen_new_label();
13349d316c75SMichael Rolnik 
13359d316c75SMichael Rolnik     TCGv var;
13369d316c75SMichael Rolnik 
13379d316c75SMichael Rolnik     switch (a->bit) {
13389d316c75SMichael Rolnik     case 0x00:
13399d316c75SMichael Rolnik         var = cpu_Cf;
13409d316c75SMichael Rolnik         break;
13419d316c75SMichael Rolnik     case 0x01:
13429d316c75SMichael Rolnik         var = cpu_Zf;
13439d316c75SMichael Rolnik         break;
13449d316c75SMichael Rolnik     case 0x02:
13459d316c75SMichael Rolnik         var = cpu_Nf;
13469d316c75SMichael Rolnik         break;
13479d316c75SMichael Rolnik     case 0x03:
13489d316c75SMichael Rolnik         var = cpu_Vf;
13499d316c75SMichael Rolnik         break;
13509d316c75SMichael Rolnik     case 0x04:
13519d316c75SMichael Rolnik         var = cpu_Sf;
13529d316c75SMichael Rolnik         break;
13539d316c75SMichael Rolnik     case 0x05:
13549d316c75SMichael Rolnik         var = cpu_Hf;
13559d316c75SMichael Rolnik         break;
13569d316c75SMichael Rolnik     case 0x06:
13579d316c75SMichael Rolnik         var = cpu_Tf;
13589d316c75SMichael Rolnik         break;
13599d316c75SMichael Rolnik     case 0x07:
13609d316c75SMichael Rolnik         var = cpu_If;
13619d316c75SMichael Rolnik         break;
13629d316c75SMichael Rolnik     default:
13639d316c75SMichael Rolnik         g_assert_not_reached();
13649d316c75SMichael Rolnik     }
13659d316c75SMichael Rolnik 
13669d316c75SMichael Rolnik     tcg_gen_brcondi_i32(TCG_COND_NE, var, 0, not_taken);
13679d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, ctx->npc + a->imm);
13689d316c75SMichael Rolnik     gen_set_label(not_taken);
13699d316c75SMichael Rolnik 
137093d4d5e4SRichard Henderson     ctx->base.is_jmp = DISAS_CHAIN;
13719d316c75SMichael Rolnik     return true;
13729d316c75SMichael Rolnik }
13739d316c75SMichael Rolnik 
13749d316c75SMichael Rolnik /*
13759d316c75SMichael Rolnik  *  Conditional relative branch. Tests a single bit in SREG and branches
13769d316c75SMichael Rolnik  *  relatively to PC if the bit is set. This instruction branches relatively to
13779d316c75SMichael Rolnik  *  PC in either direction (PC - 63 < = destination <= PC + 64). The parameter k
13789d316c75SMichael Rolnik  *  is the offset from PC and is represented in two's complement form.
13799d316c75SMichael Rolnik  */
trans_BRBS(DisasContext * ctx,arg_BRBS * a)13809d316c75SMichael Rolnik static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a)
13819d316c75SMichael Rolnik {
13829d316c75SMichael Rolnik     TCGLabel *not_taken = gen_new_label();
13839d316c75SMichael Rolnik 
13849d316c75SMichael Rolnik     TCGv var;
13859d316c75SMichael Rolnik 
13869d316c75SMichael Rolnik     switch (a->bit) {
13879d316c75SMichael Rolnik     case 0x00:
13889d316c75SMichael Rolnik         var = cpu_Cf;
13899d316c75SMichael Rolnik         break;
13909d316c75SMichael Rolnik     case 0x01:
13919d316c75SMichael Rolnik         var = cpu_Zf;
13929d316c75SMichael Rolnik         break;
13939d316c75SMichael Rolnik     case 0x02:
13949d316c75SMichael Rolnik         var = cpu_Nf;
13959d316c75SMichael Rolnik         break;
13969d316c75SMichael Rolnik     case 0x03:
13979d316c75SMichael Rolnik         var = cpu_Vf;
13989d316c75SMichael Rolnik         break;
13999d316c75SMichael Rolnik     case 0x04:
14009d316c75SMichael Rolnik         var = cpu_Sf;
14019d316c75SMichael Rolnik         break;
14029d316c75SMichael Rolnik     case 0x05:
14039d316c75SMichael Rolnik         var = cpu_Hf;
14049d316c75SMichael Rolnik         break;
14059d316c75SMichael Rolnik     case 0x06:
14069d316c75SMichael Rolnik         var = cpu_Tf;
14079d316c75SMichael Rolnik         break;
14089d316c75SMichael Rolnik     case 0x07:
14099d316c75SMichael Rolnik         var = cpu_If;
14109d316c75SMichael Rolnik         break;
14119d316c75SMichael Rolnik     default:
14129d316c75SMichael Rolnik         g_assert_not_reached();
14139d316c75SMichael Rolnik     }
14149d316c75SMichael Rolnik 
14159d316c75SMichael Rolnik     tcg_gen_brcondi_i32(TCG_COND_EQ, var, 0, not_taken);
14169d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, ctx->npc + a->imm);
14179d316c75SMichael Rolnik     gen_set_label(not_taken);
14189d316c75SMichael Rolnik 
141993d4d5e4SRichard Henderson     ctx->base.is_jmp = DISAS_CHAIN;
14209d316c75SMichael Rolnik     return true;
14219d316c75SMichael Rolnik }
14229732b024SMichael Rolnik 
14239732b024SMichael Rolnik /*
14249732b024SMichael Rolnik  * Data Transfer Instructions
14259732b024SMichael Rolnik  */
14269732b024SMichael Rolnik 
14279732b024SMichael Rolnik /*
14289732b024SMichael Rolnik  *  in the gen_set_addr & gen_get_addr functions
14299732b024SMichael Rolnik  *  H assumed to be in 0x00ff0000 format
14309732b024SMichael Rolnik  *  M assumed to be in 0x000000ff format
14319732b024SMichael Rolnik  *  L assumed to be in 0x000000ff format
14329732b024SMichael Rolnik  */
gen_set_addr(TCGv addr,TCGv H,TCGv M,TCGv L)14339732b024SMichael Rolnik static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L)
14349732b024SMichael Rolnik {
14359732b024SMichael Rolnik 
14369732b024SMichael Rolnik     tcg_gen_andi_tl(L, addr, 0x000000ff);
14379732b024SMichael Rolnik 
14389732b024SMichael Rolnik     tcg_gen_andi_tl(M, addr, 0x0000ff00);
14399732b024SMichael Rolnik     tcg_gen_shri_tl(M, M, 8);
14409732b024SMichael Rolnik 
14419732b024SMichael Rolnik     tcg_gen_andi_tl(H, addr, 0x00ff0000);
14429732b024SMichael Rolnik }
14439732b024SMichael Rolnik 
gen_set_xaddr(TCGv addr)14449732b024SMichael Rolnik static void gen_set_xaddr(TCGv addr)
14459732b024SMichael Rolnik {
14469732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]);
14479732b024SMichael Rolnik }
14489732b024SMichael Rolnik 
gen_set_yaddr(TCGv addr)14499732b024SMichael Rolnik static void gen_set_yaddr(TCGv addr)
14509732b024SMichael Rolnik {
14519732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]);
14529732b024SMichael Rolnik }
14539732b024SMichael Rolnik 
gen_set_zaddr(TCGv addr)14549732b024SMichael Rolnik static void gen_set_zaddr(TCGv addr)
14559732b024SMichael Rolnik {
14569732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]);
14579732b024SMichael Rolnik }
14589732b024SMichael Rolnik 
gen_get_addr(TCGv H,TCGv M,TCGv L)14599732b024SMichael Rolnik static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L)
14609732b024SMichael Rolnik {
14619732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
14629732b024SMichael Rolnik 
14639732b024SMichael Rolnik     tcg_gen_deposit_tl(addr, M, H, 8, 8);
14649732b024SMichael Rolnik     tcg_gen_deposit_tl(addr, L, addr, 8, 16);
14659732b024SMichael Rolnik 
14669732b024SMichael Rolnik     return addr;
14679732b024SMichael Rolnik }
14689732b024SMichael Rolnik 
gen_get_xaddr(void)14699732b024SMichael Rolnik static TCGv gen_get_xaddr(void)
14709732b024SMichael Rolnik {
14719732b024SMichael Rolnik     return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]);
14729732b024SMichael Rolnik }
14739732b024SMichael Rolnik 
gen_get_yaddr(void)14749732b024SMichael Rolnik static TCGv gen_get_yaddr(void)
14759732b024SMichael Rolnik {
14769732b024SMichael Rolnik     return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]);
14779732b024SMichael Rolnik }
14789732b024SMichael Rolnik 
gen_get_zaddr(void)14799732b024SMichael Rolnik static TCGv gen_get_zaddr(void)
14809732b024SMichael Rolnik {
14819732b024SMichael Rolnik     return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]);
14829732b024SMichael Rolnik }
14839732b024SMichael Rolnik 
14849732b024SMichael Rolnik /*
14859732b024SMichael Rolnik  *  Load one byte indirect from data space to register and stores an clear
14869732b024SMichael Rolnik  *  the bits in data space specified by the register. The instruction can only
14879732b024SMichael Rolnik  *  be used towards internal SRAM.  The data location is pointed to by the Z (16
14889732b024SMichael Rolnik  *  bits) Pointer Register in the Register File. Memory access is limited to the
14899732b024SMichael Rolnik  *  current data segment of 64KB. To access another data segment in devices with
14909732b024SMichael Rolnik  *  more than 64KB data space, the RAMPZ in register in the I/O area has to be
14919732b024SMichael Rolnik  *  changed.  The Z-pointer Register is left unchanged by the operation. This
14929732b024SMichael Rolnik  *  instruction is especially suited for clearing status bits stored in SRAM.
14939732b024SMichael Rolnik  */
gen_data_store(DisasContext * ctx,TCGv data,TCGv addr)14949732b024SMichael Rolnik static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr)
14959732b024SMichael Rolnik {
149693d4d5e4SRichard Henderson     if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) {
1497ad75a51eSRichard Henderson         gen_helper_fullwr(tcg_env, data, addr);
14989732b024SMichael Rolnik     } else {
14998b4506e5SRichard Henderson         tcg_gen_qemu_st_tl(data, addr, MMU_DATA_IDX, MO_UB);
15009732b024SMichael Rolnik     }
15019732b024SMichael Rolnik }
15029732b024SMichael Rolnik 
gen_data_load(DisasContext * ctx,TCGv data,TCGv addr)15039732b024SMichael Rolnik static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr)
15049732b024SMichael Rolnik {
150593d4d5e4SRichard Henderson     if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) {
1506ad75a51eSRichard Henderson         gen_helper_fullrd(data, tcg_env, addr);
15079732b024SMichael Rolnik     } else {
15088b4506e5SRichard Henderson         tcg_gen_qemu_ld_tl(data, addr, MMU_DATA_IDX, MO_UB);
15099732b024SMichael Rolnik     }
15109732b024SMichael Rolnik }
15119732b024SMichael Rolnik 
15129732b024SMichael Rolnik /*
15139732b024SMichael Rolnik  *  This instruction makes a copy of one register into another. The source
15149732b024SMichael Rolnik  *  register Rr is left unchanged, while the destination register Rd is loaded
15159732b024SMichael Rolnik  *  with a copy of Rr.
15169732b024SMichael Rolnik  */
trans_MOV(DisasContext * ctx,arg_MOV * a)15179732b024SMichael Rolnik static bool trans_MOV(DisasContext *ctx, arg_MOV *a)
15189732b024SMichael Rolnik {
15199732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
15209732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
15219732b024SMichael Rolnik 
15229732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, Rr);
15239732b024SMichael Rolnik 
15249732b024SMichael Rolnik     return true;
15259732b024SMichael Rolnik }
15269732b024SMichael Rolnik 
15279732b024SMichael Rolnik /*
15289732b024SMichael Rolnik  *  This instruction makes a copy of one register pair into another register
15299732b024SMichael Rolnik  *  pair. The source register pair Rr+1:Rr is left unchanged, while the
15309732b024SMichael Rolnik  *  destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr.  This
15319732b024SMichael Rolnik  *  instruction is not available in all devices. Refer to the device specific
15329732b024SMichael Rolnik  *  instruction set summary.
15339732b024SMichael Rolnik  */
trans_MOVW(DisasContext * ctx,arg_MOVW * a)15349732b024SMichael Rolnik static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a)
15359732b024SMichael Rolnik {
15369732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MOVW)) {
15379732b024SMichael Rolnik         return true;
15389732b024SMichael Rolnik     }
15399732b024SMichael Rolnik 
15409732b024SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
15419732b024SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
15429732b024SMichael Rolnik     TCGv RrL = cpu_r[a->rr];
15439732b024SMichael Rolnik     TCGv RrH = cpu_r[a->rr + 1];
15449732b024SMichael Rolnik 
15459732b024SMichael Rolnik     tcg_gen_mov_tl(RdH, RrH);
15469732b024SMichael Rolnik     tcg_gen_mov_tl(RdL, RrL);
15479732b024SMichael Rolnik 
15489732b024SMichael Rolnik     return true;
15499732b024SMichael Rolnik }
15509732b024SMichael Rolnik 
15519732b024SMichael Rolnik /*
15529732b024SMichael Rolnik  * Loads an 8 bit constant directly to register 16 to 31.
15539732b024SMichael Rolnik  */
trans_LDI(DisasContext * ctx,arg_LDI * a)15549732b024SMichael Rolnik static bool trans_LDI(DisasContext *ctx, arg_LDI *a)
15559732b024SMichael Rolnik {
15569732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
15579732b024SMichael Rolnik     int imm = a->imm;
15589732b024SMichael Rolnik 
15599732b024SMichael Rolnik     tcg_gen_movi_tl(Rd, imm);
15609732b024SMichael Rolnik 
15619732b024SMichael Rolnik     return true;
15629732b024SMichael Rolnik }
15639732b024SMichael Rolnik 
15649732b024SMichael Rolnik /*
15659732b024SMichael Rolnik  *  Loads one byte from the data space to a register. For parts with SRAM,
15669732b024SMichael Rolnik  *  the data space consists of the Register File, I/O memory and internal SRAM
15679732b024SMichael Rolnik  *  (and external SRAM if applicable). For parts without SRAM, the data space
15689732b024SMichael Rolnik  *  consists of the register file only. The EEPROM has a separate address space.
15699732b024SMichael Rolnik  *  A 16-bit address must be supplied. Memory access is limited to the current
15709732b024SMichael Rolnik  *  data segment of 64KB. The LDS instruction uses the RAMPD Register to access
15719732b024SMichael Rolnik  *  memory above 64KB. To access another data segment in devices with more than
15729732b024SMichael Rolnik  *  64KB data space, the RAMPD in register in the I/O area has to be changed.
15739732b024SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
15749732b024SMichael Rolnik  *  specific instruction set summary.
15759732b024SMichael Rolnik  */
trans_LDS(DisasContext * ctx,arg_LDS * a)15769732b024SMichael Rolnik static bool trans_LDS(DisasContext *ctx, arg_LDS *a)
15779732b024SMichael Rolnik {
15789732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
15799732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
15809732b024SMichael Rolnik     TCGv H = cpu_rampD;
15819732b024SMichael Rolnik     a->imm = next_word(ctx);
15829732b024SMichael Rolnik 
15839732b024SMichael Rolnik     tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
15849732b024SMichael Rolnik     tcg_gen_shli_tl(addr, addr, 16);
15859732b024SMichael Rolnik     tcg_gen_ori_tl(addr, addr, a->imm);
15869732b024SMichael Rolnik 
15879732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
15889732b024SMichael Rolnik     return true;
15899732b024SMichael Rolnik }
15909732b024SMichael Rolnik 
15919732b024SMichael Rolnik /*
15929732b024SMichael Rolnik  *  Loads one byte indirect from the data space to a register. For parts
15939732b024SMichael Rolnik  *  with SRAM, the data space consists of the Register File, I/O memory and
15949732b024SMichael Rolnik  *  internal SRAM (and external SRAM if applicable). For parts without SRAM, the
15959732b024SMichael Rolnik  *  data space consists of the Register File only. In some parts the Flash
15969732b024SMichael Rolnik  *  Memory has been mapped to the data space and can be read using this command.
15979732b024SMichael Rolnik  *  The EEPROM has a separate address space.  The data location is pointed to by
15989732b024SMichael Rolnik  *  the X (16 bits) Pointer Register in the Register File. Memory access is
15999732b024SMichael Rolnik  *  limited to the current data segment of 64KB. To access another data segment
16009732b024SMichael Rolnik  *  in devices with more than 64KB data space, the RAMPX in register in the I/O
16019732b024SMichael Rolnik  *  area has to be changed.  The X-pointer Register can either be left unchanged
16029732b024SMichael Rolnik  *  by the operation, or it can be post-incremented or predecremented.  These
16039732b024SMichael Rolnik  *  features are especially suited for accessing arrays, tables, and Stack
16049732b024SMichael Rolnik  *  Pointer usage of the X-pointer Register. Note that only the low byte of the
16059732b024SMichael Rolnik  *  X-pointer is updated in devices with no more than 256 bytes data space. For
16069732b024SMichael Rolnik  *  such devices, the high byte of the pointer is not used by this instruction
16079732b024SMichael Rolnik  *  and can be used for other purposes. The RAMPX Register in the I/O area is
16089732b024SMichael Rolnik  *  updated in parts with more than 64KB data space or more than 64KB Program
16099732b024SMichael Rolnik  *  memory, and the increment/decrement is added to the entire 24-bit address on
16109732b024SMichael Rolnik  *  such devices.  Not all variants of this instruction is available in all
16119732b024SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.  In the
16129732b024SMichael Rolnik  *  Reduced Core tinyAVR the LD instruction can be used to achieve the same
16139732b024SMichael Rolnik  *  operation as LPM since the program memory is mapped to the data memory
16149732b024SMichael Rolnik  *  space.
16159732b024SMichael Rolnik  */
trans_LDX1(DisasContext * ctx,arg_LDX1 * a)16169732b024SMichael Rolnik static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a)
16179732b024SMichael Rolnik {
16189732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16199732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
16209732b024SMichael Rolnik 
16219732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
16229732b024SMichael Rolnik     return true;
16239732b024SMichael Rolnik }
16249732b024SMichael Rolnik 
trans_LDX2(DisasContext * ctx,arg_LDX2 * a)16259732b024SMichael Rolnik static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a)
16269732b024SMichael Rolnik {
16279732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16289732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
16299732b024SMichael Rolnik 
16309732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
16319732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
16329732b024SMichael Rolnik 
16339732b024SMichael Rolnik     gen_set_xaddr(addr);
16349732b024SMichael Rolnik     return true;
16359732b024SMichael Rolnik }
16369732b024SMichael Rolnik 
trans_LDX3(DisasContext * ctx,arg_LDX3 * a)16379732b024SMichael Rolnik static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a)
16389732b024SMichael Rolnik {
16399732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16409732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
16419732b024SMichael Rolnik 
16429732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
16439732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
16449732b024SMichael Rolnik     gen_set_xaddr(addr);
16459732b024SMichael Rolnik     return true;
16469732b024SMichael Rolnik }
16479732b024SMichael Rolnik 
16489732b024SMichael Rolnik /*
16499732b024SMichael Rolnik  *  Loads one byte indirect with or without displacement from the data space
16509732b024SMichael Rolnik  *  to a register. For parts with SRAM, the data space consists of the Register
16519732b024SMichael Rolnik  *  File, I/O memory and internal SRAM (and external SRAM if applicable). For
16529732b024SMichael Rolnik  *  parts without SRAM, the data space consists of the Register File only. In
16539732b024SMichael Rolnik  *  some parts the Flash Memory has been mapped to the data space and can be
16549732b024SMichael Rolnik  *  read using this command. The EEPROM has a separate address space.  The data
16559732b024SMichael Rolnik  *  location is pointed to by the Y (16 bits) Pointer Register in the Register
16569732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
16579732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
16589732b024SMichael Rolnik  *  RAMPY in register in the I/O area has to be changed.  The Y-pointer Register
16599732b024SMichael Rolnik  *  can either be left unchanged by the operation, or it can be post-incremented
16609732b024SMichael Rolnik  *  or predecremented.  These features are especially suited for accessing
16619732b024SMichael Rolnik  *  arrays, tables, and Stack Pointer usage of the Y-pointer Register. Note that
16629732b024SMichael Rolnik  *  only the low byte of the Y-pointer is updated in devices with no more than
16639732b024SMichael Rolnik  *  256 bytes data space. For such devices, the high byte of the pointer is not
16649732b024SMichael Rolnik  *  used by this instruction and can be used for other purposes. The RAMPY
16659732b024SMichael Rolnik  *  Register in the I/O area is updated in parts with more than 64KB data space
16669732b024SMichael Rolnik  *  or more than 64KB Program memory, and the increment/decrement/displacement
16679732b024SMichael Rolnik  *  is added to the entire 24-bit address on such devices.  Not all variants of
16689732b024SMichael Rolnik  *  this instruction is available in all devices. Refer to the device specific
16699732b024SMichael Rolnik  *  instruction set summary.  In the Reduced Core tinyAVR the LD instruction can
16709732b024SMichael Rolnik  *  be used to achieve the same operation as LPM since the program memory is
16719732b024SMichael Rolnik  *  mapped to the data memory space.
16729732b024SMichael Rolnik  */
trans_LDY2(DisasContext * ctx,arg_LDY2 * a)16739732b024SMichael Rolnik static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a)
16749732b024SMichael Rolnik {
16759732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16769732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
16779732b024SMichael Rolnik 
16789732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
16799732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
16809732b024SMichael Rolnik 
16819732b024SMichael Rolnik     gen_set_yaddr(addr);
16829732b024SMichael Rolnik     return true;
16839732b024SMichael Rolnik }
16849732b024SMichael Rolnik 
trans_LDY3(DisasContext * ctx,arg_LDY3 * a)16859732b024SMichael Rolnik static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a)
16869732b024SMichael Rolnik {
16879732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16889732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
16899732b024SMichael Rolnik 
16909732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
16919732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
16929732b024SMichael Rolnik     gen_set_yaddr(addr);
16939732b024SMichael Rolnik     return true;
16949732b024SMichael Rolnik }
16959732b024SMichael Rolnik 
trans_LDDY(DisasContext * ctx,arg_LDDY * a)16969732b024SMichael Rolnik static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a)
16979732b024SMichael Rolnik {
16989732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16999732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
17009732b024SMichael Rolnik 
17019732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
17029732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17039732b024SMichael Rolnik     return true;
17049732b024SMichael Rolnik }
17059732b024SMichael Rolnik 
17069732b024SMichael Rolnik /*
17079732b024SMichael Rolnik  *  Loads one byte indirect with or without displacement from the data space
17089732b024SMichael Rolnik  *  to a register. For parts with SRAM, the data space consists of the Register
17099732b024SMichael Rolnik  *  File, I/O memory and internal SRAM (and external SRAM if applicable). For
17109732b024SMichael Rolnik  *  parts without SRAM, the data space consists of the Register File only. In
17119732b024SMichael Rolnik  *  some parts the Flash Memory has been mapped to the data space and can be
17129732b024SMichael Rolnik  *  read using this command. The EEPROM has a separate address space.  The data
17139732b024SMichael Rolnik  *  location is pointed to by the Z (16 bits) Pointer Register in the Register
17149732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
17159732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
17169732b024SMichael Rolnik  *  RAMPZ in register in the I/O area has to be changed.  The Z-pointer Register
17179732b024SMichael Rolnik  *  can either be left unchanged by the operation, or it can be post-incremented
17189732b024SMichael Rolnik  *  or predecremented.  These features are especially suited for Stack Pointer
17199732b024SMichael Rolnik  *  usage of the Z-pointer Register, however because the Z-pointer Register can
17209732b024SMichael Rolnik  *  be used for indirect subroutine calls, indirect jumps and table lookup, it
17219732b024SMichael Rolnik  *  is often more convenient to use the X or Y-pointer as a dedicated Stack
17229732b024SMichael Rolnik  *  Pointer. Note that only the low byte of the Z-pointer is updated in devices
17239732b024SMichael Rolnik  *  with no more than 256 bytes data space. For such devices, the high byte of
17249732b024SMichael Rolnik  *  the pointer is not used by this instruction and can be used for other
17259732b024SMichael Rolnik  *  purposes. The RAMPZ Register in the I/O area is updated in parts with more
17269732b024SMichael Rolnik  *  than 64KB data space or more than 64KB Program memory, and the
17279732b024SMichael Rolnik  *  increment/decrement/displacement is added to the entire 24-bit address on
17289732b024SMichael Rolnik  *  such devices.  Not all variants of this instruction is available in all
17299732b024SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.  In the
17309732b024SMichael Rolnik  *  Reduced Core tinyAVR the LD instruction can be used to achieve the same
17319732b024SMichael Rolnik  *  operation as LPM since the program memory is mapped to the data memory
17329732b024SMichael Rolnik  *  space.  For using the Z-pointer for table lookup in Program memory see the
17339732b024SMichael Rolnik  *  LPM and ELPM instructions.
17349732b024SMichael Rolnik  */
trans_LDZ2(DisasContext * ctx,arg_LDZ2 * a)17359732b024SMichael Rolnik static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a)
17369732b024SMichael Rolnik {
17379732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17389732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
17399732b024SMichael Rolnik 
17409732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17419732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
17429732b024SMichael Rolnik 
17439732b024SMichael Rolnik     gen_set_zaddr(addr);
17449732b024SMichael Rolnik     return true;
17459732b024SMichael Rolnik }
17469732b024SMichael Rolnik 
trans_LDZ3(DisasContext * ctx,arg_LDZ3 * a)17479732b024SMichael Rolnik static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a)
17489732b024SMichael Rolnik {
17499732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17509732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
17519732b024SMichael Rolnik 
17529732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
17539732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17549732b024SMichael Rolnik 
17559732b024SMichael Rolnik     gen_set_zaddr(addr);
17569732b024SMichael Rolnik     return true;
17579732b024SMichael Rolnik }
17589732b024SMichael Rolnik 
trans_LDDZ(DisasContext * ctx,arg_LDDZ * a)17599732b024SMichael Rolnik static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a)
17609732b024SMichael Rolnik {
17619732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17629732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
17639732b024SMichael Rolnik 
17649732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
17659732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17669732b024SMichael Rolnik     return true;
17679732b024SMichael Rolnik }
17689732b024SMichael Rolnik 
17699732b024SMichael Rolnik /*
17709732b024SMichael Rolnik  *  Stores one byte from a Register to the data space. For parts with SRAM,
17719732b024SMichael Rolnik  *  the data space consists of the Register File, I/O memory and internal SRAM
17729732b024SMichael Rolnik  *  (and external SRAM if applicable). For parts without SRAM, the data space
17739732b024SMichael Rolnik  *  consists of the Register File only. The EEPROM has a separate address space.
17749732b024SMichael Rolnik  *  A 16-bit address must be supplied. Memory access is limited to the current
17759732b024SMichael Rolnik  *  data segment of 64KB. The STS instruction uses the RAMPD Register to access
17769732b024SMichael Rolnik  *  memory above 64KB. To access another data segment in devices with more than
17779732b024SMichael Rolnik  *  64KB data space, the RAMPD in register in the I/O area has to be changed.
17789732b024SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
17799732b024SMichael Rolnik  *  specific instruction set summary.
17809732b024SMichael Rolnik  */
trans_STS(DisasContext * ctx,arg_STS * a)17819732b024SMichael Rolnik static bool trans_STS(DisasContext *ctx, arg_STS *a)
17829732b024SMichael Rolnik {
17839732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17849732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
17859732b024SMichael Rolnik     TCGv H = cpu_rampD;
17869732b024SMichael Rolnik     a->imm = next_word(ctx);
17879732b024SMichael Rolnik 
17889732b024SMichael Rolnik     tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
17899732b024SMichael Rolnik     tcg_gen_shli_tl(addr, addr, 16);
17909732b024SMichael Rolnik     tcg_gen_ori_tl(addr, addr, a->imm);
17919732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
17929732b024SMichael Rolnik     return true;
17939732b024SMichael Rolnik }
17949732b024SMichael Rolnik 
17959732b024SMichael Rolnik /*
17969732b024SMichael Rolnik  * Stores one byte indirect from a register to data space. For parts with SRAM,
17979732b024SMichael Rolnik  * the data space consists of the Register File, I/O memory, and internal SRAM
17989732b024SMichael Rolnik  * (and external SRAM if applicable). For parts without SRAM, the data space
17999732b024SMichael Rolnik  * consists of the Register File only. The EEPROM has a separate address space.
18009732b024SMichael Rolnik  *
18019732b024SMichael Rolnik  * The data location is pointed to by the X (16 bits) Pointer Register in the
18029732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
18039732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
18049732b024SMichael Rolnik  * RAMPX in register in the I/O area has to be changed.
18059732b024SMichael Rolnik  *
18069732b024SMichael Rolnik  * The X-pointer Register can either be left unchanged by the operation, or it
18079732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
18089732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the
18099732b024SMichael Rolnik  * X-pointer Register. Note that only the low byte of the X-pointer is updated
18109732b024SMichael Rolnik  * in devices with no more than 256 bytes data space. For such devices, the high
18119732b024SMichael Rolnik  * byte of the pointer is not used by this instruction and can be used for other
18129732b024SMichael Rolnik  * purposes. The RAMPX Register in the I/O area is updated in parts with more
18139732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
18149732b024SMichael Rolnik  * decrement is added to the entire 24-bit address on such devices.
18159732b024SMichael Rolnik  */
trans_STX1(DisasContext * ctx,arg_STX1 * a)18169732b024SMichael Rolnik static bool trans_STX1(DisasContext *ctx, arg_STX1 *a)
18179732b024SMichael Rolnik {
18189732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
18199732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
18209732b024SMichael Rolnik 
18219732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
18229732b024SMichael Rolnik     return true;
18239732b024SMichael Rolnik }
18249732b024SMichael Rolnik 
trans_STX2(DisasContext * ctx,arg_STX2 * a)18259732b024SMichael Rolnik static bool trans_STX2(DisasContext *ctx, arg_STX2 *a)
18269732b024SMichael Rolnik {
18279732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
18289732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
18299732b024SMichael Rolnik 
18309732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
18319732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
18329732b024SMichael Rolnik     gen_set_xaddr(addr);
18339732b024SMichael Rolnik     return true;
18349732b024SMichael Rolnik }
18359732b024SMichael Rolnik 
trans_STX3(DisasContext * ctx,arg_STX3 * a)18369732b024SMichael Rolnik static bool trans_STX3(DisasContext *ctx, arg_STX3 *a)
18379732b024SMichael Rolnik {
18389732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
18399732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
18409732b024SMichael Rolnik 
18419732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
18429732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
18439732b024SMichael Rolnik     gen_set_xaddr(addr);
18449732b024SMichael Rolnik     return true;
18459732b024SMichael Rolnik }
18469732b024SMichael Rolnik 
18479732b024SMichael Rolnik /*
18489732b024SMichael Rolnik  * Stores one byte indirect with or without displacement from a register to data
18499732b024SMichael Rolnik  * space. For parts with SRAM, the data space consists of the Register File, I/O
18509732b024SMichael Rolnik  * memory, and internal SRAM (and external SRAM if applicable). For parts
18519732b024SMichael Rolnik  * without SRAM, the data space consists of the Register File only. The EEPROM
18529732b024SMichael Rolnik  * has a separate address space.
18539732b024SMichael Rolnik  *
18549732b024SMichael Rolnik  * The data location is pointed to by the Y (16 bits) Pointer Register in the
18559732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
18569732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
18579732b024SMichael Rolnik  * RAMPY in register in the I/O area has to be changed.
18589732b024SMichael Rolnik  *
18599732b024SMichael Rolnik  * The Y-pointer Register can either be left unchanged by the operation, or it
18609732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
18619732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer
18629732b024SMichael Rolnik  * Register. Note that only the low byte of the Y-pointer is updated in devices
18639732b024SMichael Rolnik  * with no more than 256 bytes data space. For such devices, the high byte of
18649732b024SMichael Rolnik  * the pointer is not used by this instruction and can be used for other
18659732b024SMichael Rolnik  * purposes. The RAMPY Register in the I/O area is updated in parts with more
18669732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
18679732b024SMichael Rolnik  * decrement / displacement is added to the entire 24-bit address on such
18689732b024SMichael Rolnik  * devices.
18699732b024SMichael Rolnik  */
trans_STY2(DisasContext * ctx,arg_STY2 * a)18709732b024SMichael Rolnik static bool trans_STY2(DisasContext *ctx, arg_STY2 *a)
18719732b024SMichael Rolnik {
18729732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18739732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
18749732b024SMichael Rolnik 
18759732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
18769732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
18779732b024SMichael Rolnik     gen_set_yaddr(addr);
18789732b024SMichael Rolnik     return true;
18799732b024SMichael Rolnik }
18809732b024SMichael Rolnik 
trans_STY3(DisasContext * ctx,arg_STY3 * a)18819732b024SMichael Rolnik static bool trans_STY3(DisasContext *ctx, arg_STY3 *a)
18829732b024SMichael Rolnik {
18839732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18849732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
18859732b024SMichael Rolnik 
18869732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
18879732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
18889732b024SMichael Rolnik     gen_set_yaddr(addr);
18899732b024SMichael Rolnik     return true;
18909732b024SMichael Rolnik }
18919732b024SMichael Rolnik 
trans_STDY(DisasContext * ctx,arg_STDY * a)18929732b024SMichael Rolnik static bool trans_STDY(DisasContext *ctx, arg_STDY *a)
18939732b024SMichael Rolnik {
18949732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18959732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
18969732b024SMichael Rolnik 
18979732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
18989732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
18999732b024SMichael Rolnik     return true;
19009732b024SMichael Rolnik }
19019732b024SMichael Rolnik 
19029732b024SMichael Rolnik /*
19039732b024SMichael Rolnik  * Stores one byte indirect with or without displacement from a register to data
19049732b024SMichael Rolnik  * space. For parts with SRAM, the data space consists of the Register File, I/O
19059732b024SMichael Rolnik  * memory, and internal SRAM (and external SRAM if applicable). For parts
19069732b024SMichael Rolnik  * without SRAM, the data space consists of the Register File only. The EEPROM
19079732b024SMichael Rolnik  * has a separate address space.
19089732b024SMichael Rolnik  *
19099732b024SMichael Rolnik  * The data location is pointed to by the Y (16 bits) Pointer Register in the
19109732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
19119732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
19129732b024SMichael Rolnik  * RAMPY in register in the I/O area has to be changed.
19139732b024SMichael Rolnik  *
19149732b024SMichael Rolnik  * The Y-pointer Register can either be left unchanged by the operation, or it
19159732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
19169732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer
19179732b024SMichael Rolnik  * Register. Note that only the low byte of the Y-pointer is updated in devices
19189732b024SMichael Rolnik  * with no more than 256 bytes data space. For such devices, the high byte of
19199732b024SMichael Rolnik  * the pointer is not used by this instruction and can be used for other
19209732b024SMichael Rolnik  * purposes. The RAMPY Register in the I/O area is updated in parts with more
19219732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
19229732b024SMichael Rolnik  * decrement / displacement is added to the entire 24-bit address on such
19239732b024SMichael Rolnik  * devices.
19249732b024SMichael Rolnik  */
trans_STZ2(DisasContext * ctx,arg_STZ2 * a)19259732b024SMichael Rolnik static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a)
19269732b024SMichael Rolnik {
19279732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
19289732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
19299732b024SMichael Rolnik 
19309732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19319732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
19329732b024SMichael Rolnik 
19339732b024SMichael Rolnik     gen_set_zaddr(addr);
19349732b024SMichael Rolnik     return true;
19359732b024SMichael Rolnik }
19369732b024SMichael Rolnik 
trans_STZ3(DisasContext * ctx,arg_STZ3 * a)19379732b024SMichael Rolnik static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a)
19389732b024SMichael Rolnik {
19399732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
19409732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
19419732b024SMichael Rolnik 
19429732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
19439732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19449732b024SMichael Rolnik 
19459732b024SMichael Rolnik     gen_set_zaddr(addr);
19469732b024SMichael Rolnik     return true;
19479732b024SMichael Rolnik }
19489732b024SMichael Rolnik 
trans_STDZ(DisasContext * ctx,arg_STDZ * a)19499732b024SMichael Rolnik static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a)
19509732b024SMichael Rolnik {
19519732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
19529732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
19539732b024SMichael Rolnik 
19549732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
19559732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19569732b024SMichael Rolnik     return true;
19579732b024SMichael Rolnik }
19589732b024SMichael Rolnik 
19599732b024SMichael Rolnik /*
19609732b024SMichael Rolnik  *  Loads one byte pointed to by the Z-register into the destination
19619732b024SMichael Rolnik  *  register Rd. This instruction features a 100% space effective constant
19629732b024SMichael Rolnik  *  initialization or constant data fetch. The Program memory is organized in
19639732b024SMichael Rolnik  *  16-bit words while the Z-pointer is a byte address. Thus, the least
19649732b024SMichael Rolnik  *  significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high
19659732b024SMichael Rolnik  *  byte (ZLSB = 1). This instruction can address the first 64KB (32K words) of
19669732b024SMichael Rolnik  *  Program memory. The Zpointer Register can either be left unchanged by the
19679732b024SMichael Rolnik  *  operation, or it can be incremented. The incrementation does not apply to
19689732b024SMichael Rolnik  *  the RAMPZ Register.
19699732b024SMichael Rolnik  *
19709732b024SMichael Rolnik  *  Devices with Self-Programming capability can use the LPM instruction to read
19719732b024SMichael Rolnik  *  the Fuse and Lock bit values.
19729732b024SMichael Rolnik  */
trans_LPM1(DisasContext * ctx,arg_LPM1 * a)19739732b024SMichael Rolnik static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a)
19749732b024SMichael Rolnik {
19759732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) {
19769732b024SMichael Rolnik         return true;
19779732b024SMichael Rolnik     }
19789732b024SMichael Rolnik 
19799732b024SMichael Rolnik     TCGv Rd = cpu_r[0];
19809732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
19819732b024SMichael Rolnik     TCGv H = cpu_r[31];
19829732b024SMichael Rolnik     TCGv L = cpu_r[30];
19839732b024SMichael Rolnik 
19849732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
19859732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
19868b4506e5SRichard Henderson     tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
19879732b024SMichael Rolnik     return true;
19889732b024SMichael Rolnik }
19899732b024SMichael Rolnik 
trans_LPM2(DisasContext * ctx,arg_LPM2 * a)19909732b024SMichael Rolnik static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a)
19919732b024SMichael Rolnik {
19929732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) {
19939732b024SMichael Rolnik         return true;
19949732b024SMichael Rolnik     }
19959732b024SMichael Rolnik 
19969732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
19979732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
19989732b024SMichael Rolnik     TCGv H = cpu_r[31];
19999732b024SMichael Rolnik     TCGv L = cpu_r[30];
20009732b024SMichael Rolnik 
20019732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
20029732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
20038b4506e5SRichard Henderson     tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
20049732b024SMichael Rolnik     return true;
20059732b024SMichael Rolnik }
20069732b024SMichael Rolnik 
trans_LPMX(DisasContext * ctx,arg_LPMX * a)20079732b024SMichael Rolnik static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a)
20089732b024SMichael Rolnik {
20099732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPMX)) {
20109732b024SMichael Rolnik         return true;
20119732b024SMichael Rolnik     }
20129732b024SMichael Rolnik 
20139732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20149732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
20159732b024SMichael Rolnik     TCGv H = cpu_r[31];
20169732b024SMichael Rolnik     TCGv L = cpu_r[30];
20179732b024SMichael Rolnik 
20189732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
20199732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
20208b4506e5SRichard Henderson     tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
20219732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
20229732b024SMichael Rolnik     tcg_gen_andi_tl(L, addr, 0xff);
20239732b024SMichael Rolnik     tcg_gen_shri_tl(addr, addr, 8);
20249732b024SMichael Rolnik     tcg_gen_andi_tl(H, addr, 0xff);
20259732b024SMichael Rolnik     return true;
20269732b024SMichael Rolnik }
20279732b024SMichael Rolnik 
20289732b024SMichael Rolnik /*
20299732b024SMichael Rolnik  *  Loads one byte pointed to by the Z-register and the RAMPZ Register in
20309732b024SMichael Rolnik  *  the I/O space, and places this byte in the destination register Rd. This
20319732b024SMichael Rolnik  *  instruction features a 100% space effective constant initialization or
20329732b024SMichael Rolnik  *  constant data fetch. The Program memory is organized in 16-bit words while
20339732b024SMichael Rolnik  *  the Z-pointer is a byte address. Thus, the least significant bit of the
20349732b024SMichael Rolnik  *  Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This
20359732b024SMichael Rolnik  *  instruction can address the entire Program memory space. The Z-pointer
20369732b024SMichael Rolnik  *  Register can either be left unchanged by the operation, or it can be
20379732b024SMichael Rolnik  *  incremented. The incrementation applies to the entire 24-bit concatenation
20389732b024SMichael Rolnik  *  of the RAMPZ and Z-pointer Registers.
20399732b024SMichael Rolnik  *
20409732b024SMichael Rolnik  *  Devices with Self-Programming capability can use the ELPM instruction to
20419732b024SMichael Rolnik  *  read the Fuse and Lock bit value.
20429732b024SMichael Rolnik  */
trans_ELPM1(DisasContext * ctx,arg_ELPM1 * a)20439732b024SMichael Rolnik static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a)
20449732b024SMichael Rolnik {
20459732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) {
20469732b024SMichael Rolnik         return true;
20479732b024SMichael Rolnik     }
20489732b024SMichael Rolnik 
20499732b024SMichael Rolnik     TCGv Rd = cpu_r[0];
20509732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
20519732b024SMichael Rolnik 
20528b4506e5SRichard Henderson     tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
20539732b024SMichael Rolnik     return true;
20549732b024SMichael Rolnik }
20559732b024SMichael Rolnik 
trans_ELPM2(DisasContext * ctx,arg_ELPM2 * a)20569732b024SMichael Rolnik static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a)
20579732b024SMichael Rolnik {
20589732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) {
20599732b024SMichael Rolnik         return true;
20609732b024SMichael Rolnik     }
20619732b024SMichael Rolnik 
20629732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20639732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
20649732b024SMichael Rolnik 
20658b4506e5SRichard Henderson     tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
20669732b024SMichael Rolnik     return true;
20679732b024SMichael Rolnik }
20689732b024SMichael Rolnik 
trans_ELPMX(DisasContext * ctx,arg_ELPMX * a)20699732b024SMichael Rolnik static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a)
20709732b024SMichael Rolnik {
20719732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPMX)) {
20729732b024SMichael Rolnik         return true;
20739732b024SMichael Rolnik     }
20749732b024SMichael Rolnik 
20759732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20769732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
20779732b024SMichael Rolnik 
20788b4506e5SRichard Henderson     tcg_gen_qemu_ld_tl(Rd, addr, MMU_CODE_IDX, MO_UB);
20799732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
20809732b024SMichael Rolnik     gen_set_zaddr(addr);
20819732b024SMichael Rolnik     return true;
20829732b024SMichael Rolnik }
20839732b024SMichael Rolnik 
20849732b024SMichael Rolnik /*
20859732b024SMichael Rolnik  *  SPM can be used to erase a page in the Program memory, to write a page
20869732b024SMichael Rolnik  *  in the Program memory (that is already erased), and to set Boot Loader Lock
20879732b024SMichael Rolnik  *  bits. In some devices, the Program memory can be written one word at a time,
20889732b024SMichael Rolnik  *  in other devices an entire page can be programmed simultaneously after first
20899732b024SMichael Rolnik  *  filling a temporary page buffer. In all cases, the Program memory must be
20909732b024SMichael Rolnik  *  erased one page at a time. When erasing the Program memory, the RAMPZ and
20919732b024SMichael Rolnik  *  Z-register are used as page address. When writing the Program memory, the
20929732b024SMichael Rolnik  *  RAMPZ and Z-register are used as page or word address, and the R1:R0
20939732b024SMichael Rolnik  *  register pair is used as data(1). When setting the Boot Loader Lock bits,
20949732b024SMichael Rolnik  *  the R1:R0 register pair is used as data. Refer to the device documentation
20959732b024SMichael Rolnik  *  for detailed description of SPM usage. This instruction can address the
20969732b024SMichael Rolnik  *  entire Program memory.
20979732b024SMichael Rolnik  *
20989732b024SMichael Rolnik  *  The SPM instruction is not available in all devices. Refer to the device
20999732b024SMichael Rolnik  *  specific instruction set summary.
21009732b024SMichael Rolnik  *
21019732b024SMichael Rolnik  *  Note: 1. R1 determines the instruction high byte, and R0 determines the
21029732b024SMichael Rolnik  *  instruction low byte.
21039732b024SMichael Rolnik  */
trans_SPM(DisasContext * ctx,arg_SPM * a)21049732b024SMichael Rolnik static bool trans_SPM(DisasContext *ctx, arg_SPM *a)
21059732b024SMichael Rolnik {
21069732b024SMichael Rolnik     /* TODO */
21079732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_SPM)) {
21089732b024SMichael Rolnik         return true;
21099732b024SMichael Rolnik     }
21109732b024SMichael Rolnik 
21119732b024SMichael Rolnik     return true;
21129732b024SMichael Rolnik }
21139732b024SMichael Rolnik 
trans_SPMX(DisasContext * ctx,arg_SPMX * a)21149732b024SMichael Rolnik static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a)
21159732b024SMichael Rolnik {
21169732b024SMichael Rolnik     /* TODO */
21179732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_SPMX)) {
21189732b024SMichael Rolnik         return true;
21199732b024SMichael Rolnik     }
21209732b024SMichael Rolnik 
21219732b024SMichael Rolnik     return true;
21229732b024SMichael Rolnik }
21239732b024SMichael Rolnik 
21249732b024SMichael Rolnik /*
21259732b024SMichael Rolnik  *  Loads data from the I/O Space (Ports, Timers, Configuration Registers,
21269732b024SMichael Rolnik  *  etc.) into register Rd in the Register File.
21279732b024SMichael Rolnik  */
trans_IN(DisasContext * ctx,arg_IN * a)21289732b024SMichael Rolnik static bool trans_IN(DisasContext *ctx, arg_IN *a)
21299732b024SMichael Rolnik {
21309732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
21316d27bb55SRichard Henderson     TCGv port = tcg_constant_i32(a->imm);
21329732b024SMichael Rolnik 
2133ad75a51eSRichard Henderson     gen_helper_inb(Rd, tcg_env, port);
21349732b024SMichael Rolnik     return true;
21359732b024SMichael Rolnik }
21369732b024SMichael Rolnik 
21379732b024SMichael Rolnik /*
21389732b024SMichael Rolnik  *  Stores data from register Rr in the Register File to I/O Space (Ports,
21399732b024SMichael Rolnik  *  Timers, Configuration Registers, etc.).
21409732b024SMichael Rolnik  */
trans_OUT(DisasContext * ctx,arg_OUT * a)21419732b024SMichael Rolnik static bool trans_OUT(DisasContext *ctx, arg_OUT *a)
21429732b024SMichael Rolnik {
21439732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
21446d27bb55SRichard Henderson     TCGv port = tcg_constant_i32(a->imm);
21459732b024SMichael Rolnik 
2146ad75a51eSRichard Henderson     gen_helper_outb(tcg_env, port, Rd);
21479732b024SMichael Rolnik     return true;
21489732b024SMichael Rolnik }
21499732b024SMichael Rolnik 
21509732b024SMichael Rolnik /*
21519732b024SMichael Rolnik  *  This instruction stores the contents of register Rr on the STACK. The
21529732b024SMichael Rolnik  *  Stack Pointer is post-decremented by 1 after the PUSH.  This instruction is
21539732b024SMichael Rolnik  *  not available in all devices. Refer to the device specific instruction set
21549732b024SMichael Rolnik  *  summary.
21559732b024SMichael Rolnik  */
trans_PUSH(DisasContext * ctx,arg_PUSH * a)21569732b024SMichael Rolnik static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a)
21579732b024SMichael Rolnik {
21589732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
21599732b024SMichael Rolnik 
21609732b024SMichael Rolnik     gen_data_store(ctx, Rd, cpu_sp);
21619732b024SMichael Rolnik     tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
21629732b024SMichael Rolnik 
21639732b024SMichael Rolnik     return true;
21649732b024SMichael Rolnik }
21659732b024SMichael Rolnik 
21669732b024SMichael Rolnik /*
21679732b024SMichael Rolnik  *  This instruction loads register Rd with a byte from the STACK. The Stack
21689732b024SMichael Rolnik  *  Pointer is pre-incremented by 1 before the POP.  This instruction is not
21699732b024SMichael Rolnik  *  available in all devices. Refer to the device specific instruction set
21709732b024SMichael Rolnik  *  summary.
21719732b024SMichael Rolnik  */
trans_POP(DisasContext * ctx,arg_POP * a)21729732b024SMichael Rolnik static bool trans_POP(DisasContext *ctx, arg_POP *a)
21739732b024SMichael Rolnik {
21749732b024SMichael Rolnik     /*
21759732b024SMichael Rolnik      * Using a temp to work around some strange behaviour:
21769732b024SMichael Rolnik      * tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
21779732b024SMichael Rolnik      * gen_data_load(ctx, Rd, cpu_sp);
21789732b024SMichael Rolnik      * seems to cause the add to happen twice.
21799732b024SMichael Rolnik      * This doesn't happen if either the add or the load is removed.
21809732b024SMichael Rolnik      */
21819732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
21829732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
21839732b024SMichael Rolnik 
21849732b024SMichael Rolnik     tcg_gen_addi_tl(t1, cpu_sp, 1);
21859732b024SMichael Rolnik     gen_data_load(ctx, Rd, t1);
21869732b024SMichael Rolnik     tcg_gen_mov_tl(cpu_sp, t1);
21879732b024SMichael Rolnik 
21889732b024SMichael Rolnik     return true;
21899732b024SMichael Rolnik }
21909732b024SMichael Rolnik 
21919732b024SMichael Rolnik /*
21929732b024SMichael Rolnik  *  Exchanges one byte indirect between register and data space.  The data
21939732b024SMichael Rolnik  *  location is pointed to by the Z (16 bits) Pointer Register in the Register
21949732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
21959732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
21969732b024SMichael Rolnik  *  RAMPZ in register in the I/O area has to be changed.
21979732b024SMichael Rolnik  *
21989732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
21999732b024SMichael Rolnik  *  is especially suited for writing/reading status bits stored in SRAM.
22009732b024SMichael Rolnik  */
trans_XCH(DisasContext * ctx,arg_XCH * a)22019732b024SMichael Rolnik static bool trans_XCH(DisasContext *ctx, arg_XCH *a)
22029732b024SMichael Rolnik {
22039732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
22049732b024SMichael Rolnik         return true;
22059732b024SMichael Rolnik     }
22069732b024SMichael Rolnik 
22079732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
22089732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
22099732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
22109732b024SMichael Rolnik 
22119732b024SMichael Rolnik     gen_data_load(ctx, t0, addr);
22129732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
22139732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, t0);
22149732b024SMichael Rolnik     return true;
22159732b024SMichael Rolnik }
22169732b024SMichael Rolnik 
22179732b024SMichael Rolnik /*
22189732b024SMichael Rolnik  *  Load one byte indirect from data space to register and set bits in data
22199732b024SMichael Rolnik  *  space specified by the register. The instruction can only be used towards
22209732b024SMichael Rolnik  *  internal SRAM.  The data location is pointed to by the Z (16 bits) Pointer
22219732b024SMichael Rolnik  *  Register in the Register File. Memory access is limited to the current data
22229732b024SMichael Rolnik  *  segment of 64KB. To access another data segment in devices with more than
22239732b024SMichael Rolnik  *  64KB data space, the RAMPZ in register in the I/O area has to be changed.
22249732b024SMichael Rolnik  *
22259732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
22269732b024SMichael Rolnik  *  is especially suited for setting status bits stored in SRAM.
22279732b024SMichael Rolnik  */
trans_LAS(DisasContext * ctx,arg_LAS * a)22289732b024SMichael Rolnik static bool trans_LAS(DisasContext *ctx, arg_LAS *a)
22299732b024SMichael Rolnik {
22309732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
22319732b024SMichael Rolnik         return true;
22329732b024SMichael Rolnik     }
22339732b024SMichael Rolnik 
22349732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rd];
22359732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
22369732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
22379732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
22389732b024SMichael Rolnik 
22399732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
22409732b024SMichael Rolnik     tcg_gen_or_tl(t1, t0, Rr);
22419732b024SMichael Rolnik     tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
22429732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
22439732b024SMichael Rolnik     return true;
22449732b024SMichael Rolnik }
22459732b024SMichael Rolnik 
22469732b024SMichael Rolnik /*
22479732b024SMichael Rolnik  *  Load one byte indirect from data space to register and stores and clear
22489732b024SMichael Rolnik  *  the bits in data space specified by the register. The instruction can
22499732b024SMichael Rolnik  *  only be used towards internal SRAM.  The data location is pointed to by
22509732b024SMichael Rolnik  *  the Z (16 bits) Pointer Register in the Register File. Memory access is
22519732b024SMichael Rolnik  *  limited to the current data segment of 64KB. To access another data
22529732b024SMichael Rolnik  *  segment in devices with more than 64KB data space, the RAMPZ in register
22539732b024SMichael Rolnik  *  in the I/O area has to be changed.
22549732b024SMichael Rolnik  *
22559732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
22569732b024SMichael Rolnik  *  is especially suited for clearing status bits stored in SRAM.
22579732b024SMichael Rolnik  */
trans_LAC(DisasContext * ctx,arg_LAC * a)22589732b024SMichael Rolnik static bool trans_LAC(DisasContext *ctx, arg_LAC *a)
22599732b024SMichael Rolnik {
22609732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
22619732b024SMichael Rolnik         return true;
22629732b024SMichael Rolnik     }
22639732b024SMichael Rolnik 
22649732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rd];
22659732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
22669732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
22679732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
22689732b024SMichael Rolnik 
22699732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
22709732b024SMichael Rolnik     tcg_gen_andc_tl(t1, t0, Rr); /* t1 = t0 & (0xff - Rr) = t0 & ~Rr */
22719732b024SMichael Rolnik     tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
22729732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
22739732b024SMichael Rolnik     return true;
22749732b024SMichael Rolnik }
22759732b024SMichael Rolnik 
22769732b024SMichael Rolnik 
22779732b024SMichael Rolnik /*
22789732b024SMichael Rolnik  *  Load one byte indirect from data space to register and toggles bits in
22799732b024SMichael Rolnik  *  the data space specified by the register.  The instruction can only be used
22809732b024SMichael Rolnik  *  towards SRAM.  The data location is pointed to by the Z (16 bits) Pointer
22819732b024SMichael Rolnik  *  Register in the Register File. Memory access is limited to the current data
22829732b024SMichael Rolnik  *  segment of 64KB. To access another data segment in devices with more than
22839732b024SMichael Rolnik  *  64KB data space, the RAMPZ in register in the I/O area has to be changed.
22849732b024SMichael Rolnik  *
22859732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
22869732b024SMichael Rolnik  *  is especially suited for changing status bits stored in SRAM.
22879732b024SMichael Rolnik  */
trans_LAT(DisasContext * ctx,arg_LAT * a)22889732b024SMichael Rolnik static bool trans_LAT(DisasContext *ctx, arg_LAT *a)
22899732b024SMichael Rolnik {
22909732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
22919732b024SMichael Rolnik         return true;
22929732b024SMichael Rolnik     }
22939732b024SMichael Rolnik 
22949732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
22959732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
22969732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
22979732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
22989732b024SMichael Rolnik 
22999732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
23009732b024SMichael Rolnik     tcg_gen_xor_tl(t1, t0, Rd);
23019732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, t0); /* Rd = t0 */
23029732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
23039732b024SMichael Rolnik     return true;
23049732b024SMichael Rolnik }
23055718cef0SMichael Rolnik 
23065718cef0SMichael Rolnik /*
23075718cef0SMichael Rolnik  * Bit and Bit-test Instructions
23085718cef0SMichael Rolnik  */
gen_rshift_ZNVSf(TCGv R)23095718cef0SMichael Rolnik static void gen_rshift_ZNVSf(TCGv R)
23105718cef0SMichael Rolnik {
23115718cef0SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
23125718cef0SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
23135718cef0SMichael Rolnik     tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf);
23145718cef0SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
23155718cef0SMichael Rolnik }
23165718cef0SMichael Rolnik 
23175718cef0SMichael Rolnik /*
23185718cef0SMichael Rolnik  *  Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is
23195718cef0SMichael Rolnik  *  loaded into the C Flag of the SREG. This operation effectively divides an
23205718cef0SMichael Rolnik  *  unsigned value by two. The C Flag can be used to round the result.
23215718cef0SMichael Rolnik  */
trans_LSR(DisasContext * ctx,arg_LSR * a)23225718cef0SMichael Rolnik static bool trans_LSR(DisasContext *ctx, arg_LSR *a)
23235718cef0SMichael Rolnik {
23245718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23255718cef0SMichael Rolnik 
23265718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Cf, Rd, 1);
23275718cef0SMichael Rolnik     tcg_gen_shri_tl(Rd, Rd, 1);
23285718cef0SMichael Rolnik 
23295718cef0SMichael Rolnik     /* update status register */
23305718cef0SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, Rd, 0); /* Zf = Rd == 0 */
23315718cef0SMichael Rolnik     tcg_gen_movi_tl(cpu_Nf, 0);
23325718cef0SMichael Rolnik     tcg_gen_mov_tl(cpu_Vf, cpu_Cf);
23335718cef0SMichael Rolnik     tcg_gen_mov_tl(cpu_Sf, cpu_Vf);
23345718cef0SMichael Rolnik 
23355718cef0SMichael Rolnik     return true;
23365718cef0SMichael Rolnik }
23375718cef0SMichael Rolnik 
23385718cef0SMichael Rolnik /*
23395718cef0SMichael Rolnik  *  Shifts all bits in Rd one place to the right. The C Flag is shifted into
23405718cef0SMichael Rolnik  *  bit 7 of Rd. Bit 0 is shifted into the C Flag.  This operation, combined
23415718cef0SMichael Rolnik  *  with ASR, effectively divides multi-byte signed values by two. Combined with
23425718cef0SMichael Rolnik  *  LSR it effectively divides multi-byte unsigned values by two. The Carry Flag
23435718cef0SMichael Rolnik  *  can be used to round the result.
23445718cef0SMichael Rolnik  */
trans_ROR(DisasContext * ctx,arg_ROR * a)23455718cef0SMichael Rolnik static bool trans_ROR(DisasContext *ctx, arg_ROR *a)
23465718cef0SMichael Rolnik {
23475718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23485718cef0SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
23495718cef0SMichael Rolnik 
23505718cef0SMichael Rolnik     tcg_gen_shli_tl(t0, cpu_Cf, 7);
23515718cef0SMichael Rolnik 
23525718cef0SMichael Rolnik     /* update status register */
23535718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Cf, Rd, 1);
23545718cef0SMichael Rolnik 
23555718cef0SMichael Rolnik     /* update output register */
23565718cef0SMichael Rolnik     tcg_gen_shri_tl(Rd, Rd, 1);
23575718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, Rd, t0);
23585718cef0SMichael Rolnik 
23595718cef0SMichael Rolnik     /* update status register */
23605718cef0SMichael Rolnik     gen_rshift_ZNVSf(Rd);
23615718cef0SMichael Rolnik     return true;
23625718cef0SMichael Rolnik }
23635718cef0SMichael Rolnik 
23645718cef0SMichael Rolnik /*
23655718cef0SMichael Rolnik  *  Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0
23665718cef0SMichael Rolnik  *  is loaded into the C Flag of the SREG. This operation effectively divides a
23675718cef0SMichael Rolnik  *  signed value by two without changing its sign. The Carry Flag can be used to
23685718cef0SMichael Rolnik  *  round the result.
23695718cef0SMichael Rolnik  */
trans_ASR(DisasContext * ctx,arg_ASR * a)23705718cef0SMichael Rolnik static bool trans_ASR(DisasContext *ctx, arg_ASR *a)
23715718cef0SMichael Rolnik {
23725718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23735718cef0SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
23745718cef0SMichael Rolnik 
23755718cef0SMichael Rolnik     /* update status register */
23765718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */
23775718cef0SMichael Rolnik 
23785718cef0SMichael Rolnik     /* update output register */
23795718cef0SMichael Rolnik     tcg_gen_andi_tl(t0, Rd, 0x80); /* Rd = (Rd & 0x80) | (Rd >> 1) */
23805718cef0SMichael Rolnik     tcg_gen_shri_tl(Rd, Rd, 1);
23815718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, Rd, t0);
23825718cef0SMichael Rolnik 
23835718cef0SMichael Rolnik     /* update status register */
23845718cef0SMichael Rolnik     gen_rshift_ZNVSf(Rd);
23855718cef0SMichael Rolnik     return true;
23865718cef0SMichael Rolnik }
23875718cef0SMichael Rolnik 
23885718cef0SMichael Rolnik /*
23895718cef0SMichael Rolnik  *  Swaps high and low nibbles in a register.
23905718cef0SMichael Rolnik  */
trans_SWAP(DisasContext * ctx,arg_SWAP * a)23915718cef0SMichael Rolnik static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a)
23925718cef0SMichael Rolnik {
23935718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23945718cef0SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
23955718cef0SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
23965718cef0SMichael Rolnik 
23975718cef0SMichael Rolnik     tcg_gen_andi_tl(t0, Rd, 0x0f);
23985718cef0SMichael Rolnik     tcg_gen_shli_tl(t0, t0, 4);
23995718cef0SMichael Rolnik     tcg_gen_andi_tl(t1, Rd, 0xf0);
24005718cef0SMichael Rolnik     tcg_gen_shri_tl(t1, t1, 4);
24015718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, t0, t1);
24025718cef0SMichael Rolnik     return true;
24035718cef0SMichael Rolnik }
24045718cef0SMichael Rolnik 
24055718cef0SMichael Rolnik /*
24065718cef0SMichael Rolnik  *  Sets a specified bit in an I/O Register. This instruction operates on
24075718cef0SMichael Rolnik  *  the lower 32 I/O Registers -- addresses 0-31.
24085718cef0SMichael Rolnik  */
trans_SBI(DisasContext * ctx,arg_SBI * a)24095718cef0SMichael Rolnik static bool trans_SBI(DisasContext *ctx, arg_SBI *a)
24105718cef0SMichael Rolnik {
24115718cef0SMichael Rolnik     TCGv data = tcg_temp_new_i32();
24126d27bb55SRichard Henderson     TCGv port = tcg_constant_i32(a->reg);
24135718cef0SMichael Rolnik 
2414ad75a51eSRichard Henderson     gen_helper_inb(data, tcg_env, port);
24155718cef0SMichael Rolnik     tcg_gen_ori_tl(data, data, 1 << a->bit);
2416ad75a51eSRichard Henderson     gen_helper_outb(tcg_env, port, data);
24175718cef0SMichael Rolnik     return true;
24185718cef0SMichael Rolnik }
24195718cef0SMichael Rolnik 
24205718cef0SMichael Rolnik /*
24215718cef0SMichael Rolnik  *  Clears a specified bit in an I/O Register. This instruction operates on
24225718cef0SMichael Rolnik  *  the lower 32 I/O Registers -- addresses 0-31.
24235718cef0SMichael Rolnik  */
trans_CBI(DisasContext * ctx,arg_CBI * a)24245718cef0SMichael Rolnik static bool trans_CBI(DisasContext *ctx, arg_CBI *a)
24255718cef0SMichael Rolnik {
24265718cef0SMichael Rolnik     TCGv data = tcg_temp_new_i32();
24276d27bb55SRichard Henderson     TCGv port = tcg_constant_i32(a->reg);
24285718cef0SMichael Rolnik 
2429ad75a51eSRichard Henderson     gen_helper_inb(data, tcg_env, port);
24305718cef0SMichael Rolnik     tcg_gen_andi_tl(data, data, ~(1 << a->bit));
2431ad75a51eSRichard Henderson     gen_helper_outb(tcg_env, port, data);
24325718cef0SMichael Rolnik     return true;
24335718cef0SMichael Rolnik }
24345718cef0SMichael Rolnik 
24355718cef0SMichael Rolnik /*
24365718cef0SMichael Rolnik  *  Stores bit b from Rd to the T Flag in SREG (Status Register).
24375718cef0SMichael Rolnik  */
trans_BST(DisasContext * ctx,arg_BST * a)24385718cef0SMichael Rolnik static bool trans_BST(DisasContext *ctx, arg_BST *a)
24395718cef0SMichael Rolnik {
24405718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
24415718cef0SMichael Rolnik 
24425718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit);
24435718cef0SMichael Rolnik     tcg_gen_shri_tl(cpu_Tf, cpu_Tf, a->bit);
24445718cef0SMichael Rolnik 
24455718cef0SMichael Rolnik     return true;
24465718cef0SMichael Rolnik }
24475718cef0SMichael Rolnik 
24485718cef0SMichael Rolnik /*
24495718cef0SMichael Rolnik  *  Copies the T Flag in the SREG (Status Register) to bit b in register Rd.
24505718cef0SMichael Rolnik  */
trans_BLD(DisasContext * ctx,arg_BLD * a)24515718cef0SMichael Rolnik static bool trans_BLD(DisasContext *ctx, arg_BLD *a)
24525718cef0SMichael Rolnik {
24535718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
24545718cef0SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
24555718cef0SMichael Rolnik 
24565718cef0SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */
24575718cef0SMichael Rolnik     tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */
24585718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, Rd, t1);
24595718cef0SMichael Rolnik     return true;
24605718cef0SMichael Rolnik }
24615718cef0SMichael Rolnik 
24625718cef0SMichael Rolnik /*
24635718cef0SMichael Rolnik  *  Sets a single Flag or bit in SREG.
24645718cef0SMichael Rolnik  */
trans_BSET(DisasContext * ctx,arg_BSET * a)24655718cef0SMichael Rolnik static bool trans_BSET(DisasContext *ctx, arg_BSET *a)
24665718cef0SMichael Rolnik {
24675718cef0SMichael Rolnik     switch (a->bit) {
24685718cef0SMichael Rolnik     case 0x00:
24695718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Cf, 0x01);
24705718cef0SMichael Rolnik         break;
24715718cef0SMichael Rolnik     case 0x01:
24725718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Zf, 0x01);
24735718cef0SMichael Rolnik         break;
24745718cef0SMichael Rolnik     case 0x02:
24755718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Nf, 0x01);
24765718cef0SMichael Rolnik         break;
24775718cef0SMichael Rolnik     case 0x03:
24785718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Vf, 0x01);
24795718cef0SMichael Rolnik         break;
24805718cef0SMichael Rolnik     case 0x04:
24815718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Sf, 0x01);
24825718cef0SMichael Rolnik         break;
24835718cef0SMichael Rolnik     case 0x05:
24845718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Hf, 0x01);
24855718cef0SMichael Rolnik         break;
24865718cef0SMichael Rolnik     case 0x06:
24875718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Tf, 0x01);
24885718cef0SMichael Rolnik         break;
24895718cef0SMichael Rolnik     case 0x07:
24905718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_If, 0x01);
24915718cef0SMichael Rolnik         break;
24925718cef0SMichael Rolnik     }
24935718cef0SMichael Rolnik 
24945718cef0SMichael Rolnik     return true;
24955718cef0SMichael Rolnik }
24965718cef0SMichael Rolnik 
24975718cef0SMichael Rolnik /*
24985718cef0SMichael Rolnik  *  Clears a single Flag in SREG.
24995718cef0SMichael Rolnik  */
trans_BCLR(DisasContext * ctx,arg_BCLR * a)25005718cef0SMichael Rolnik static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a)
25015718cef0SMichael Rolnik {
25025718cef0SMichael Rolnik     switch (a->bit) {
25035718cef0SMichael Rolnik     case 0x00:
25045718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Cf, 0x00);
25055718cef0SMichael Rolnik         break;
25065718cef0SMichael Rolnik     case 0x01:
25075718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Zf, 0x00);
25085718cef0SMichael Rolnik         break;
25095718cef0SMichael Rolnik     case 0x02:
25105718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Nf, 0x00);
25115718cef0SMichael Rolnik         break;
25125718cef0SMichael Rolnik     case 0x03:
25135718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Vf, 0x00);
25145718cef0SMichael Rolnik         break;
25155718cef0SMichael Rolnik     case 0x04:
25165718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Sf, 0x00);
25175718cef0SMichael Rolnik         break;
25185718cef0SMichael Rolnik     case 0x05:
25195718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Hf, 0x00);
25205718cef0SMichael Rolnik         break;
25215718cef0SMichael Rolnik     case 0x06:
25225718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Tf, 0x00);
25235718cef0SMichael Rolnik         break;
25245718cef0SMichael Rolnik     case 0x07:
25255718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_If, 0x00);
25265718cef0SMichael Rolnik         break;
25275718cef0SMichael Rolnik     }
25285718cef0SMichael Rolnik 
25295718cef0SMichael Rolnik     return true;
25305718cef0SMichael Rolnik }
253146188cabSMichael Rolnik 
253246188cabSMichael Rolnik /*
253346188cabSMichael Rolnik  * MCU Control Instructions
253446188cabSMichael Rolnik  */
253546188cabSMichael Rolnik 
253646188cabSMichael Rolnik /*
253746188cabSMichael Rolnik  *  The BREAK instruction is used by the On-chip Debug system, and is
253846188cabSMichael Rolnik  *  normally not used in the application software. When the BREAK instruction is
253946188cabSMichael Rolnik  *  executed, the AVR CPU is set in the Stopped Mode. This gives the On-chip
254046188cabSMichael Rolnik  *  Debugger access to internal resources.  If any Lock bits are set, or either
254146188cabSMichael Rolnik  *  the JTAGEN or OCDEN Fuses are unprogrammed, the CPU will treat the BREAK
254246188cabSMichael Rolnik  *  instruction as a NOP and will not enter the Stopped mode.  This instruction
254346188cabSMichael Rolnik  *  is not available in all devices. Refer to the device specific instruction
254446188cabSMichael Rolnik  *  set summary.
254546188cabSMichael Rolnik  */
trans_BREAK(DisasContext * ctx,arg_BREAK * a)254646188cabSMichael Rolnik static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a)
254746188cabSMichael Rolnik {
254846188cabSMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_BREAK)) {
254946188cabSMichael Rolnik         return true;
255046188cabSMichael Rolnik     }
255146188cabSMichael Rolnik 
255246188cabSMichael Rolnik #ifdef BREAKPOINT_ON_BREAK
255346188cabSMichael Rolnik     tcg_gen_movi_tl(cpu_pc, ctx->npc - 1);
2554ad75a51eSRichard Henderson     gen_helper_debug(tcg_env);
255593d4d5e4SRichard Henderson     ctx->base.is_jmp = DISAS_EXIT;
255646188cabSMichael Rolnik #else
255746188cabSMichael Rolnik     /* NOP */
255846188cabSMichael Rolnik #endif
255946188cabSMichael Rolnik 
256046188cabSMichael Rolnik     return true;
256146188cabSMichael Rolnik }
256246188cabSMichael Rolnik 
256346188cabSMichael Rolnik /*
256446188cabSMichael Rolnik  *  This instruction performs a single cycle No Operation.
256546188cabSMichael Rolnik  */
trans_NOP(DisasContext * ctx,arg_NOP * a)256646188cabSMichael Rolnik static bool trans_NOP(DisasContext *ctx, arg_NOP *a)
256746188cabSMichael Rolnik {
256846188cabSMichael Rolnik 
256946188cabSMichael Rolnik     /* NOP */
257046188cabSMichael Rolnik 
257146188cabSMichael Rolnik     return true;
257246188cabSMichael Rolnik }
257346188cabSMichael Rolnik 
257446188cabSMichael Rolnik /*
257546188cabSMichael Rolnik  *  This instruction sets the circuit in sleep mode defined by the MCU
257646188cabSMichael Rolnik  *  Control Register.
257746188cabSMichael Rolnik  */
trans_SLEEP(DisasContext * ctx,arg_SLEEP * a)257846188cabSMichael Rolnik static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a)
257946188cabSMichael Rolnik {
2580ad75a51eSRichard Henderson     gen_helper_sleep(tcg_env);
258193d4d5e4SRichard Henderson     ctx->base.is_jmp = DISAS_NORETURN;
258246188cabSMichael Rolnik     return true;
258346188cabSMichael Rolnik }
258446188cabSMichael Rolnik 
258546188cabSMichael Rolnik /*
258646188cabSMichael Rolnik  *  This instruction resets the Watchdog Timer. This instruction must be
258746188cabSMichael Rolnik  *  executed within a limited time given by the WD prescaler. See the Watchdog
258846188cabSMichael Rolnik  *  Timer hardware specification.
258946188cabSMichael Rolnik  */
trans_WDR(DisasContext * ctx,arg_WDR * a)259046188cabSMichael Rolnik static bool trans_WDR(DisasContext *ctx, arg_WDR *a)
259146188cabSMichael Rolnik {
2592ad75a51eSRichard Henderson     gen_helper_wdr(tcg_env);
259346188cabSMichael Rolnik 
259446188cabSMichael Rolnik     return true;
259546188cabSMichael Rolnik }
25969baade8dSMichael Rolnik 
25979baade8dSMichael Rolnik /*
25989baade8dSMichael Rolnik  *  Core translation mechanism functions:
25999baade8dSMichael Rolnik  *
26009baade8dSMichael Rolnik  *    - translate()
26019baade8dSMichael Rolnik  *    - canonicalize_skip()
26029baade8dSMichael Rolnik  *    - gen_intermediate_code()
26039baade8dSMichael Rolnik  *    - restore_state_to_opc()
26049baade8dSMichael Rolnik  *
26059baade8dSMichael Rolnik  */
translate(DisasContext * ctx)26069baade8dSMichael Rolnik static void translate(DisasContext *ctx)
26079baade8dSMichael Rolnik {
26089baade8dSMichael Rolnik     uint32_t opcode = next_word(ctx);
26099baade8dSMichael Rolnik 
26109baade8dSMichael Rolnik     if (!decode_insn(ctx, opcode)) {
2611ad75a51eSRichard Henderson         gen_helper_unsupported(tcg_env);
261293d4d5e4SRichard Henderson         ctx->base.is_jmp = DISAS_NORETURN;
26139baade8dSMichael Rolnik     }
26149baade8dSMichael Rolnik }
26159baade8dSMichael Rolnik 
26169baade8dSMichael Rolnik /* Standardize the cpu_skip condition to NE.  */
canonicalize_skip(DisasContext * ctx)26179baade8dSMichael Rolnik static bool canonicalize_skip(DisasContext *ctx)
26189baade8dSMichael Rolnik {
26199baade8dSMichael Rolnik     switch (ctx->skip_cond) {
26209baade8dSMichael Rolnik     case TCG_COND_NEVER:
26219baade8dSMichael Rolnik         /* Normal case: cpu_skip is known to be false.  */
26229baade8dSMichael Rolnik         return false;
26239baade8dSMichael Rolnik 
26249baade8dSMichael Rolnik     case TCG_COND_ALWAYS:
26259baade8dSMichael Rolnik         /*
26269baade8dSMichael Rolnik          * Breakpoint case: cpu_skip is known to be true, via TB_FLAGS_SKIP.
26279baade8dSMichael Rolnik          * The breakpoint is on the instruction being skipped, at the start
26289baade8dSMichael Rolnik          * of the TranslationBlock.  No need to update.
26299baade8dSMichael Rolnik          */
26309baade8dSMichael Rolnik         return false;
26319baade8dSMichael Rolnik 
26329baade8dSMichael Rolnik     case TCG_COND_NE:
26339baade8dSMichael Rolnik         if (ctx->skip_var1 == NULL) {
26349baade8dSMichael Rolnik             tcg_gen_mov_tl(cpu_skip, ctx->skip_var0);
26359baade8dSMichael Rolnik         } else {
26369baade8dSMichael Rolnik             tcg_gen_xor_tl(cpu_skip, ctx->skip_var0, ctx->skip_var1);
26379baade8dSMichael Rolnik             ctx->skip_var1 = NULL;
26389baade8dSMichael Rolnik         }
26399baade8dSMichael Rolnik         break;
26409baade8dSMichael Rolnik 
26419baade8dSMichael Rolnik     default:
26429baade8dSMichael Rolnik         /* Convert to a NE condition vs 0. */
26439baade8dSMichael Rolnik         if (ctx->skip_var1 == NULL) {
26449baade8dSMichael Rolnik             tcg_gen_setcondi_tl(ctx->skip_cond, cpu_skip, ctx->skip_var0, 0);
26459baade8dSMichael Rolnik         } else {
26469baade8dSMichael Rolnik             tcg_gen_setcond_tl(ctx->skip_cond, cpu_skip,
26479baade8dSMichael Rolnik                                ctx->skip_var0, ctx->skip_var1);
26489baade8dSMichael Rolnik             ctx->skip_var1 = NULL;
26499baade8dSMichael Rolnik         }
26509baade8dSMichael Rolnik         ctx->skip_cond = TCG_COND_NE;
26519baade8dSMichael Rolnik         break;
26529baade8dSMichael Rolnik     }
26539baade8dSMichael Rolnik     ctx->skip_var0 = cpu_skip;
26549baade8dSMichael Rolnik     return true;
26559baade8dSMichael Rolnik }
26569baade8dSMichael Rolnik 
avr_tr_init_disas_context(DisasContextBase * dcbase,CPUState * cs)26573fbd28d8SRichard Henderson static void avr_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
26583fbd28d8SRichard Henderson {
26593fbd28d8SRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
2660*b77af26eSRichard Henderson     CPUAVRState *env = cpu_env(cs);
26613fbd28d8SRichard Henderson     uint32_t tb_flags = ctx->base.tb->flags;
26629baade8dSMichael Rolnik 
26633fbd28d8SRichard Henderson     ctx->cs = cs;
26643fbd28d8SRichard Henderson     ctx->env = env;
26653fbd28d8SRichard Henderson     ctx->npc = ctx->base.pc_first / 2;
26669baade8dSMichael Rolnik 
26673fbd28d8SRichard Henderson     ctx->skip_cond = TCG_COND_NEVER;
26683fbd28d8SRichard Henderson     if (tb_flags & TB_FLAGS_SKIP) {
2669bcef6d76SRichard Henderson         ctx->skip_cond = TCG_COND_ALWAYS;
2670bcef6d76SRichard Henderson         ctx->skip_var0 = cpu_skip;
26719baade8dSMichael Rolnik     }
26729baade8dSMichael Rolnik 
26733fbd28d8SRichard Henderson     if (tb_flags & TB_FLAGS_FULL_ACCESS) {
26743fbd28d8SRichard Henderson         /*
26753fbd28d8SRichard Henderson          * This flag is set by ST/LD instruction we will regenerate it ONLY
26763fbd28d8SRichard Henderson          * with mem/cpu memory access instead of mem access
26773fbd28d8SRichard Henderson          */
26783fbd28d8SRichard Henderson         ctx->base.max_insns = 1;
26793fbd28d8SRichard Henderson     }
26803fbd28d8SRichard Henderson }
26813fbd28d8SRichard Henderson 
avr_tr_tb_start(DisasContextBase * db,CPUState * cs)26823fbd28d8SRichard Henderson static void avr_tr_tb_start(DisasContextBase *db, CPUState *cs)
26833fbd28d8SRichard Henderson {
26843fbd28d8SRichard Henderson }
26853fbd28d8SRichard Henderson 
avr_tr_insn_start(DisasContextBase * dcbase,CPUState * cs)26863fbd28d8SRichard Henderson static void avr_tr_insn_start(DisasContextBase *dcbase, CPUState *cs)
26873fbd28d8SRichard Henderson {
26883fbd28d8SRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
26893fbd28d8SRichard Henderson 
26903fbd28d8SRichard Henderson     tcg_gen_insn_start(ctx->npc);
26913fbd28d8SRichard Henderson }
26923fbd28d8SRichard Henderson 
avr_tr_translate_insn(DisasContextBase * dcbase,CPUState * cs)26933fbd28d8SRichard Henderson static void avr_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
26943fbd28d8SRichard Henderson {
26953fbd28d8SRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
26969baade8dSMichael Rolnik     TCGLabel *skip_label = NULL;
26979baade8dSMichael Rolnik 
26989baade8dSMichael Rolnik     /* Conditionally skip the next instruction, if indicated.  */
2699bcef6d76SRichard Henderson     if (ctx->skip_cond != TCG_COND_NEVER) {
27009baade8dSMichael Rolnik         skip_label = gen_new_label();
2701bcef6d76SRichard Henderson         if (ctx->skip_var0 == cpu_skip) {
27029baade8dSMichael Rolnik             /*
27039baade8dSMichael Rolnik              * Copy cpu_skip so that we may zero it before the branch.
27049baade8dSMichael Rolnik              * This ensures that cpu_skip is non-zero after the label
27059baade8dSMichael Rolnik              * if and only if the skipped insn itself sets a skip.
27069baade8dSMichael Rolnik              */
2707bcef6d76SRichard Henderson             ctx->skip_var0 = tcg_temp_new();
2708bcef6d76SRichard Henderson             tcg_gen_mov_tl(ctx->skip_var0, cpu_skip);
27099baade8dSMichael Rolnik             tcg_gen_movi_tl(cpu_skip, 0);
27109baade8dSMichael Rolnik         }
2711bcef6d76SRichard Henderson         if (ctx->skip_var1 == NULL) {
27123fbd28d8SRichard Henderson             tcg_gen_brcondi_tl(ctx->skip_cond, ctx->skip_var0, 0, skip_label);
27139baade8dSMichael Rolnik         } else {
2714bcef6d76SRichard Henderson             tcg_gen_brcond_tl(ctx->skip_cond, ctx->skip_var0,
2715bcef6d76SRichard Henderson                               ctx->skip_var1, skip_label);
2716bcef6d76SRichard Henderson             ctx->skip_var1 = NULL;
27179baade8dSMichael Rolnik         }
2718bcef6d76SRichard Henderson         ctx->skip_cond = TCG_COND_NEVER;
2719bcef6d76SRichard Henderson         ctx->skip_var0 = NULL;
27209baade8dSMichael Rolnik     }
27219baade8dSMichael Rolnik 
2722bcef6d76SRichard Henderson     translate(ctx);
27239baade8dSMichael Rolnik 
27243fbd28d8SRichard Henderson     ctx->base.pc_next = ctx->npc * 2;
27253fbd28d8SRichard Henderson 
27269baade8dSMichael Rolnik     if (skip_label) {
2727bcef6d76SRichard Henderson         canonicalize_skip(ctx);
27289baade8dSMichael Rolnik         gen_set_label(skip_label);
272936027c70SRichard Henderson 
273036027c70SRichard Henderson         switch (ctx->base.is_jmp) {
273136027c70SRichard Henderson         case DISAS_NORETURN:
2732bcef6d76SRichard Henderson             ctx->base.is_jmp = DISAS_CHAIN;
273336027c70SRichard Henderson             break;
273436027c70SRichard Henderson         case DISAS_NEXT:
273536027c70SRichard Henderson             if (ctx->base.tb->flags & TB_FLAGS_SKIP) {
273636027c70SRichard Henderson                 ctx->base.is_jmp = DISAS_TOO_MANY;
273736027c70SRichard Henderson             }
273836027c70SRichard Henderson             break;
273936027c70SRichard Henderson         default:
274036027c70SRichard Henderson             break;
27419baade8dSMichael Rolnik         }
27429baade8dSMichael Rolnik     }
27439baade8dSMichael Rolnik 
27443fbd28d8SRichard Henderson     if (ctx->base.is_jmp == DISAS_NEXT) {
27453fbd28d8SRichard Henderson         target_ulong page_first = ctx->base.pc_first & TARGET_PAGE_MASK;
27463fbd28d8SRichard Henderson 
27473fbd28d8SRichard Henderson         if ((ctx->base.pc_next - page_first) >= TARGET_PAGE_SIZE - 4) {
27483fbd28d8SRichard Henderson             ctx->base.is_jmp = DISAS_TOO_MANY;
27493fbd28d8SRichard Henderson         }
27503fbd28d8SRichard Henderson     }
27519baade8dSMichael Rolnik }
27529baade8dSMichael Rolnik 
avr_tr_tb_stop(DisasContextBase * dcbase,CPUState * cs)27533fbd28d8SRichard Henderson static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
27543fbd28d8SRichard Henderson {
27553fbd28d8SRichard Henderson     DisasContext *ctx = container_of(dcbase, DisasContext, base);
2756bcef6d76SRichard Henderson     bool nonconst_skip = canonicalize_skip(ctx);
275736027c70SRichard Henderson     /*
275836027c70SRichard Henderson      * Because we disable interrupts while env->skip is set,
275936027c70SRichard Henderson      * we must return to the main loop to re-evaluate afterward.
276036027c70SRichard Henderson      */
276136027c70SRichard Henderson     bool force_exit = ctx->base.tb->flags & TB_FLAGS_SKIP;
27629baade8dSMichael Rolnik 
2763bcef6d76SRichard Henderson     switch (ctx->base.is_jmp) {
27649baade8dSMichael Rolnik     case DISAS_NORETURN:
27659baade8dSMichael Rolnik         assert(!nonconst_skip);
27669baade8dSMichael Rolnik         break;
27679baade8dSMichael Rolnik     case DISAS_NEXT:
27689baade8dSMichael Rolnik     case DISAS_TOO_MANY:
27699baade8dSMichael Rolnik     case DISAS_CHAIN:
277036027c70SRichard Henderson         if (!nonconst_skip && !force_exit) {
27719baade8dSMichael Rolnik             /* Note gen_goto_tb checks singlestep.  */
2772bcef6d76SRichard Henderson             gen_goto_tb(ctx, 1, ctx->npc);
27739baade8dSMichael Rolnik             break;
27749baade8dSMichael Rolnik         }
2775bcef6d76SRichard Henderson         tcg_gen_movi_tl(cpu_pc, ctx->npc);
27769baade8dSMichael Rolnik         /* fall through */
27779baade8dSMichael Rolnik     case DISAS_LOOKUP:
277836027c70SRichard Henderson         if (!force_exit) {
27799baade8dSMichael Rolnik             tcg_gen_lookup_and_goto_ptr();
27809baade8dSMichael Rolnik             break;
278136027c70SRichard Henderson         }
278236027c70SRichard Henderson         /* fall through */
27839baade8dSMichael Rolnik     case DISAS_EXIT:
27849baade8dSMichael Rolnik         tcg_gen_exit_tb(NULL, 0);
27859baade8dSMichael Rolnik         break;
27869baade8dSMichael Rolnik     default:
27879baade8dSMichael Rolnik         g_assert_not_reached();
27889baade8dSMichael Rolnik     }
27899d8caa67SMichael Rolnik }
27903fbd28d8SRichard Henderson 
avr_tr_disas_log(const DisasContextBase * dcbase,CPUState * cs,FILE * logfile)27918eb806a7SRichard Henderson static void avr_tr_disas_log(const DisasContextBase *dcbase,
27928eb806a7SRichard Henderson                              CPUState *cs, FILE *logfile)
27933fbd28d8SRichard Henderson {
27948eb806a7SRichard Henderson     fprintf(logfile, "IN: %s\n", lookup_symbol(dcbase->pc_first));
27958eb806a7SRichard Henderson     target_disas(logfile, cs, dcbase->pc_first, dcbase->tb->size);
27963fbd28d8SRichard Henderson }
27973fbd28d8SRichard Henderson 
27983fbd28d8SRichard Henderson static const TranslatorOps avr_tr_ops = {
27993fbd28d8SRichard Henderson     .init_disas_context = avr_tr_init_disas_context,
28003fbd28d8SRichard Henderson     .tb_start           = avr_tr_tb_start,
28013fbd28d8SRichard Henderson     .insn_start         = avr_tr_insn_start,
28023fbd28d8SRichard Henderson     .translate_insn     = avr_tr_translate_insn,
28033fbd28d8SRichard Henderson     .tb_stop            = avr_tr_tb_stop,
28043fbd28d8SRichard Henderson     .disas_log          = avr_tr_disas_log,
28053fbd28d8SRichard Henderson };
28063fbd28d8SRichard Henderson 
gen_intermediate_code(CPUState * cs,TranslationBlock * tb,int * max_insns,target_ulong pc,void * host_pc)2807597f9b2dSRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int *max_insns,
2808306c8721SRichard Henderson                            target_ulong pc, void *host_pc)
28093fbd28d8SRichard Henderson {
28103fbd28d8SRichard Henderson     DisasContext dc = { };
2811306c8721SRichard Henderson     translator_loop(cs, tb, max_insns, pc, host_pc, &avr_tr_ops, &dc.base);
28129baade8dSMichael Rolnik }
2813