xref: /openbmc/qemu/target/avr/translate.c (revision 5718cef0)
1e03feba0SMichael Rolnik /*
2e03feba0SMichael Rolnik  * QEMU AVR CPU
3e03feba0SMichael Rolnik  *
4e03feba0SMichael Rolnik  * Copyright (c) 2019-2020 Michael Rolnik
5e03feba0SMichael Rolnik  *
6e03feba0SMichael Rolnik  * This library is free software; you can redistribute it and/or
7e03feba0SMichael Rolnik  * modify it under the terms of the GNU Lesser General Public
8e03feba0SMichael Rolnik  * License as published by the Free Software Foundation; either
9e03feba0SMichael Rolnik  * version 2.1 of the License, or (at your option) any later version.
10e03feba0SMichael Rolnik  *
11e03feba0SMichael Rolnik  * This library is distributed in the hope that it will be useful,
12e03feba0SMichael Rolnik  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13e03feba0SMichael Rolnik  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14e03feba0SMichael Rolnik  * Lesser General Public License for more details.
15e03feba0SMichael Rolnik  *
16e03feba0SMichael Rolnik  * You should have received a copy of the GNU Lesser General Public
17e03feba0SMichael Rolnik  * License along with this library; if not, see
18e03feba0SMichael Rolnik  * <http://www.gnu.org/licenses/lgpl-2.1.html>
19e03feba0SMichael Rolnik  */
20e03feba0SMichael Rolnik 
21e03feba0SMichael Rolnik #include "qemu/osdep.h"
22e03feba0SMichael Rolnik #include "qemu/qemu-print.h"
23e03feba0SMichael Rolnik #include "tcg/tcg.h"
24e03feba0SMichael Rolnik #include "cpu.h"
25e03feba0SMichael Rolnik #include "exec/exec-all.h"
26e03feba0SMichael Rolnik #include "tcg/tcg-op.h"
27e03feba0SMichael Rolnik #include "exec/cpu_ldst.h"
28e03feba0SMichael Rolnik #include "exec/helper-proto.h"
29e03feba0SMichael Rolnik #include "exec/helper-gen.h"
30e03feba0SMichael Rolnik #include "exec/log.h"
31e03feba0SMichael Rolnik #include "exec/translator.h"
32e03feba0SMichael Rolnik #include "exec/gen-icount.h"
33e03feba0SMichael Rolnik 
34e03feba0SMichael Rolnik /*
35e03feba0SMichael Rolnik  *  Define if you want a BREAK instruction translated to a breakpoint
36e03feba0SMichael Rolnik  *  Active debugging connection is assumed
37e03feba0SMichael Rolnik  *  This is for
38e03feba0SMichael Rolnik  *  https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tests
39e03feba0SMichael Rolnik  *  tests
40e03feba0SMichael Rolnik  */
41e03feba0SMichael Rolnik #undef BREAKPOINT_ON_BREAK
42e03feba0SMichael Rolnik 
43e03feba0SMichael Rolnik static TCGv cpu_pc;
44e03feba0SMichael Rolnik 
45e03feba0SMichael Rolnik static TCGv cpu_Cf;
46e03feba0SMichael Rolnik static TCGv cpu_Zf;
47e03feba0SMichael Rolnik static TCGv cpu_Nf;
48e03feba0SMichael Rolnik static TCGv cpu_Vf;
49e03feba0SMichael Rolnik static TCGv cpu_Sf;
50e03feba0SMichael Rolnik static TCGv cpu_Hf;
51e03feba0SMichael Rolnik static TCGv cpu_Tf;
52e03feba0SMichael Rolnik static TCGv cpu_If;
53e03feba0SMichael Rolnik 
54e03feba0SMichael Rolnik static TCGv cpu_rampD;
55e03feba0SMichael Rolnik static TCGv cpu_rampX;
56e03feba0SMichael Rolnik static TCGv cpu_rampY;
57e03feba0SMichael Rolnik static TCGv cpu_rampZ;
58e03feba0SMichael Rolnik 
59e03feba0SMichael Rolnik static TCGv cpu_r[NUMBER_OF_CPU_REGISTERS];
60e03feba0SMichael Rolnik static TCGv cpu_eind;
61e03feba0SMichael Rolnik static TCGv cpu_sp;
62e03feba0SMichael Rolnik 
63e03feba0SMichael Rolnik static TCGv cpu_skip;
64e03feba0SMichael Rolnik 
65e03feba0SMichael Rolnik static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = {
66e03feba0SMichael Rolnik     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
67e03feba0SMichael Rolnik     "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
68e03feba0SMichael Rolnik     "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
69e03feba0SMichael Rolnik     "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
70e03feba0SMichael Rolnik };
71e03feba0SMichael Rolnik #define REG(x) (cpu_r[x])
72e03feba0SMichael Rolnik 
73e03feba0SMichael Rolnik enum {
74e03feba0SMichael Rolnik     DISAS_EXIT   = DISAS_TARGET_0,  /* We want return to the cpu main loop.  */
75e03feba0SMichael Rolnik     DISAS_LOOKUP = DISAS_TARGET_1,  /* We have a variable condition exit.  */
76e03feba0SMichael Rolnik     DISAS_CHAIN  = DISAS_TARGET_2,  /* We have a single condition exit.  */
77e03feba0SMichael Rolnik };
78e03feba0SMichael Rolnik 
79e03feba0SMichael Rolnik typedef struct DisasContext DisasContext;
80e03feba0SMichael Rolnik 
81e03feba0SMichael Rolnik /* This is the state at translation time. */
82e03feba0SMichael Rolnik struct DisasContext {
83e03feba0SMichael Rolnik     TranslationBlock *tb;
84e03feba0SMichael Rolnik 
85e03feba0SMichael Rolnik     CPUAVRState *env;
86e03feba0SMichael Rolnik     CPUState *cs;
87e03feba0SMichael Rolnik 
88e03feba0SMichael Rolnik     target_long npc;
89e03feba0SMichael Rolnik     uint32_t opcode;
90e03feba0SMichael Rolnik 
91e03feba0SMichael Rolnik     /* Routine used to access memory */
92e03feba0SMichael Rolnik     int memidx;
93e03feba0SMichael Rolnik     int bstate;
94e03feba0SMichael Rolnik     int singlestep;
95e03feba0SMichael Rolnik 
96e03feba0SMichael Rolnik     /*
97e03feba0SMichael Rolnik      * some AVR instructions can make the following instruction to be skipped
98e03feba0SMichael Rolnik      * Let's name those instructions
99e03feba0SMichael Rolnik      *     A   - instruction that can skip the next one
100e03feba0SMichael Rolnik      *     B   - instruction that can be skipped. this depends on execution of A
101e03feba0SMichael Rolnik      * there are two scenarios
102e03feba0SMichael Rolnik      * 1. A and B belong to the same translation block
103e03feba0SMichael Rolnik      * 2. A is the last instruction in the translation block and B is the last
104e03feba0SMichael Rolnik      *
105e03feba0SMichael Rolnik      * following variables are used to simplify the skipping logic, they are
106e03feba0SMichael Rolnik      * used in the following manner (sketch)
107e03feba0SMichael Rolnik      *
108e03feba0SMichael Rolnik      * TCGLabel *skip_label = NULL;
109e03feba0SMichael Rolnik      * if (ctx.skip_cond != TCG_COND_NEVER) {
110e03feba0SMichael Rolnik      *     skip_label = gen_new_label();
111e03feba0SMichael Rolnik      *     tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label);
112e03feba0SMichael Rolnik      * }
113e03feba0SMichael Rolnik      *
114e03feba0SMichael Rolnik      * if (free_skip_var0) {
115e03feba0SMichael Rolnik      *     tcg_temp_free(skip_var0);
116e03feba0SMichael Rolnik      *     free_skip_var0 = false;
117e03feba0SMichael Rolnik      * }
118e03feba0SMichael Rolnik      *
119e03feba0SMichael Rolnik      * translate(&ctx);
120e03feba0SMichael Rolnik      *
121e03feba0SMichael Rolnik      * if (skip_label) {
122e03feba0SMichael Rolnik      *     gen_set_label(skip_label);
123e03feba0SMichael Rolnik      * }
124e03feba0SMichael Rolnik      */
125e03feba0SMichael Rolnik     TCGv skip_var0;
126e03feba0SMichael Rolnik     TCGv skip_var1;
127e03feba0SMichael Rolnik     TCGCond skip_cond;
128e03feba0SMichael Rolnik     bool free_skip_var0;
129e03feba0SMichael Rolnik };
130e03feba0SMichael Rolnik 
131865f3bb9SMichael Rolnik static int to_regs_16_31_by_one(DisasContext *ctx, int indx)
132865f3bb9SMichael Rolnik {
133865f3bb9SMichael Rolnik     return 16 + (indx % 16);
134865f3bb9SMichael Rolnik }
135865f3bb9SMichael Rolnik 
136865f3bb9SMichael Rolnik static int to_regs_16_23_by_one(DisasContext *ctx, int indx)
137865f3bb9SMichael Rolnik {
138865f3bb9SMichael Rolnik     return 16 + (indx % 8);
139865f3bb9SMichael Rolnik }
140865f3bb9SMichael Rolnik 
141865f3bb9SMichael Rolnik static int to_regs_24_30_by_two(DisasContext *ctx, int indx)
142865f3bb9SMichael Rolnik {
143865f3bb9SMichael Rolnik     return 24 + (indx % 4) * 2;
144865f3bb9SMichael Rolnik }
145865f3bb9SMichael Rolnik 
1469732b024SMichael Rolnik static int to_regs_00_30_by_two(DisasContext *ctx, int indx)
1479732b024SMichael Rolnik {
1489732b024SMichael Rolnik     return (indx % 16) * 2;
1499732b024SMichael Rolnik }
150865f3bb9SMichael Rolnik 
1519d316c75SMichael Rolnik static uint16_t next_word(DisasContext *ctx)
1529d316c75SMichael Rolnik {
1539d316c75SMichael Rolnik     return cpu_lduw_code(ctx->env, ctx->npc++ * 2);
1549d316c75SMichael Rolnik }
1559d316c75SMichael Rolnik 
1569d316c75SMichael Rolnik static int append_16(DisasContext *ctx, int x)
1579d316c75SMichael Rolnik {
1589d316c75SMichael Rolnik     return x << 16 | next_word(ctx);
1599d316c75SMichael Rolnik }
1609d316c75SMichael Rolnik 
161e03feba0SMichael Rolnik static bool avr_have_feature(DisasContext *ctx, int feature)
162e03feba0SMichael Rolnik {
163e03feba0SMichael Rolnik     if (!avr_feature(ctx->env, feature)) {
164e03feba0SMichael Rolnik         gen_helper_unsupported(cpu_env);
165e03feba0SMichael Rolnik         ctx->bstate = DISAS_NORETURN;
166e03feba0SMichael Rolnik         return false;
167e03feba0SMichael Rolnik     }
168e03feba0SMichael Rolnik     return true;
169e03feba0SMichael Rolnik }
170e03feba0SMichael Rolnik 
171e03feba0SMichael Rolnik static bool decode_insn(DisasContext *ctx, uint16_t insn);
172e03feba0SMichael Rolnik #include "decode_insn.inc.c"
173865f3bb9SMichael Rolnik 
174865f3bb9SMichael Rolnik /*
175865f3bb9SMichael Rolnik  * Arithmetic Instructions
176865f3bb9SMichael Rolnik  */
177865f3bb9SMichael Rolnik 
178865f3bb9SMichael Rolnik /*
179865f3bb9SMichael Rolnik  * Utility functions for updating status registers:
180865f3bb9SMichael Rolnik  *
181865f3bb9SMichael Rolnik  *   - gen_add_CHf()
182865f3bb9SMichael Rolnik  *   - gen_add_Vf()
183865f3bb9SMichael Rolnik  *   - gen_sub_CHf()
184865f3bb9SMichael Rolnik  *   - gen_sub_Vf()
185865f3bb9SMichael Rolnik  *   - gen_NSf()
186865f3bb9SMichael Rolnik  *   - gen_ZNSf()
187865f3bb9SMichael Rolnik  *
188865f3bb9SMichael Rolnik  */
189865f3bb9SMichael Rolnik 
190865f3bb9SMichael Rolnik static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr)
191865f3bb9SMichael Rolnik {
192865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
193865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
194865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
195865f3bb9SMichael Rolnik 
196865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */
197865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */
198865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */
199865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */
200865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t3);
201865f3bb9SMichael Rolnik 
202865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */
203865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */
204865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
205865f3bb9SMichael Rolnik 
206865f3bb9SMichael Rolnik     tcg_temp_free_i32(t3);
207865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
208865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
209865f3bb9SMichael Rolnik }
210865f3bb9SMichael Rolnik 
211865f3bb9SMichael Rolnik static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
212865f3bb9SMichael Rolnik {
213865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
214865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
215865f3bb9SMichael Rolnik 
216865f3bb9SMichael Rolnik     /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */
217865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & ~(Rd ^ Rr) */
218865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
219865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
220865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t1, t1, t2);
221865f3bb9SMichael Rolnik 
222865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
223865f3bb9SMichael Rolnik 
224865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
225865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
226865f3bb9SMichael Rolnik }
227865f3bb9SMichael Rolnik 
228865f3bb9SMichael Rolnik static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
229865f3bb9SMichael Rolnik {
230865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
231865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
232865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
233865f3bb9SMichael Rolnik 
234865f3bb9SMichael Rolnik     tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */
235865f3bb9SMichael Rolnik     tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */
236865f3bb9SMichael Rolnik     tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */
237865f3bb9SMichael Rolnik     tcg_gen_and_tl(t3, t3, R);
238865f3bb9SMichael Rolnik     tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */
239865f3bb9SMichael Rolnik 
240865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */
241865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */
242865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
243865f3bb9SMichael Rolnik 
244865f3bb9SMichael Rolnik     tcg_temp_free_i32(t3);
245865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
246865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
247865f3bb9SMichael Rolnik }
248865f3bb9SMichael Rolnik 
249865f3bb9SMichael Rolnik static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
250865f3bb9SMichael Rolnik {
251865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
252865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
253865f3bb9SMichael Rolnik 
254865f3bb9SMichael Rolnik     /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */
255865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & (Rd ^ R) */
256865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
257865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
258865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, t1, t2);
259865f3bb9SMichael Rolnik 
260865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
261865f3bb9SMichael Rolnik 
262865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
263865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
264865f3bb9SMichael Rolnik }
265865f3bb9SMichael Rolnik 
266865f3bb9SMichael Rolnik static void gen_NSf(TCGv R)
267865f3bb9SMichael Rolnik {
268865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
269865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
270865f3bb9SMichael Rolnik }
271865f3bb9SMichael Rolnik 
272865f3bb9SMichael Rolnik static void gen_ZNSf(TCGv R)
273865f3bb9SMichael Rolnik {
274865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
275865f3bb9SMichael Rolnik 
276865f3bb9SMichael Rolnik     /* update status register */
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 
281865f3bb9SMichael Rolnik /*
282865f3bb9SMichael Rolnik  *  Adds two registers without the C Flag and places the result in the
283865f3bb9SMichael Rolnik  *  destination register Rd.
284865f3bb9SMichael Rolnik  */
285865f3bb9SMichael Rolnik static bool trans_ADD(DisasContext *ctx, arg_ADD *a)
286865f3bb9SMichael Rolnik {
287865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
288865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
289865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
290865f3bb9SMichael Rolnik 
291865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */
292865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
293865f3bb9SMichael Rolnik 
294865f3bb9SMichael Rolnik     /* update status register */
295865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
296865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
297865f3bb9SMichael Rolnik     gen_ZNSf(R);
298865f3bb9SMichael Rolnik 
299865f3bb9SMichael Rolnik     /* update output registers */
300865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
301865f3bb9SMichael Rolnik 
302865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
303865f3bb9SMichael Rolnik 
304865f3bb9SMichael Rolnik     return true;
305865f3bb9SMichael Rolnik }
306865f3bb9SMichael Rolnik 
307865f3bb9SMichael Rolnik /*
308865f3bb9SMichael Rolnik  *  Adds two registers and the contents of the C Flag and places the result in
309865f3bb9SMichael Rolnik  *  the destination register Rd.
310865f3bb9SMichael Rolnik  */
311865f3bb9SMichael Rolnik static bool trans_ADC(DisasContext *ctx, arg_ADC *a)
312865f3bb9SMichael Rolnik {
313865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
314865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
315865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
316865f3bb9SMichael Rolnik 
317865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */
318865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, R, cpu_Cf);
319865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
320865f3bb9SMichael Rolnik 
321865f3bb9SMichael Rolnik     /* update status register */
322865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
323865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
324865f3bb9SMichael Rolnik     gen_ZNSf(R);
325865f3bb9SMichael Rolnik 
326865f3bb9SMichael Rolnik     /* update output registers */
327865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
328865f3bb9SMichael Rolnik 
329865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
330865f3bb9SMichael Rolnik 
331865f3bb9SMichael Rolnik     return true;
332865f3bb9SMichael Rolnik }
333865f3bb9SMichael Rolnik 
334865f3bb9SMichael Rolnik /*
335865f3bb9SMichael Rolnik  *  Adds an immediate value (0 - 63) to a register pair and places the result
336865f3bb9SMichael Rolnik  *  in the register pair. This instruction operates on the upper four register
337865f3bb9SMichael Rolnik  *  pairs, and is well suited for operations on the pointer registers.  This
338865f3bb9SMichael Rolnik  *  instruction is not available in all devices. Refer to the device specific
339865f3bb9SMichael Rolnik  *  instruction set summary.
340865f3bb9SMichael Rolnik  */
341865f3bb9SMichael Rolnik static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a)
342865f3bb9SMichael Rolnik {
343865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
344865f3bb9SMichael Rolnik         return true;
345865f3bb9SMichael Rolnik     }
346865f3bb9SMichael Rolnik 
347865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
348865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
349865f3bb9SMichael Rolnik     int Imm = (a->imm);
350865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
351865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
352865f3bb9SMichael Rolnik 
353865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
354865f3bb9SMichael Rolnik     tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */
355865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
356865f3bb9SMichael Rolnik 
357865f3bb9SMichael Rolnik     /* update status register */
358865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
359865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15);
360865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */
361865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15);
362865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
363865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
364865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */
365865f3bb9SMichael Rolnik 
366865f3bb9SMichael Rolnik     /* update output registers */
367865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
368865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
369865f3bb9SMichael Rolnik 
370865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rd);
371865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
372865f3bb9SMichael Rolnik 
373865f3bb9SMichael Rolnik     return true;
374865f3bb9SMichael Rolnik }
375865f3bb9SMichael Rolnik 
376865f3bb9SMichael Rolnik /*
377865f3bb9SMichael Rolnik  *  Subtracts two registers and places the result in the destination
378865f3bb9SMichael Rolnik  *  register Rd.
379865f3bb9SMichael Rolnik  */
380865f3bb9SMichael Rolnik static bool trans_SUB(DisasContext *ctx, arg_SUB *a)
381865f3bb9SMichael Rolnik {
382865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
383865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
384865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
385865f3bb9SMichael Rolnik 
386865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
387865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
388865f3bb9SMichael Rolnik 
389865f3bb9SMichael Rolnik     /* update status register */
390865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
391865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
392865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
393865f3bb9SMichael Rolnik     gen_ZNSf(R);
394865f3bb9SMichael Rolnik 
395865f3bb9SMichael Rolnik     /* update output registers */
396865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
397865f3bb9SMichael Rolnik 
398865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
399865f3bb9SMichael Rolnik 
400865f3bb9SMichael Rolnik     return true;
401865f3bb9SMichael Rolnik }
402865f3bb9SMichael Rolnik 
403865f3bb9SMichael Rolnik /*
404865f3bb9SMichael Rolnik  *  Subtracts a register and a constant and places the result in the
405865f3bb9SMichael Rolnik  *  destination register Rd. This instruction is working on Register R16 to R31
406865f3bb9SMichael Rolnik  *  and is very well suited for operations on the X, Y, and Z-pointers.
407865f3bb9SMichael Rolnik  */
408865f3bb9SMichael Rolnik static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a)
409865f3bb9SMichael Rolnik {
410865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
411865f3bb9SMichael Rolnik     TCGv Rr = tcg_const_i32(a->imm);
412865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
413865f3bb9SMichael Rolnik 
414865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */
415865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
416865f3bb9SMichael Rolnik 
417865f3bb9SMichael Rolnik     /* update status register */
418865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
419865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
420865f3bb9SMichael Rolnik     gen_ZNSf(R);
421865f3bb9SMichael Rolnik 
422865f3bb9SMichael Rolnik     /* update output registers */
423865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
424865f3bb9SMichael Rolnik 
425865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
426865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rr);
427865f3bb9SMichael Rolnik 
428865f3bb9SMichael Rolnik     return true;
429865f3bb9SMichael Rolnik }
430865f3bb9SMichael Rolnik 
431865f3bb9SMichael Rolnik /*
432865f3bb9SMichael Rolnik  *  Subtracts two registers and subtracts with the C Flag and places the
433865f3bb9SMichael Rolnik  *  result in the destination register Rd.
434865f3bb9SMichael Rolnik  */
435865f3bb9SMichael Rolnik static bool trans_SBC(DisasContext *ctx, arg_SBC *a)
436865f3bb9SMichael Rolnik {
437865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
438865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
439865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
440865f3bb9SMichael Rolnik     TCGv zero = tcg_const_i32(0);
441865f3bb9SMichael Rolnik 
442865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
443865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
444865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
445865f3bb9SMichael Rolnik 
446865f3bb9SMichael Rolnik     /* update status register */
447865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
448865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
449865f3bb9SMichael Rolnik     gen_NSf(R);
450865f3bb9SMichael Rolnik 
451865f3bb9SMichael Rolnik     /*
452865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
453865f3bb9SMichael Rolnik      * cleared otherwise.
454865f3bb9SMichael Rolnik      */
455865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
456865f3bb9SMichael Rolnik 
457865f3bb9SMichael Rolnik     /* update output registers */
458865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
459865f3bb9SMichael Rolnik 
460865f3bb9SMichael Rolnik     tcg_temp_free_i32(zero);
461865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
462865f3bb9SMichael Rolnik 
463865f3bb9SMichael Rolnik     return true;
464865f3bb9SMichael Rolnik }
465865f3bb9SMichael Rolnik 
466865f3bb9SMichael Rolnik /*
467865f3bb9SMichael Rolnik  *  SBCI -- Subtract Immediate with Carry
468865f3bb9SMichael Rolnik  */
469865f3bb9SMichael Rolnik static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a)
470865f3bb9SMichael Rolnik {
471865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
472865f3bb9SMichael Rolnik     TCGv Rr = tcg_const_i32(a->imm);
473865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
474865f3bb9SMichael Rolnik     TCGv zero = tcg_const_i32(0);
475865f3bb9SMichael Rolnik 
476865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
477865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
478865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
479865f3bb9SMichael Rolnik 
480865f3bb9SMichael Rolnik     /* update status register */
481865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
482865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
483865f3bb9SMichael Rolnik     gen_NSf(R);
484865f3bb9SMichael Rolnik 
485865f3bb9SMichael Rolnik     /*
486865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
487865f3bb9SMichael Rolnik      * cleared otherwise.
488865f3bb9SMichael Rolnik      */
489865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
490865f3bb9SMichael Rolnik 
491865f3bb9SMichael Rolnik     /* update output registers */
492865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
493865f3bb9SMichael Rolnik 
494865f3bb9SMichael Rolnik     tcg_temp_free_i32(zero);
495865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
496865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rr);
497865f3bb9SMichael Rolnik 
498865f3bb9SMichael Rolnik     return true;
499865f3bb9SMichael Rolnik }
500865f3bb9SMichael Rolnik 
501865f3bb9SMichael Rolnik /*
502865f3bb9SMichael Rolnik  *  Subtracts an immediate value (0-63) from a register pair and places the
503865f3bb9SMichael Rolnik  *  result in the register pair. This instruction operates on the upper four
504865f3bb9SMichael Rolnik  *  register pairs, and is well suited for operations on the Pointer Registers.
505865f3bb9SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
506865f3bb9SMichael Rolnik  *  specific instruction set summary.
507865f3bb9SMichael Rolnik  */
508865f3bb9SMichael Rolnik static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a)
509865f3bb9SMichael Rolnik {
510865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
511865f3bb9SMichael Rolnik         return true;
512865f3bb9SMichael Rolnik     }
513865f3bb9SMichael Rolnik 
514865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
515865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
516865f3bb9SMichael Rolnik     int Imm = (a->imm);
517865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
518865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
519865f3bb9SMichael Rolnik 
520865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
521865f3bb9SMichael Rolnik     tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */
522865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
523865f3bb9SMichael Rolnik 
524865f3bb9SMichael Rolnik     /* update status register */
525865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, R, Rd);
526865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */
527865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, Rd, R);
528865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */
529865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
530865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
531865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
532865f3bb9SMichael Rolnik 
533865f3bb9SMichael Rolnik     /* update output registers */
534865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
535865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
536865f3bb9SMichael Rolnik 
537865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rd);
538865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
539865f3bb9SMichael Rolnik 
540865f3bb9SMichael Rolnik     return true;
541865f3bb9SMichael Rolnik }
542865f3bb9SMichael Rolnik 
543865f3bb9SMichael Rolnik /*
544865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and register
545865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
546865f3bb9SMichael Rolnik  */
547865f3bb9SMichael Rolnik static bool trans_AND(DisasContext *ctx, arg_AND *a)
548865f3bb9SMichael Rolnik {
549865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
550865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
551865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
552865f3bb9SMichael Rolnik 
553865f3bb9SMichael Rolnik     tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */
554865f3bb9SMichael Rolnik 
555865f3bb9SMichael Rolnik     /* update status register */
556865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
557865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
558865f3bb9SMichael Rolnik     gen_ZNSf(R);
559865f3bb9SMichael Rolnik 
560865f3bb9SMichael Rolnik     /* update output registers */
561865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
562865f3bb9SMichael Rolnik 
563865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
564865f3bb9SMichael Rolnik 
565865f3bb9SMichael Rolnik     return true;
566865f3bb9SMichael Rolnik }
567865f3bb9SMichael Rolnik 
568865f3bb9SMichael Rolnik /*
569865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and a constant
570865f3bb9SMichael Rolnik  *  and places the result in the destination register Rd.
571865f3bb9SMichael Rolnik  */
572865f3bb9SMichael Rolnik static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a)
573865f3bb9SMichael Rolnik {
574865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
575865f3bb9SMichael Rolnik     int Imm = (a->imm);
576865f3bb9SMichael Rolnik 
577865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */
578865f3bb9SMichael Rolnik 
579865f3bb9SMichael Rolnik     /* update status register */
580865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
581865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
582865f3bb9SMichael Rolnik 
583865f3bb9SMichael Rolnik     return true;
584865f3bb9SMichael Rolnik }
585865f3bb9SMichael Rolnik 
586865f3bb9SMichael Rolnik /*
587865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and register
588865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
589865f3bb9SMichael Rolnik  */
590865f3bb9SMichael Rolnik static bool trans_OR(DisasContext *ctx, arg_OR *a)
591865f3bb9SMichael Rolnik {
592865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
593865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
594865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
595865f3bb9SMichael Rolnik 
596865f3bb9SMichael Rolnik     tcg_gen_or_tl(R, Rd, Rr);
597865f3bb9SMichael Rolnik 
598865f3bb9SMichael Rolnik     /* update status register */
599865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
600865f3bb9SMichael Rolnik     gen_ZNSf(R);
601865f3bb9SMichael Rolnik 
602865f3bb9SMichael Rolnik     /* update output registers */
603865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
604865f3bb9SMichael Rolnik 
605865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
606865f3bb9SMichael Rolnik 
607865f3bb9SMichael Rolnik     return true;
608865f3bb9SMichael Rolnik }
609865f3bb9SMichael Rolnik 
610865f3bb9SMichael Rolnik /*
611865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and a
612865f3bb9SMichael Rolnik  *  constant and places the result in the destination register Rd.
613865f3bb9SMichael Rolnik  */
614865f3bb9SMichael Rolnik static bool trans_ORI(DisasContext *ctx, arg_ORI *a)
615865f3bb9SMichael Rolnik {
616865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
617865f3bb9SMichael Rolnik     int Imm = (a->imm);
618865f3bb9SMichael Rolnik 
619865f3bb9SMichael Rolnik     tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */
620865f3bb9SMichael Rolnik 
621865f3bb9SMichael Rolnik     /* update status register */
622865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
623865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
624865f3bb9SMichael Rolnik 
625865f3bb9SMichael Rolnik     return true;
626865f3bb9SMichael Rolnik }
627865f3bb9SMichael Rolnik 
628865f3bb9SMichael Rolnik /*
629865f3bb9SMichael Rolnik  *  Performs the logical EOR between the contents of register Rd and
630865f3bb9SMichael Rolnik  *  register Rr and places the result in the destination register Rd.
631865f3bb9SMichael Rolnik  */
632865f3bb9SMichael Rolnik static bool trans_EOR(DisasContext *ctx, arg_EOR *a)
633865f3bb9SMichael Rolnik {
634865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
635865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
636865f3bb9SMichael Rolnik 
637865f3bb9SMichael Rolnik     tcg_gen_xor_tl(Rd, Rd, Rr);
638865f3bb9SMichael Rolnik 
639865f3bb9SMichael Rolnik     /* update status register */
640865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
641865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
642865f3bb9SMichael Rolnik 
643865f3bb9SMichael Rolnik     return true;
644865f3bb9SMichael Rolnik }
645865f3bb9SMichael Rolnik 
646865f3bb9SMichael Rolnik /*
647865f3bb9SMichael Rolnik  *  Clears the specified bits in register Rd. Performs the logical AND
648865f3bb9SMichael Rolnik  *  between the contents of register Rd and the complement of the constant mask
649865f3bb9SMichael Rolnik  *  K. The result will be placed in register Rd.
650865f3bb9SMichael Rolnik  */
651865f3bb9SMichael Rolnik static bool trans_COM(DisasContext *ctx, arg_COM *a)
652865f3bb9SMichael Rolnik {
653865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
654865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
655865f3bb9SMichael Rolnik 
656865f3bb9SMichael Rolnik     tcg_gen_xori_tl(Rd, Rd, 0xff);
657865f3bb9SMichael Rolnik 
658865f3bb9SMichael Rolnik     /* update status register */
659865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */
660865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
661865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
662865f3bb9SMichael Rolnik 
663865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
664865f3bb9SMichael Rolnik 
665865f3bb9SMichael Rolnik     return true;
666865f3bb9SMichael Rolnik }
667865f3bb9SMichael Rolnik 
668865f3bb9SMichael Rolnik /*
669865f3bb9SMichael Rolnik  *  Replaces the contents of register Rd with its two's complement; the
670865f3bb9SMichael Rolnik  *  value $80 is left unchanged.
671865f3bb9SMichael Rolnik  */
672865f3bb9SMichael Rolnik static bool trans_NEG(DisasContext *ctx, arg_NEG *a)
673865f3bb9SMichael Rolnik {
674865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
675865f3bb9SMichael Rolnik     TCGv t0 = tcg_const_i32(0);
676865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
677865f3bb9SMichael Rolnik 
678865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */
679865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
680865f3bb9SMichael Rolnik 
681865f3bb9SMichael Rolnik     /* update status register */
682865f3bb9SMichael Rolnik     gen_sub_CHf(R, t0, Rd);
683865f3bb9SMichael Rolnik     gen_sub_Vf(R, t0, Rd);
684865f3bb9SMichael Rolnik     gen_ZNSf(R);
685865f3bb9SMichael Rolnik 
686865f3bb9SMichael Rolnik     /* update output registers */
687865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
688865f3bb9SMichael Rolnik 
689865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
690865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
691865f3bb9SMichael Rolnik 
692865f3bb9SMichael Rolnik     return true;
693865f3bb9SMichael Rolnik }
694865f3bb9SMichael Rolnik 
695865f3bb9SMichael Rolnik /*
696865f3bb9SMichael Rolnik  *  Adds one -1- to the contents of register Rd and places the result in the
697865f3bb9SMichael Rolnik  *  destination register Rd.  The C Flag in SREG is not affected by the
698865f3bb9SMichael Rolnik  *  operation, thus allowing the INC instruction to be used on a loop counter in
699865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned numbers, only
700865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently. When
701865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
702865f3bb9SMichael Rolnik  */
703865f3bb9SMichael Rolnik static bool trans_INC(DisasContext *ctx, arg_INC *a)
704865f3bb9SMichael Rolnik {
705865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
706865f3bb9SMichael Rolnik 
707865f3bb9SMichael Rolnik     tcg_gen_addi_tl(Rd, Rd, 1);
708865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff);
709865f3bb9SMichael Rolnik 
710865f3bb9SMichael Rolnik     /* update status register */
711865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */
712865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
713865f3bb9SMichael Rolnik 
714865f3bb9SMichael Rolnik     return true;
715865f3bb9SMichael Rolnik }
716865f3bb9SMichael Rolnik 
717865f3bb9SMichael Rolnik /*
718865f3bb9SMichael Rolnik  *  Subtracts one -1- from the contents of register Rd and places the result
719865f3bb9SMichael Rolnik  *  in the destination register Rd.  The C Flag in SREG is not affected by the
720865f3bb9SMichael Rolnik  *  operation, thus allowing the DEC instruction to be used on a loop counter in
721865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned values, only
722865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently.  When
723865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
724865f3bb9SMichael Rolnik  */
725865f3bb9SMichael Rolnik static bool trans_DEC(DisasContext *ctx, arg_DEC *a)
726865f3bb9SMichael Rolnik {
727865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
728865f3bb9SMichael Rolnik 
729865f3bb9SMichael Rolnik     tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
730865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
731865f3bb9SMichael Rolnik 
732865f3bb9SMichael Rolnik     /* update status register */
733865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */
734865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
735865f3bb9SMichael Rolnik 
736865f3bb9SMichael Rolnik     return true;
737865f3bb9SMichael Rolnik }
738865f3bb9SMichael Rolnik 
739865f3bb9SMichael Rolnik /*
740865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication.
741865f3bb9SMichael Rolnik  */
742865f3bb9SMichael Rolnik static bool trans_MUL(DisasContext *ctx, arg_MUL *a)
743865f3bb9SMichael Rolnik {
744865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
745865f3bb9SMichael Rolnik         return true;
746865f3bb9SMichael Rolnik     }
747865f3bb9SMichael Rolnik 
748865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
749865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
750865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
751865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
752865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
753865f3bb9SMichael Rolnik 
754865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
755865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
756865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
757865f3bb9SMichael Rolnik 
758865f3bb9SMichael Rolnik     /* update status register */
759865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
760865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
761865f3bb9SMichael Rolnik 
762865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
763865f3bb9SMichael Rolnik 
764865f3bb9SMichael Rolnik     return true;
765865f3bb9SMichael Rolnik }
766865f3bb9SMichael Rolnik 
767865f3bb9SMichael Rolnik /*
768865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication.
769865f3bb9SMichael Rolnik  */
770865f3bb9SMichael Rolnik static bool trans_MULS(DisasContext *ctx, arg_MULS *a)
771865f3bb9SMichael Rolnik {
772865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
773865f3bb9SMichael Rolnik         return true;
774865f3bb9SMichael Rolnik     }
775865f3bb9SMichael Rolnik 
776865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
777865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
778865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
779865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
780865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
781865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
782865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
783865f3bb9SMichael Rolnik 
784865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
785865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
786865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
787865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
788865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
789865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
790865f3bb9SMichael Rolnik 
791865f3bb9SMichael Rolnik     /* update status register */
792865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
793865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
794865f3bb9SMichael Rolnik 
795865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
796865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
797865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
798865f3bb9SMichael Rolnik 
799865f3bb9SMichael Rolnik     return true;
800865f3bb9SMichael Rolnik }
801865f3bb9SMichael Rolnik 
802865f3bb9SMichael Rolnik /*
803865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a
804865f3bb9SMichael Rolnik  *  signed and an unsigned number.
805865f3bb9SMichael Rolnik  */
806865f3bb9SMichael Rolnik static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a)
807865f3bb9SMichael Rolnik {
808865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
809865f3bb9SMichael Rolnik         return true;
810865f3bb9SMichael Rolnik     }
811865f3bb9SMichael Rolnik 
812865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
813865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
814865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
815865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
816865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
817865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
818865f3bb9SMichael Rolnik 
819865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
820865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
821865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */
822865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
823865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
824865f3bb9SMichael Rolnik 
825865f3bb9SMichael Rolnik     /* update status register */
826865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
827865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
828865f3bb9SMichael Rolnik 
829865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
830865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
831865f3bb9SMichael Rolnik 
832865f3bb9SMichael Rolnik     return true;
833865f3bb9SMichael Rolnik }
834865f3bb9SMichael Rolnik 
835865f3bb9SMichael Rolnik /*
836865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned
837865f3bb9SMichael Rolnik  *  multiplication and shifts the result one bit left.
838865f3bb9SMichael Rolnik  */
839865f3bb9SMichael Rolnik static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a)
840865f3bb9SMichael Rolnik {
841865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
842865f3bb9SMichael Rolnik         return true;
843865f3bb9SMichael Rolnik     }
844865f3bb9SMichael Rolnik 
845865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
846865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
847865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
848865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
849865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
850865f3bb9SMichael Rolnik 
851865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
852865f3bb9SMichael Rolnik 
853865f3bb9SMichael Rolnik     /* update status register */
854865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
855865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
856865f3bb9SMichael Rolnik 
857865f3bb9SMichael Rolnik     /* update output registers */
858865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
859865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
860865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
861865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
862865f3bb9SMichael Rolnik 
863865f3bb9SMichael Rolnik 
864865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
865865f3bb9SMichael Rolnik 
866865f3bb9SMichael Rolnik     return true;
867865f3bb9SMichael Rolnik }
868865f3bb9SMichael Rolnik 
869865f3bb9SMichael Rolnik /*
870865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
871865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
872865f3bb9SMichael Rolnik  */
873865f3bb9SMichael Rolnik static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a)
874865f3bb9SMichael Rolnik {
875865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
876865f3bb9SMichael Rolnik         return true;
877865f3bb9SMichael Rolnik     }
878865f3bb9SMichael Rolnik 
879865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
880865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
881865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
882865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
883865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
884865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
885865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
886865f3bb9SMichael Rolnik 
887865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
888865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
889865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
890865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
891865f3bb9SMichael Rolnik 
892865f3bb9SMichael Rolnik     /* update status register */
893865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
894865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
895865f3bb9SMichael Rolnik 
896865f3bb9SMichael Rolnik     /* update output registers */
897865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
898865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
899865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
900865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
901865f3bb9SMichael Rolnik 
902865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
903865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
904865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
905865f3bb9SMichael Rolnik 
906865f3bb9SMichael Rolnik     return true;
907865f3bb9SMichael Rolnik }
908865f3bb9SMichael Rolnik 
909865f3bb9SMichael Rolnik /*
910865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
911865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
912865f3bb9SMichael Rolnik  */
913865f3bb9SMichael Rolnik static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a)
914865f3bb9SMichael Rolnik {
915865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
916865f3bb9SMichael Rolnik         return true;
917865f3bb9SMichael Rolnik     }
918865f3bb9SMichael Rolnik 
919865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
920865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
921865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
922865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
923865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
924865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
925865f3bb9SMichael Rolnik 
926865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
927865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
928865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
929865f3bb9SMichael Rolnik 
930865f3bb9SMichael Rolnik     /* update status register */
931865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
932865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
933865f3bb9SMichael Rolnik 
934865f3bb9SMichael Rolnik     /* update output registers */
935865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
936865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
937865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
938865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
939865f3bb9SMichael Rolnik 
940865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
941865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
942865f3bb9SMichael Rolnik 
943865f3bb9SMichael Rolnik     return true;
944865f3bb9SMichael Rolnik }
945865f3bb9SMichael Rolnik 
946865f3bb9SMichael Rolnik /*
947865f3bb9SMichael Rolnik  *  The module is an instruction set extension to the AVR CPU, performing
948865f3bb9SMichael Rolnik  *  DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in
949865f3bb9SMichael Rolnik  *  the CPU register file, registers R0-R7, where LSB of data is placed in LSB
950865f3bb9SMichael Rolnik  *  of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including
951865f3bb9SMichael Rolnik  *  parity bits) is placed in registers R8- R15, organized in the register file
952865f3bb9SMichael Rolnik  *  with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES
953865f3bb9SMichael Rolnik  *  instruction performs one round in the DES algorithm. Sixteen rounds must be
954865f3bb9SMichael Rolnik  *  executed in increasing order to form the correct DES ciphertext or
955865f3bb9SMichael Rolnik  *  plaintext. Intermediate results are stored in the register file (R0-R15)
956865f3bb9SMichael Rolnik  *  after each DES instruction. The instruction's operand (K) determines which
957865f3bb9SMichael Rolnik  *  round is executed, and the half carry flag (H) determines whether encryption
958865f3bb9SMichael Rolnik  *  or decryption is performed.  The DES algorithm is described in
959865f3bb9SMichael Rolnik  *  "Specifications for the Data Encryption Standard" (Federal Information
960865f3bb9SMichael Rolnik  *  Processing Standards Publication 46). Intermediate results in this
961865f3bb9SMichael Rolnik  *  implementation differ from the standard because the initial permutation and
962865f3bb9SMichael Rolnik  *  the inverse initial permutation are performed each iteration. This does not
963865f3bb9SMichael Rolnik  *  affect the result in the final ciphertext or plaintext, but reduces
964865f3bb9SMichael Rolnik  *  execution time.
965865f3bb9SMichael Rolnik  */
966865f3bb9SMichael Rolnik static bool trans_DES(DisasContext *ctx, arg_DES *a)
967865f3bb9SMichael Rolnik {
968865f3bb9SMichael Rolnik     /* TODO */
969865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_DES)) {
970865f3bb9SMichael Rolnik         return true;
971865f3bb9SMichael Rolnik     }
972865f3bb9SMichael Rolnik 
973865f3bb9SMichael Rolnik     qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
974865f3bb9SMichael Rolnik 
975865f3bb9SMichael Rolnik     return true;
976865f3bb9SMichael Rolnik }
9779d316c75SMichael Rolnik 
9789d316c75SMichael Rolnik /*
9799d316c75SMichael Rolnik  * Branch Instructions
9809d316c75SMichael Rolnik  */
9819d316c75SMichael Rolnik static void gen_jmp_ez(DisasContext *ctx)
9829d316c75SMichael Rolnik {
9839d316c75SMichael Rolnik     tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
9849d316c75SMichael Rolnik     tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind);
9859d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
9869d316c75SMichael Rolnik }
9879d316c75SMichael Rolnik 
9889d316c75SMichael Rolnik static void gen_jmp_z(DisasContext *ctx)
9899d316c75SMichael Rolnik {
9909d316c75SMichael Rolnik     tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
9919d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
9929d316c75SMichael Rolnik }
9939d316c75SMichael Rolnik 
9949d316c75SMichael Rolnik static void gen_push_ret(DisasContext *ctx, int ret)
9959d316c75SMichael Rolnik {
9969d316c75SMichael Rolnik     if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
9979d316c75SMichael Rolnik 
9989d316c75SMichael Rolnik         TCGv t0 = tcg_const_i32((ret & 0x0000ff));
9999d316c75SMichael Rolnik 
10009d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB);
10019d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10029d316c75SMichael Rolnik 
10039d316c75SMichael Rolnik         tcg_temp_free_i32(t0);
10049d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
10059d316c75SMichael Rolnik 
10069d316c75SMichael Rolnik         TCGv t0 = tcg_const_i32((ret & 0x00ffff));
10079d316c75SMichael Rolnik 
10089d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10099d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10109d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10119d316c75SMichael Rolnik 
10129d316c75SMichael Rolnik         tcg_temp_free_i32(t0);
10139d316c75SMichael Rolnik 
10149d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
10159d316c75SMichael Rolnik 
10169d316c75SMichael Rolnik         TCGv lo = tcg_const_i32((ret & 0x0000ff));
10179d316c75SMichael Rolnik         TCGv hi = tcg_const_i32((ret & 0xffff00) >> 8);
10189d316c75SMichael Rolnik 
10199d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
10209d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 2);
10219d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10229d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10239d316c75SMichael Rolnik 
10249d316c75SMichael Rolnik         tcg_temp_free_i32(lo);
10259d316c75SMichael Rolnik         tcg_temp_free_i32(hi);
10269d316c75SMichael Rolnik     }
10279d316c75SMichael Rolnik }
10289d316c75SMichael Rolnik 
10299d316c75SMichael Rolnik static void gen_pop_ret(DisasContext *ctx, TCGv ret)
10309d316c75SMichael Rolnik {
10319d316c75SMichael Rolnik     if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
10329d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10339d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB);
10349d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
10359d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10369d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10379d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10389d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
10399d316c75SMichael Rolnik         TCGv lo = tcg_temp_new_i32();
10409d316c75SMichael Rolnik         TCGv hi = tcg_temp_new_i32();
10419d316c75SMichael Rolnik 
10429d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10439d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10449d316c75SMichael Rolnik 
10459d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 2);
10469d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
10479d316c75SMichael Rolnik 
10489d316c75SMichael Rolnik         tcg_gen_deposit_tl(ret, lo, hi, 8, 16);
10499d316c75SMichael Rolnik 
10509d316c75SMichael Rolnik         tcg_temp_free_i32(lo);
10519d316c75SMichael Rolnik         tcg_temp_free_i32(hi);
10529d316c75SMichael Rolnik     }
10539d316c75SMichael Rolnik }
10549d316c75SMichael Rolnik 
10559d316c75SMichael Rolnik static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
10569d316c75SMichael Rolnik {
10579d316c75SMichael Rolnik     TranslationBlock *tb = ctx->tb;
10589d316c75SMichael Rolnik 
10599d316c75SMichael Rolnik     if (ctx->singlestep == 0) {
10609d316c75SMichael Rolnik         tcg_gen_goto_tb(n);
10619d316c75SMichael Rolnik         tcg_gen_movi_i32(cpu_pc, dest);
10629d316c75SMichael Rolnik         tcg_gen_exit_tb(tb, n);
10639d316c75SMichael Rolnik     } else {
10649d316c75SMichael Rolnik         tcg_gen_movi_i32(cpu_pc, dest);
10659d316c75SMichael Rolnik         gen_helper_debug(cpu_env);
10669d316c75SMichael Rolnik         tcg_gen_exit_tb(NULL, 0);
10679d316c75SMichael Rolnik     }
10689d316c75SMichael Rolnik     ctx->bstate = DISAS_NORETURN;
10699d316c75SMichael Rolnik }
10709d316c75SMichael Rolnik 
10719d316c75SMichael Rolnik /*
10729d316c75SMichael Rolnik  *  Relative jump to an address within PC - 2K +1 and PC + 2K (words). For
10739d316c75SMichael Rolnik  *  AVR microcontrollers with Program memory not exceeding 4K words (8KB) this
10749d316c75SMichael Rolnik  *  instruction can address the entire memory from every address location. See
10759d316c75SMichael Rolnik  *  also JMP.
10769d316c75SMichael Rolnik  */
10779d316c75SMichael Rolnik static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a)
10789d316c75SMichael Rolnik {
10799d316c75SMichael Rolnik     int dst = ctx->npc + a->imm;
10809d316c75SMichael Rolnik 
10819d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, dst);
10829d316c75SMichael Rolnik 
10839d316c75SMichael Rolnik     return true;
10849d316c75SMichael Rolnik }
10859d316c75SMichael Rolnik 
10869d316c75SMichael Rolnik /*
10879d316c75SMichael Rolnik  *  Indirect jump to the address pointed to by the Z (16 bits) Pointer
10889d316c75SMichael Rolnik  *  Register in the Register File. The Z-pointer Register is 16 bits wide and
10899d316c75SMichael Rolnik  *  allows jump within the lowest 64K words (128KB) section of Program memory.
10909d316c75SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
10919d316c75SMichael Rolnik  *  specific instruction set summary.
10929d316c75SMichael Rolnik  */
10939d316c75SMichael Rolnik static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a)
10949d316c75SMichael Rolnik {
10959d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) {
10969d316c75SMichael Rolnik         return true;
10979d316c75SMichael Rolnik     }
10989d316c75SMichael Rolnik 
10999d316c75SMichael Rolnik     gen_jmp_z(ctx);
11009d316c75SMichael Rolnik 
11019d316c75SMichael Rolnik     return true;
11029d316c75SMichael Rolnik }
11039d316c75SMichael Rolnik 
11049d316c75SMichael Rolnik /*
11059d316c75SMichael Rolnik  *  Indirect jump to the address pointed to by the Z (16 bits) Pointer
11069d316c75SMichael Rolnik  *  Register in the Register File and the EIND Register in the I/O space. This
11079d316c75SMichael Rolnik  *  instruction allows for indirect jumps to the entire 4M (words) Program
11089d316c75SMichael Rolnik  *  memory space. See also IJMP.  This instruction is not available in all
11099d316c75SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.
11109d316c75SMichael Rolnik  */
11119d316c75SMichael Rolnik static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a)
11129d316c75SMichael Rolnik {
11139d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) {
11149d316c75SMichael Rolnik         return true;
11159d316c75SMichael Rolnik     }
11169d316c75SMichael Rolnik 
11179d316c75SMichael Rolnik     gen_jmp_ez(ctx);
11189d316c75SMichael Rolnik     return true;
11199d316c75SMichael Rolnik }
11209d316c75SMichael Rolnik 
11219d316c75SMichael Rolnik /*
11229d316c75SMichael Rolnik  *  Jump to an address within the entire 4M (words) Program memory. See also
11239d316c75SMichael Rolnik  *  RJMP.  This instruction is not available in all devices. Refer to the device
11249d316c75SMichael Rolnik  *  specific instruction set summary.0
11259d316c75SMichael Rolnik  */
11269d316c75SMichael Rolnik static bool trans_JMP(DisasContext *ctx, arg_JMP *a)
11279d316c75SMichael Rolnik {
11289d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) {
11299d316c75SMichael Rolnik         return true;
11309d316c75SMichael Rolnik     }
11319d316c75SMichael Rolnik 
11329d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, a->imm);
11339d316c75SMichael Rolnik 
11349d316c75SMichael Rolnik     return true;
11359d316c75SMichael Rolnik }
11369d316c75SMichael Rolnik 
11379d316c75SMichael Rolnik /*
11389d316c75SMichael Rolnik  *  Relative call to an address within PC - 2K + 1 and PC + 2K (words). The
11399d316c75SMichael Rolnik  *  return address (the instruction after the RCALL) is stored onto the Stack.
11409d316c75SMichael Rolnik  *  See also CALL. For AVR microcontrollers with Program memory not exceeding 4K
11419d316c75SMichael Rolnik  *  words (8KB) this instruction can address the entire memory from every
11429d316c75SMichael Rolnik  *  address location. The Stack Pointer uses a post-decrement scheme during
11439d316c75SMichael Rolnik  *  RCALL.
11449d316c75SMichael Rolnik  */
11459d316c75SMichael Rolnik static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a)
11469d316c75SMichael Rolnik {
11479d316c75SMichael Rolnik     int ret = ctx->npc;
11489d316c75SMichael Rolnik     int dst = ctx->npc + a->imm;
11499d316c75SMichael Rolnik 
11509d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
11519d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, dst);
11529d316c75SMichael Rolnik 
11539d316c75SMichael Rolnik     return true;
11549d316c75SMichael Rolnik }
11559d316c75SMichael Rolnik 
11569d316c75SMichael Rolnik /*
11579d316c75SMichael Rolnik  *  Calls to a subroutine within the entire 4M (words) Program memory. The
11589d316c75SMichael Rolnik  *  return address (to the instruction after the CALL) will be stored onto the
11599d316c75SMichael Rolnik  *  Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme during
11609d316c75SMichael Rolnik  *  CALL.  This instruction is not available in all devices. Refer to the device
11619d316c75SMichael Rolnik  *  specific instruction set summary.
11629d316c75SMichael Rolnik  */
11639d316c75SMichael Rolnik static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a)
11649d316c75SMichael Rolnik {
11659d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) {
11669d316c75SMichael Rolnik         return true;
11679d316c75SMichael Rolnik     }
11689d316c75SMichael Rolnik 
11699d316c75SMichael Rolnik     int ret = ctx->npc;
11709d316c75SMichael Rolnik 
11719d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
11729d316c75SMichael Rolnik     gen_jmp_z(ctx);
11739d316c75SMichael Rolnik 
11749d316c75SMichael Rolnik     return true;
11759d316c75SMichael Rolnik }
11769d316c75SMichael Rolnik 
11779d316c75SMichael Rolnik /*
11789d316c75SMichael Rolnik  *  Indirect call of a subroutine pointed to by the Z (16 bits) Pointer
11799d316c75SMichael Rolnik  *  Register in the Register File and the EIND Register in the I/O space. This
11809d316c75SMichael Rolnik  *  instruction allows for indirect calls to the entire 4M (words) Program
11819d316c75SMichael Rolnik  *  memory space. See also ICALL. The Stack Pointer uses a post-decrement scheme
11829d316c75SMichael Rolnik  *  during EICALL.  This instruction is not available in all devices. Refer to
11839d316c75SMichael Rolnik  *  the device specific instruction set summary.
11849d316c75SMichael Rolnik  */
11859d316c75SMichael Rolnik static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a)
11869d316c75SMichael Rolnik {
11879d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) {
11889d316c75SMichael Rolnik         return true;
11899d316c75SMichael Rolnik     }
11909d316c75SMichael Rolnik 
11919d316c75SMichael Rolnik     int ret = ctx->npc;
11929d316c75SMichael Rolnik 
11939d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
11949d316c75SMichael Rolnik     gen_jmp_ez(ctx);
11959d316c75SMichael Rolnik     return true;
11969d316c75SMichael Rolnik }
11979d316c75SMichael Rolnik 
11989d316c75SMichael Rolnik /*
11999d316c75SMichael Rolnik  *  Calls to a subroutine within the entire Program memory. The return
12009d316c75SMichael Rolnik  *  address (to the instruction after the CALL) will be stored onto the Stack.
12019d316c75SMichael Rolnik  *  (See also RCALL). The Stack Pointer uses a post-decrement scheme during
12029d316c75SMichael Rolnik  *  CALL.  This instruction is not available in all devices. Refer to the device
12039d316c75SMichael Rolnik  *  specific instruction set summary.
12049d316c75SMichael Rolnik  */
12059d316c75SMichael Rolnik static bool trans_CALL(DisasContext *ctx, arg_CALL *a)
12069d316c75SMichael Rolnik {
12079d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) {
12089d316c75SMichael Rolnik         return true;
12099d316c75SMichael Rolnik     }
12109d316c75SMichael Rolnik 
12119d316c75SMichael Rolnik     int Imm = a->imm;
12129d316c75SMichael Rolnik     int ret = ctx->npc;
12139d316c75SMichael Rolnik 
12149d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
12159d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, Imm);
12169d316c75SMichael Rolnik 
12179d316c75SMichael Rolnik     return true;
12189d316c75SMichael Rolnik }
12199d316c75SMichael Rolnik 
12209d316c75SMichael Rolnik /*
12219d316c75SMichael Rolnik  *  Returns from subroutine. The return address is loaded from the STACK.
12229d316c75SMichael Rolnik  *  The Stack Pointer uses a preincrement scheme during RET.
12239d316c75SMichael Rolnik  */
12249d316c75SMichael Rolnik static bool trans_RET(DisasContext *ctx, arg_RET *a)
12259d316c75SMichael Rolnik {
12269d316c75SMichael Rolnik     gen_pop_ret(ctx, cpu_pc);
12279d316c75SMichael Rolnik 
12289d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
12299d316c75SMichael Rolnik     return true;
12309d316c75SMichael Rolnik }
12319d316c75SMichael Rolnik 
12329d316c75SMichael Rolnik /*
12339d316c75SMichael Rolnik  *  Returns from interrupt. The return address is loaded from the STACK and
12349d316c75SMichael Rolnik  *  the Global Interrupt Flag is set.  Note that the Status Register is not
12359d316c75SMichael Rolnik  *  automatically stored when entering an interrupt routine, and it is not
12369d316c75SMichael Rolnik  *  restored when returning from an interrupt routine. This must be handled by
12379d316c75SMichael Rolnik  *  the application program. The Stack Pointer uses a pre-increment scheme
12389d316c75SMichael Rolnik  *  during RETI.
12399d316c75SMichael Rolnik  */
12409d316c75SMichael Rolnik static bool trans_RETI(DisasContext *ctx, arg_RETI *a)
12419d316c75SMichael Rolnik {
12429d316c75SMichael Rolnik     gen_pop_ret(ctx, cpu_pc);
12439d316c75SMichael Rolnik     tcg_gen_movi_tl(cpu_If, 1);
12449d316c75SMichael Rolnik 
12459d316c75SMichael Rolnik     /* Need to return to main loop to re-evaluate interrupts.  */
12469d316c75SMichael Rolnik     ctx->bstate = DISAS_EXIT;
12479d316c75SMichael Rolnik     return true;
12489d316c75SMichael Rolnik }
12499d316c75SMichael Rolnik 
12509d316c75SMichael Rolnik /*
12519d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr, and
12529d316c75SMichael Rolnik  *  skips the next instruction if Rd = Rr.
12539d316c75SMichael Rolnik  */
12549d316c75SMichael Rolnik static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a)
12559d316c75SMichael Rolnik {
12569d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
12579d316c75SMichael Rolnik     ctx->skip_var0 = cpu_r[a->rd];
12589d316c75SMichael Rolnik     ctx->skip_var1 = cpu_r[a->rr];
12599d316c75SMichael Rolnik     return true;
12609d316c75SMichael Rolnik }
12619d316c75SMichael Rolnik 
12629d316c75SMichael Rolnik /*
12639d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr.
12649d316c75SMichael Rolnik  *  None of the registers are changed. All conditional branches can be used
12659d316c75SMichael Rolnik  *  after this instruction.
12669d316c75SMichael Rolnik  */
12679d316c75SMichael Rolnik static bool trans_CP(DisasContext *ctx, arg_CP *a)
12689d316c75SMichael Rolnik {
12699d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
12709d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
12719d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
12729d316c75SMichael Rolnik 
12739d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
12749d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
12759d316c75SMichael Rolnik 
12769d316c75SMichael Rolnik     /* update status register */
12779d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
12789d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
12799d316c75SMichael Rolnik     gen_ZNSf(R);
12809d316c75SMichael Rolnik 
12819d316c75SMichael Rolnik     tcg_temp_free_i32(R);
12829d316c75SMichael Rolnik 
12839d316c75SMichael Rolnik     return true;
12849d316c75SMichael Rolnik }
12859d316c75SMichael Rolnik 
12869d316c75SMichael Rolnik /*
12879d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr and
12889d316c75SMichael Rolnik  *  also takes into account the previous carry. None of the registers are
12899d316c75SMichael Rolnik  *  changed. All conditional branches can be used after this instruction.
12909d316c75SMichael Rolnik  */
12919d316c75SMichael Rolnik static bool trans_CPC(DisasContext *ctx, arg_CPC *a)
12929d316c75SMichael Rolnik {
12939d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
12949d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
12959d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
12969d316c75SMichael Rolnik     TCGv zero = tcg_const_i32(0);
12979d316c75SMichael Rolnik 
12989d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
12999d316c75SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
13009d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
13019d316c75SMichael Rolnik     /* update status register */
13029d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
13039d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
13049d316c75SMichael Rolnik     gen_NSf(R);
13059d316c75SMichael Rolnik 
13069d316c75SMichael Rolnik     /*
13079d316c75SMichael Rolnik      * Previous value remains unchanged when the result is zero;
13089d316c75SMichael Rolnik      * cleared otherwise.
13099d316c75SMichael Rolnik      */
13109d316c75SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
13119d316c75SMichael Rolnik 
13129d316c75SMichael Rolnik     tcg_temp_free_i32(zero);
13139d316c75SMichael Rolnik     tcg_temp_free_i32(R);
13149d316c75SMichael Rolnik 
13159d316c75SMichael Rolnik     return true;
13169d316c75SMichael Rolnik }
13179d316c75SMichael Rolnik 
13189d316c75SMichael Rolnik /*
13199d316c75SMichael Rolnik  *  This instruction performs a compare between register Rd and a constant.
13209d316c75SMichael Rolnik  *  The register is not changed. All conditional branches can be used after this
13219d316c75SMichael Rolnik  *  instruction.
13229d316c75SMichael Rolnik  */
13239d316c75SMichael Rolnik static bool trans_CPI(DisasContext *ctx, arg_CPI *a)
13249d316c75SMichael Rolnik {
13259d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
13269d316c75SMichael Rolnik     int Imm = a->imm;
13279d316c75SMichael Rolnik     TCGv Rr = tcg_const_i32(Imm);
13289d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
13299d316c75SMichael Rolnik 
13309d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
13319d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
13329d316c75SMichael Rolnik 
13339d316c75SMichael Rolnik     /* update status register */
13349d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
13359d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
13369d316c75SMichael Rolnik     gen_ZNSf(R);
13379d316c75SMichael Rolnik 
13389d316c75SMichael Rolnik     tcg_temp_free_i32(R);
13399d316c75SMichael Rolnik     tcg_temp_free_i32(Rr);
13409d316c75SMichael Rolnik 
13419d316c75SMichael Rolnik     return true;
13429d316c75SMichael Rolnik }
13439d316c75SMichael Rolnik 
13449d316c75SMichael Rolnik /*
13459d316c75SMichael Rolnik  *  This instruction tests a single bit in a register and skips the next
13469d316c75SMichael Rolnik  *  instruction if the bit is cleared.
13479d316c75SMichael Rolnik  */
13489d316c75SMichael Rolnik static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a)
13499d316c75SMichael Rolnik {
13509d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
13519d316c75SMichael Rolnik 
13529d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
13539d316c75SMichael Rolnik     ctx->skip_var0 = tcg_temp_new();
13549d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
13559d316c75SMichael Rolnik 
13569d316c75SMichael Rolnik     tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
13579d316c75SMichael Rolnik     return true;
13589d316c75SMichael Rolnik }
13599d316c75SMichael Rolnik 
13609d316c75SMichael Rolnik /*
13619d316c75SMichael Rolnik  *  This instruction tests a single bit in a register and skips the next
13629d316c75SMichael Rolnik  *  instruction if the bit is set.
13639d316c75SMichael Rolnik  */
13649d316c75SMichael Rolnik static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a)
13659d316c75SMichael Rolnik {
13669d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
13679d316c75SMichael Rolnik 
13689d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_NE;
13699d316c75SMichael Rolnik     ctx->skip_var0 = tcg_temp_new();
13709d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
13719d316c75SMichael Rolnik 
13729d316c75SMichael Rolnik     tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
13739d316c75SMichael Rolnik     return true;
13749d316c75SMichael Rolnik }
13759d316c75SMichael Rolnik 
13769d316c75SMichael Rolnik /*
13779d316c75SMichael Rolnik  *  This instruction tests a single bit in an I/O Register and skips the
13789d316c75SMichael Rolnik  *  next instruction if the bit is cleared. This instruction operates on the
13799d316c75SMichael Rolnik  *  lower 32 I/O Registers -- addresses 0-31.
13809d316c75SMichael Rolnik  */
13819d316c75SMichael Rolnik static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a)
13829d316c75SMichael Rolnik {
13839d316c75SMichael Rolnik     TCGv temp = tcg_const_i32(a->reg);
13849d316c75SMichael Rolnik 
13859d316c75SMichael Rolnik     gen_helper_inb(temp, cpu_env, temp);
13869d316c75SMichael Rolnik     tcg_gen_andi_tl(temp, temp, 1 << a->bit);
13879d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
13889d316c75SMichael Rolnik     ctx->skip_var0 = temp;
13899d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
13909d316c75SMichael Rolnik 
13919d316c75SMichael Rolnik     return true;
13929d316c75SMichael Rolnik }
13939d316c75SMichael Rolnik 
13949d316c75SMichael Rolnik /*
13959d316c75SMichael Rolnik  *  This instruction tests a single bit in an I/O Register and skips the
13969d316c75SMichael Rolnik  *  next instruction if the bit is set. This instruction operates on the lower
13979d316c75SMichael Rolnik  *  32 I/O Registers -- addresses 0-31.
13989d316c75SMichael Rolnik  */
13999d316c75SMichael Rolnik static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a)
14009d316c75SMichael Rolnik {
14019d316c75SMichael Rolnik     TCGv temp = tcg_const_i32(a->reg);
14029d316c75SMichael Rolnik 
14039d316c75SMichael Rolnik     gen_helper_inb(temp, cpu_env, temp);
14049d316c75SMichael Rolnik     tcg_gen_andi_tl(temp, temp, 1 << a->bit);
14059d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_NE;
14069d316c75SMichael Rolnik     ctx->skip_var0 = temp;
14079d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
14089d316c75SMichael Rolnik 
14099d316c75SMichael Rolnik     return true;
14109d316c75SMichael Rolnik }
14119d316c75SMichael Rolnik 
14129d316c75SMichael Rolnik /*
14139d316c75SMichael Rolnik  *  Conditional relative branch. Tests a single bit in SREG and branches
14149d316c75SMichael Rolnik  *  relatively to PC if the bit is cleared. This instruction branches relatively
14159d316c75SMichael Rolnik  *  to PC in either direction (PC - 63 < = destination <= PC + 64). The
14169d316c75SMichael Rolnik  *  parameter k is the offset from PC and is represented in two's complement
14179d316c75SMichael Rolnik  *  form.
14189d316c75SMichael Rolnik  */
14199d316c75SMichael Rolnik static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a)
14209d316c75SMichael Rolnik {
14219d316c75SMichael Rolnik     TCGLabel *not_taken = gen_new_label();
14229d316c75SMichael Rolnik 
14239d316c75SMichael Rolnik     TCGv var;
14249d316c75SMichael Rolnik 
14259d316c75SMichael Rolnik     switch (a->bit) {
14269d316c75SMichael Rolnik     case 0x00:
14279d316c75SMichael Rolnik         var = cpu_Cf;
14289d316c75SMichael Rolnik         break;
14299d316c75SMichael Rolnik     case 0x01:
14309d316c75SMichael Rolnik         var = cpu_Zf;
14319d316c75SMichael Rolnik         break;
14329d316c75SMichael Rolnik     case 0x02:
14339d316c75SMichael Rolnik         var = cpu_Nf;
14349d316c75SMichael Rolnik         break;
14359d316c75SMichael Rolnik     case 0x03:
14369d316c75SMichael Rolnik         var = cpu_Vf;
14379d316c75SMichael Rolnik         break;
14389d316c75SMichael Rolnik     case 0x04:
14399d316c75SMichael Rolnik         var = cpu_Sf;
14409d316c75SMichael Rolnik         break;
14419d316c75SMichael Rolnik     case 0x05:
14429d316c75SMichael Rolnik         var = cpu_Hf;
14439d316c75SMichael Rolnik         break;
14449d316c75SMichael Rolnik     case 0x06:
14459d316c75SMichael Rolnik         var = cpu_Tf;
14469d316c75SMichael Rolnik         break;
14479d316c75SMichael Rolnik     case 0x07:
14489d316c75SMichael Rolnik         var = cpu_If;
14499d316c75SMichael Rolnik         break;
14509d316c75SMichael Rolnik     default:
14519d316c75SMichael Rolnik         g_assert_not_reached();
14529d316c75SMichael Rolnik     }
14539d316c75SMichael Rolnik 
14549d316c75SMichael Rolnik     tcg_gen_brcondi_i32(TCG_COND_NE, var, 0, not_taken);
14559d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, ctx->npc + a->imm);
14569d316c75SMichael Rolnik     gen_set_label(not_taken);
14579d316c75SMichael Rolnik 
14589d316c75SMichael Rolnik     ctx->bstate = DISAS_CHAIN;
14599d316c75SMichael Rolnik     return true;
14609d316c75SMichael Rolnik }
14619d316c75SMichael Rolnik 
14629d316c75SMichael Rolnik /*
14639d316c75SMichael Rolnik  *  Conditional relative branch. Tests a single bit in SREG and branches
14649d316c75SMichael Rolnik  *  relatively to PC if the bit is set. This instruction branches relatively to
14659d316c75SMichael Rolnik  *  PC in either direction (PC - 63 < = destination <= PC + 64). The parameter k
14669d316c75SMichael Rolnik  *  is the offset from PC and is represented in two's complement form.
14679d316c75SMichael Rolnik  */
14689d316c75SMichael Rolnik static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a)
14699d316c75SMichael Rolnik {
14709d316c75SMichael Rolnik     TCGLabel *not_taken = gen_new_label();
14719d316c75SMichael Rolnik 
14729d316c75SMichael Rolnik     TCGv var;
14739d316c75SMichael Rolnik 
14749d316c75SMichael Rolnik     switch (a->bit) {
14759d316c75SMichael Rolnik     case 0x00:
14769d316c75SMichael Rolnik         var = cpu_Cf;
14779d316c75SMichael Rolnik         break;
14789d316c75SMichael Rolnik     case 0x01:
14799d316c75SMichael Rolnik         var = cpu_Zf;
14809d316c75SMichael Rolnik         break;
14819d316c75SMichael Rolnik     case 0x02:
14829d316c75SMichael Rolnik         var = cpu_Nf;
14839d316c75SMichael Rolnik         break;
14849d316c75SMichael Rolnik     case 0x03:
14859d316c75SMichael Rolnik         var = cpu_Vf;
14869d316c75SMichael Rolnik         break;
14879d316c75SMichael Rolnik     case 0x04:
14889d316c75SMichael Rolnik         var = cpu_Sf;
14899d316c75SMichael Rolnik         break;
14909d316c75SMichael Rolnik     case 0x05:
14919d316c75SMichael Rolnik         var = cpu_Hf;
14929d316c75SMichael Rolnik         break;
14939d316c75SMichael Rolnik     case 0x06:
14949d316c75SMichael Rolnik         var = cpu_Tf;
14959d316c75SMichael Rolnik         break;
14969d316c75SMichael Rolnik     case 0x07:
14979d316c75SMichael Rolnik         var = cpu_If;
14989d316c75SMichael Rolnik         break;
14999d316c75SMichael Rolnik     default:
15009d316c75SMichael Rolnik         g_assert_not_reached();
15019d316c75SMichael Rolnik     }
15029d316c75SMichael Rolnik 
15039d316c75SMichael Rolnik     tcg_gen_brcondi_i32(TCG_COND_EQ, var, 0, not_taken);
15049d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, ctx->npc + a->imm);
15059d316c75SMichael Rolnik     gen_set_label(not_taken);
15069d316c75SMichael Rolnik 
15079d316c75SMichael Rolnik     ctx->bstate = DISAS_CHAIN;
15089d316c75SMichael Rolnik     return true;
15099d316c75SMichael Rolnik }
15109732b024SMichael Rolnik 
15119732b024SMichael Rolnik /*
15129732b024SMichael Rolnik  * Data Transfer Instructions
15139732b024SMichael Rolnik  */
15149732b024SMichael Rolnik 
15159732b024SMichael Rolnik /*
15169732b024SMichael Rolnik  *  in the gen_set_addr & gen_get_addr functions
15179732b024SMichael Rolnik  *  H assumed to be in 0x00ff0000 format
15189732b024SMichael Rolnik  *  M assumed to be in 0x000000ff format
15199732b024SMichael Rolnik  *  L assumed to be in 0x000000ff format
15209732b024SMichael Rolnik  */
15219732b024SMichael Rolnik static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L)
15229732b024SMichael Rolnik {
15239732b024SMichael Rolnik 
15249732b024SMichael Rolnik     tcg_gen_andi_tl(L, addr, 0x000000ff);
15259732b024SMichael Rolnik 
15269732b024SMichael Rolnik     tcg_gen_andi_tl(M, addr, 0x0000ff00);
15279732b024SMichael Rolnik     tcg_gen_shri_tl(M, M, 8);
15289732b024SMichael Rolnik 
15299732b024SMichael Rolnik     tcg_gen_andi_tl(H, addr, 0x00ff0000);
15309732b024SMichael Rolnik }
15319732b024SMichael Rolnik 
15329732b024SMichael Rolnik static void gen_set_xaddr(TCGv addr)
15339732b024SMichael Rolnik {
15349732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]);
15359732b024SMichael Rolnik }
15369732b024SMichael Rolnik 
15379732b024SMichael Rolnik static void gen_set_yaddr(TCGv addr)
15389732b024SMichael Rolnik {
15399732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]);
15409732b024SMichael Rolnik }
15419732b024SMichael Rolnik 
15429732b024SMichael Rolnik static void gen_set_zaddr(TCGv addr)
15439732b024SMichael Rolnik {
15449732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]);
15459732b024SMichael Rolnik }
15469732b024SMichael Rolnik 
15479732b024SMichael Rolnik static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L)
15489732b024SMichael Rolnik {
15499732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
15509732b024SMichael Rolnik 
15519732b024SMichael Rolnik     tcg_gen_deposit_tl(addr, M, H, 8, 8);
15529732b024SMichael Rolnik     tcg_gen_deposit_tl(addr, L, addr, 8, 16);
15539732b024SMichael Rolnik 
15549732b024SMichael Rolnik     return addr;
15559732b024SMichael Rolnik }
15569732b024SMichael Rolnik 
15579732b024SMichael Rolnik static TCGv gen_get_xaddr(void)
15589732b024SMichael Rolnik {
15599732b024SMichael Rolnik     return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]);
15609732b024SMichael Rolnik }
15619732b024SMichael Rolnik 
15629732b024SMichael Rolnik static TCGv gen_get_yaddr(void)
15639732b024SMichael Rolnik {
15649732b024SMichael Rolnik     return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]);
15659732b024SMichael Rolnik }
15669732b024SMichael Rolnik 
15679732b024SMichael Rolnik static TCGv gen_get_zaddr(void)
15689732b024SMichael Rolnik {
15699732b024SMichael Rolnik     return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]);
15709732b024SMichael Rolnik }
15719732b024SMichael Rolnik 
15729732b024SMichael Rolnik /*
15739732b024SMichael Rolnik  *  Load one byte indirect from data space to register and stores an clear
15749732b024SMichael Rolnik  *  the bits in data space specified by the register. The instruction can only
15759732b024SMichael Rolnik  *  be used towards internal SRAM.  The data location is pointed to by the Z (16
15769732b024SMichael Rolnik  *  bits) Pointer Register in the Register File. Memory access is limited to the
15779732b024SMichael Rolnik  *  current data segment of 64KB. To access another data segment in devices with
15789732b024SMichael Rolnik  *  more than 64KB data space, the RAMPZ in register in the I/O area has to be
15799732b024SMichael Rolnik  *  changed.  The Z-pointer Register is left unchanged by the operation. This
15809732b024SMichael Rolnik  *  instruction is especially suited for clearing status bits stored in SRAM.
15819732b024SMichael Rolnik  */
15829732b024SMichael Rolnik static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr)
15839732b024SMichael Rolnik {
15849732b024SMichael Rolnik     if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) {
15859732b024SMichael Rolnik         gen_helper_fullwr(cpu_env, data, addr);
15869732b024SMichael Rolnik     } else {
15879732b024SMichael Rolnik         tcg_gen_qemu_st8(data, addr, MMU_DATA_IDX); /* mem[addr] = data */
15889732b024SMichael Rolnik     }
15899732b024SMichael Rolnik }
15909732b024SMichael Rolnik 
15919732b024SMichael Rolnik static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr)
15929732b024SMichael Rolnik {
15939732b024SMichael Rolnik     if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) {
15949732b024SMichael Rolnik         gen_helper_fullrd(data, cpu_env, addr);
15959732b024SMichael Rolnik     } else {
15969732b024SMichael Rolnik         tcg_gen_qemu_ld8u(data, addr, MMU_DATA_IDX); /* data = mem[addr] */
15979732b024SMichael Rolnik     }
15989732b024SMichael Rolnik }
15999732b024SMichael Rolnik 
16009732b024SMichael Rolnik /*
16019732b024SMichael Rolnik  *  This instruction makes a copy of one register into another. The source
16029732b024SMichael Rolnik  *  register Rr is left unchanged, while the destination register Rd is loaded
16039732b024SMichael Rolnik  *  with a copy of Rr.
16049732b024SMichael Rolnik  */
16059732b024SMichael Rolnik static bool trans_MOV(DisasContext *ctx, arg_MOV *a)
16069732b024SMichael Rolnik {
16079732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16089732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
16099732b024SMichael Rolnik 
16109732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, Rr);
16119732b024SMichael Rolnik 
16129732b024SMichael Rolnik     return true;
16139732b024SMichael Rolnik }
16149732b024SMichael Rolnik 
16159732b024SMichael Rolnik /*
16169732b024SMichael Rolnik  *  This instruction makes a copy of one register pair into another register
16179732b024SMichael Rolnik  *  pair. The source register pair Rr+1:Rr is left unchanged, while the
16189732b024SMichael Rolnik  *  destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr.  This
16199732b024SMichael Rolnik  *  instruction is not available in all devices. Refer to the device specific
16209732b024SMichael Rolnik  *  instruction set summary.
16219732b024SMichael Rolnik  */
16229732b024SMichael Rolnik static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a)
16239732b024SMichael Rolnik {
16249732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MOVW)) {
16259732b024SMichael Rolnik         return true;
16269732b024SMichael Rolnik     }
16279732b024SMichael Rolnik 
16289732b024SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
16299732b024SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
16309732b024SMichael Rolnik     TCGv RrL = cpu_r[a->rr];
16319732b024SMichael Rolnik     TCGv RrH = cpu_r[a->rr + 1];
16329732b024SMichael Rolnik 
16339732b024SMichael Rolnik     tcg_gen_mov_tl(RdH, RrH);
16349732b024SMichael Rolnik     tcg_gen_mov_tl(RdL, RrL);
16359732b024SMichael Rolnik 
16369732b024SMichael Rolnik     return true;
16379732b024SMichael Rolnik }
16389732b024SMichael Rolnik 
16399732b024SMichael Rolnik /*
16409732b024SMichael Rolnik  * Loads an 8 bit constant directly to register 16 to 31.
16419732b024SMichael Rolnik  */
16429732b024SMichael Rolnik static bool trans_LDI(DisasContext *ctx, arg_LDI *a)
16439732b024SMichael Rolnik {
16449732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16459732b024SMichael Rolnik     int imm = a->imm;
16469732b024SMichael Rolnik 
16479732b024SMichael Rolnik     tcg_gen_movi_tl(Rd, imm);
16489732b024SMichael Rolnik 
16499732b024SMichael Rolnik     return true;
16509732b024SMichael Rolnik }
16519732b024SMichael Rolnik 
16529732b024SMichael Rolnik /*
16539732b024SMichael Rolnik  *  Loads one byte from the data space to a register. For parts with SRAM,
16549732b024SMichael Rolnik  *  the data space consists of the Register File, I/O memory and internal SRAM
16559732b024SMichael Rolnik  *  (and external SRAM if applicable). For parts without SRAM, the data space
16569732b024SMichael Rolnik  *  consists of the register file only. The EEPROM has a separate address space.
16579732b024SMichael Rolnik  *  A 16-bit address must be supplied. Memory access is limited to the current
16589732b024SMichael Rolnik  *  data segment of 64KB. The LDS instruction uses the RAMPD Register to access
16599732b024SMichael Rolnik  *  memory above 64KB. To access another data segment in devices with more than
16609732b024SMichael Rolnik  *  64KB data space, the RAMPD in register in the I/O area has to be changed.
16619732b024SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
16629732b024SMichael Rolnik  *  specific instruction set summary.
16639732b024SMichael Rolnik  */
16649732b024SMichael Rolnik static bool trans_LDS(DisasContext *ctx, arg_LDS *a)
16659732b024SMichael Rolnik {
16669732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
16679732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
16689732b024SMichael Rolnik     TCGv H = cpu_rampD;
16699732b024SMichael Rolnik     a->imm = next_word(ctx);
16709732b024SMichael Rolnik 
16719732b024SMichael Rolnik     tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
16729732b024SMichael Rolnik     tcg_gen_shli_tl(addr, addr, 16);
16739732b024SMichael Rolnik     tcg_gen_ori_tl(addr, addr, a->imm);
16749732b024SMichael Rolnik 
16759732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
16769732b024SMichael Rolnik 
16779732b024SMichael Rolnik     tcg_temp_free_i32(addr);
16789732b024SMichael Rolnik 
16799732b024SMichael Rolnik     return true;
16809732b024SMichael Rolnik }
16819732b024SMichael Rolnik 
16829732b024SMichael Rolnik /*
16839732b024SMichael Rolnik  *  Loads one byte indirect from the data space to a register. For parts
16849732b024SMichael Rolnik  *  with SRAM, the data space consists of the Register File, I/O memory and
16859732b024SMichael Rolnik  *  internal SRAM (and external SRAM if applicable). For parts without SRAM, the
16869732b024SMichael Rolnik  *  data space consists of the Register File only. In some parts the Flash
16879732b024SMichael Rolnik  *  Memory has been mapped to the data space and can be read using this command.
16889732b024SMichael Rolnik  *  The EEPROM has a separate address space.  The data location is pointed to by
16899732b024SMichael Rolnik  *  the X (16 bits) Pointer Register in the Register File. Memory access is
16909732b024SMichael Rolnik  *  limited to the current data segment of 64KB. To access another data segment
16919732b024SMichael Rolnik  *  in devices with more than 64KB data space, the RAMPX in register in the I/O
16929732b024SMichael Rolnik  *  area has to be changed.  The X-pointer Register can either be left unchanged
16939732b024SMichael Rolnik  *  by the operation, or it can be post-incremented or predecremented.  These
16949732b024SMichael Rolnik  *  features are especially suited for accessing arrays, tables, and Stack
16959732b024SMichael Rolnik  *  Pointer usage of the X-pointer Register. Note that only the low byte of the
16969732b024SMichael Rolnik  *  X-pointer is updated in devices with no more than 256 bytes data space. For
16979732b024SMichael Rolnik  *  such devices, the high byte of the pointer is not used by this instruction
16989732b024SMichael Rolnik  *  and can be used for other purposes. The RAMPX Register in the I/O area is
16999732b024SMichael Rolnik  *  updated in parts with more than 64KB data space or more than 64KB Program
17009732b024SMichael Rolnik  *  memory, and the increment/decrement is added to the entire 24-bit address on
17019732b024SMichael Rolnik  *  such devices.  Not all variants of this instruction is available in all
17029732b024SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.  In the
17039732b024SMichael Rolnik  *  Reduced Core tinyAVR the LD instruction can be used to achieve the same
17049732b024SMichael Rolnik  *  operation as LPM since the program memory is mapped to the data memory
17059732b024SMichael Rolnik  *  space.
17069732b024SMichael Rolnik  */
17079732b024SMichael Rolnik static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a)
17089732b024SMichael Rolnik {
17099732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17109732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
17119732b024SMichael Rolnik 
17129732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17139732b024SMichael Rolnik 
17149732b024SMichael Rolnik     tcg_temp_free_i32(addr);
17159732b024SMichael Rolnik 
17169732b024SMichael Rolnik     return true;
17179732b024SMichael Rolnik }
17189732b024SMichael Rolnik 
17199732b024SMichael Rolnik static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a)
17209732b024SMichael Rolnik {
17219732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17229732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
17239732b024SMichael Rolnik 
17249732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17259732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
17269732b024SMichael Rolnik 
17279732b024SMichael Rolnik     gen_set_xaddr(addr);
17289732b024SMichael Rolnik 
17299732b024SMichael Rolnik     tcg_temp_free_i32(addr);
17309732b024SMichael Rolnik 
17319732b024SMichael Rolnik     return true;
17329732b024SMichael Rolnik }
17339732b024SMichael Rolnik 
17349732b024SMichael Rolnik static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a)
17359732b024SMichael Rolnik {
17369732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17379732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
17389732b024SMichael Rolnik 
17399732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
17409732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17419732b024SMichael Rolnik     gen_set_xaddr(addr);
17429732b024SMichael Rolnik 
17439732b024SMichael Rolnik     tcg_temp_free_i32(addr);
17449732b024SMichael Rolnik 
17459732b024SMichael Rolnik     return true;
17469732b024SMichael Rolnik }
17479732b024SMichael Rolnik 
17489732b024SMichael Rolnik /*
17499732b024SMichael Rolnik  *  Loads one byte indirect with or without displacement from the data space
17509732b024SMichael Rolnik  *  to a register. For parts with SRAM, the data space consists of the Register
17519732b024SMichael Rolnik  *  File, I/O memory and internal SRAM (and external SRAM if applicable). For
17529732b024SMichael Rolnik  *  parts without SRAM, the data space consists of the Register File only. In
17539732b024SMichael Rolnik  *  some parts the Flash Memory has been mapped to the data space and can be
17549732b024SMichael Rolnik  *  read using this command. The EEPROM has a separate address space.  The data
17559732b024SMichael Rolnik  *  location is pointed to by the Y (16 bits) Pointer Register in the Register
17569732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
17579732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
17589732b024SMichael Rolnik  *  RAMPY in register in the I/O area has to be changed.  The Y-pointer Register
17599732b024SMichael Rolnik  *  can either be left unchanged by the operation, or it can be post-incremented
17609732b024SMichael Rolnik  *  or predecremented.  These features are especially suited for accessing
17619732b024SMichael Rolnik  *  arrays, tables, and Stack Pointer usage of the Y-pointer Register. Note that
17629732b024SMichael Rolnik  *  only the low byte of the Y-pointer is updated in devices with no more than
17639732b024SMichael Rolnik  *  256 bytes data space. For such devices, the high byte of the pointer is not
17649732b024SMichael Rolnik  *  used by this instruction and can be used for other purposes. The RAMPY
17659732b024SMichael Rolnik  *  Register in the I/O area is updated in parts with more than 64KB data space
17669732b024SMichael Rolnik  *  or more than 64KB Program memory, and the increment/decrement/displacement
17679732b024SMichael Rolnik  *  is added to the entire 24-bit address on such devices.  Not all variants of
17689732b024SMichael Rolnik  *  this instruction is available in all devices. Refer to the device specific
17699732b024SMichael Rolnik  *  instruction set summary.  In the Reduced Core tinyAVR the LD instruction can
17709732b024SMichael Rolnik  *  be used to achieve the same operation as LPM since the program memory is
17719732b024SMichael Rolnik  *  mapped to the data memory space.
17729732b024SMichael Rolnik  */
17739732b024SMichael Rolnik static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a)
17749732b024SMichael Rolnik {
17759732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17769732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
17779732b024SMichael Rolnik 
17789732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17799732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
17809732b024SMichael Rolnik 
17819732b024SMichael Rolnik     gen_set_yaddr(addr);
17829732b024SMichael Rolnik 
17839732b024SMichael Rolnik     tcg_temp_free_i32(addr);
17849732b024SMichael Rolnik 
17859732b024SMichael Rolnik     return true;
17869732b024SMichael Rolnik }
17879732b024SMichael Rolnik 
17889732b024SMichael Rolnik static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a)
17899732b024SMichael Rolnik {
17909732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
17919732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
17929732b024SMichael Rolnik 
17939732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
17949732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
17959732b024SMichael Rolnik     gen_set_yaddr(addr);
17969732b024SMichael Rolnik 
17979732b024SMichael Rolnik     tcg_temp_free_i32(addr);
17989732b024SMichael Rolnik 
17999732b024SMichael Rolnik     return true;
18009732b024SMichael Rolnik }
18019732b024SMichael Rolnik 
18029732b024SMichael Rolnik static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a)
18039732b024SMichael Rolnik {
18049732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18059732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
18069732b024SMichael Rolnik 
18079732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
18089732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
18099732b024SMichael Rolnik 
18109732b024SMichael Rolnik     tcg_temp_free_i32(addr);
18119732b024SMichael Rolnik 
18129732b024SMichael Rolnik     return true;
18139732b024SMichael Rolnik }
18149732b024SMichael Rolnik 
18159732b024SMichael Rolnik /*
18169732b024SMichael Rolnik  *  Loads one byte indirect with or without displacement from the data space
18179732b024SMichael Rolnik  *  to a register. For parts with SRAM, the data space consists of the Register
18189732b024SMichael Rolnik  *  File, I/O memory and internal SRAM (and external SRAM if applicable). For
18199732b024SMichael Rolnik  *  parts without SRAM, the data space consists of the Register File only. In
18209732b024SMichael Rolnik  *  some parts the Flash Memory has been mapped to the data space and can be
18219732b024SMichael Rolnik  *  read using this command. The EEPROM has a separate address space.  The data
18229732b024SMichael Rolnik  *  location is pointed to by the Z (16 bits) Pointer Register in the Register
18239732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
18249732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
18259732b024SMichael Rolnik  *  RAMPZ in register in the I/O area has to be changed.  The Z-pointer Register
18269732b024SMichael Rolnik  *  can either be left unchanged by the operation, or it can be post-incremented
18279732b024SMichael Rolnik  *  or predecremented.  These features are especially suited for Stack Pointer
18289732b024SMichael Rolnik  *  usage of the Z-pointer Register, however because the Z-pointer Register can
18299732b024SMichael Rolnik  *  be used for indirect subroutine calls, indirect jumps and table lookup, it
18309732b024SMichael Rolnik  *  is often more convenient to use the X or Y-pointer as a dedicated Stack
18319732b024SMichael Rolnik  *  Pointer. Note that only the low byte of the Z-pointer is updated in devices
18329732b024SMichael Rolnik  *  with no more than 256 bytes data space. For such devices, the high byte of
18339732b024SMichael Rolnik  *  the pointer is not used by this instruction and can be used for other
18349732b024SMichael Rolnik  *  purposes. The RAMPZ Register in the I/O area is updated in parts with more
18359732b024SMichael Rolnik  *  than 64KB data space or more than 64KB Program memory, and the
18369732b024SMichael Rolnik  *  increment/decrement/displacement is added to the entire 24-bit address on
18379732b024SMichael Rolnik  *  such devices.  Not all variants of this instruction is available in all
18389732b024SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.  In the
18399732b024SMichael Rolnik  *  Reduced Core tinyAVR the LD instruction can be used to achieve the same
18409732b024SMichael Rolnik  *  operation as LPM since the program memory is mapped to the data memory
18419732b024SMichael Rolnik  *  space.  For using the Z-pointer for table lookup in Program memory see the
18429732b024SMichael Rolnik  *  LPM and ELPM instructions.
18439732b024SMichael Rolnik  */
18449732b024SMichael Rolnik static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a)
18459732b024SMichael Rolnik {
18469732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18479732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
18489732b024SMichael Rolnik 
18499732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
18509732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
18519732b024SMichael Rolnik 
18529732b024SMichael Rolnik     gen_set_zaddr(addr);
18539732b024SMichael Rolnik 
18549732b024SMichael Rolnik     tcg_temp_free_i32(addr);
18559732b024SMichael Rolnik 
18569732b024SMichael Rolnik     return true;
18579732b024SMichael Rolnik }
18589732b024SMichael Rolnik 
18599732b024SMichael Rolnik static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a)
18609732b024SMichael Rolnik {
18619732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18629732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
18639732b024SMichael Rolnik 
18649732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
18659732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
18669732b024SMichael Rolnik 
18679732b024SMichael Rolnik     gen_set_zaddr(addr);
18689732b024SMichael Rolnik 
18699732b024SMichael Rolnik     tcg_temp_free_i32(addr);
18709732b024SMichael Rolnik 
18719732b024SMichael Rolnik     return true;
18729732b024SMichael Rolnik }
18739732b024SMichael Rolnik 
18749732b024SMichael Rolnik static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a)
18759732b024SMichael Rolnik {
18769732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
18779732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
18789732b024SMichael Rolnik 
18799732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
18809732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
18819732b024SMichael Rolnik 
18829732b024SMichael Rolnik     tcg_temp_free_i32(addr);
18839732b024SMichael Rolnik 
18849732b024SMichael Rolnik     return true;
18859732b024SMichael Rolnik }
18869732b024SMichael Rolnik 
18879732b024SMichael Rolnik /*
18889732b024SMichael Rolnik  *  Stores one byte from a Register to the data space. For parts with SRAM,
18899732b024SMichael Rolnik  *  the data space consists of the Register File, I/O memory and internal SRAM
18909732b024SMichael Rolnik  *  (and external SRAM if applicable). For parts without SRAM, the data space
18919732b024SMichael Rolnik  *  consists of the Register File only. The EEPROM has a separate address space.
18929732b024SMichael Rolnik  *  A 16-bit address must be supplied. Memory access is limited to the current
18939732b024SMichael Rolnik  *  data segment of 64KB. The STS instruction uses the RAMPD Register to access
18949732b024SMichael Rolnik  *  memory above 64KB. To access another data segment in devices with more than
18959732b024SMichael Rolnik  *  64KB data space, the RAMPD in register in the I/O area has to be changed.
18969732b024SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
18979732b024SMichael Rolnik  *  specific instruction set summary.
18989732b024SMichael Rolnik  */
18999732b024SMichael Rolnik static bool trans_STS(DisasContext *ctx, arg_STS *a)
19009732b024SMichael Rolnik {
19019732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
19029732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
19039732b024SMichael Rolnik     TCGv H = cpu_rampD;
19049732b024SMichael Rolnik     a->imm = next_word(ctx);
19059732b024SMichael Rolnik 
19069732b024SMichael Rolnik     tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
19079732b024SMichael Rolnik     tcg_gen_shli_tl(addr, addr, 16);
19089732b024SMichael Rolnik     tcg_gen_ori_tl(addr, addr, a->imm);
19099732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19109732b024SMichael Rolnik 
19119732b024SMichael Rolnik     tcg_temp_free_i32(addr);
19129732b024SMichael Rolnik 
19139732b024SMichael Rolnik     return true;
19149732b024SMichael Rolnik }
19159732b024SMichael Rolnik 
19169732b024SMichael Rolnik /*
19179732b024SMichael Rolnik  * Stores one byte indirect from a register to data space. For parts with SRAM,
19189732b024SMichael Rolnik  * the data space consists of the Register File, I/O memory, and internal SRAM
19199732b024SMichael Rolnik  * (and external SRAM if applicable). For parts without SRAM, the data space
19209732b024SMichael Rolnik  * consists of the Register File only. The EEPROM has a separate address space.
19219732b024SMichael Rolnik  *
19229732b024SMichael Rolnik  * The data location is pointed to by the X (16 bits) Pointer Register in the
19239732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
19249732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
19259732b024SMichael Rolnik  * RAMPX in register in the I/O area has to be changed.
19269732b024SMichael Rolnik  *
19279732b024SMichael Rolnik  * The X-pointer Register can either be left unchanged by the operation, or it
19289732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
19299732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the
19309732b024SMichael Rolnik  * X-pointer Register. Note that only the low byte of the X-pointer is updated
19319732b024SMichael Rolnik  * in devices with no more than 256 bytes data space. For such devices, the high
19329732b024SMichael Rolnik  * byte of the pointer is not used by this instruction and can be used for other
19339732b024SMichael Rolnik  * purposes. The RAMPX Register in the I/O area is updated in parts with more
19349732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
19359732b024SMichael Rolnik  * decrement is added to the entire 24-bit address on such devices.
19369732b024SMichael Rolnik  */
19379732b024SMichael Rolnik static bool trans_STX1(DisasContext *ctx, arg_STX1 *a)
19389732b024SMichael Rolnik {
19399732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
19409732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
19419732b024SMichael Rolnik 
19429732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19439732b024SMichael Rolnik 
19449732b024SMichael Rolnik     tcg_temp_free_i32(addr);
19459732b024SMichael Rolnik 
19469732b024SMichael Rolnik     return true;
19479732b024SMichael Rolnik }
19489732b024SMichael Rolnik 
19499732b024SMichael Rolnik static bool trans_STX2(DisasContext *ctx, arg_STX2 *a)
19509732b024SMichael Rolnik {
19519732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
19529732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
19539732b024SMichael Rolnik 
19549732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19559732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
19569732b024SMichael Rolnik     gen_set_xaddr(addr);
19579732b024SMichael Rolnik 
19589732b024SMichael Rolnik     tcg_temp_free_i32(addr);
19599732b024SMichael Rolnik 
19609732b024SMichael Rolnik     return true;
19619732b024SMichael Rolnik }
19629732b024SMichael Rolnik 
19639732b024SMichael Rolnik static bool trans_STX3(DisasContext *ctx, arg_STX3 *a)
19649732b024SMichael Rolnik {
19659732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
19669732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
19679732b024SMichael Rolnik 
19689732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
19699732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
19709732b024SMichael Rolnik     gen_set_xaddr(addr);
19719732b024SMichael Rolnik 
19729732b024SMichael Rolnik     tcg_temp_free_i32(addr);
19739732b024SMichael Rolnik 
19749732b024SMichael Rolnik     return true;
19759732b024SMichael Rolnik }
19769732b024SMichael Rolnik 
19779732b024SMichael Rolnik /*
19789732b024SMichael Rolnik  * Stores one byte indirect with or without displacement from a register to data
19799732b024SMichael Rolnik  * space. For parts with SRAM, the data space consists of the Register File, I/O
19809732b024SMichael Rolnik  * memory, and internal SRAM (and external SRAM if applicable). For parts
19819732b024SMichael Rolnik  * without SRAM, the data space consists of the Register File only. The EEPROM
19829732b024SMichael Rolnik  * has a separate address space.
19839732b024SMichael Rolnik  *
19849732b024SMichael Rolnik  * The data location is pointed to by the Y (16 bits) Pointer Register in the
19859732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
19869732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
19879732b024SMichael Rolnik  * RAMPY in register in the I/O area has to be changed.
19889732b024SMichael Rolnik  *
19899732b024SMichael Rolnik  * The Y-pointer Register can either be left unchanged by the operation, or it
19909732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
19919732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer
19929732b024SMichael Rolnik  * Register. Note that only the low byte of the Y-pointer is updated in devices
19939732b024SMichael Rolnik  * with no more than 256 bytes data space. For such devices, the high byte of
19949732b024SMichael Rolnik  * the pointer is not used by this instruction and can be used for other
19959732b024SMichael Rolnik  * purposes. The RAMPY Register in the I/O area is updated in parts with more
19969732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
19979732b024SMichael Rolnik  * decrement / displacement is added to the entire 24-bit address on such
19989732b024SMichael Rolnik  * devices.
19999732b024SMichael Rolnik  */
20009732b024SMichael Rolnik static bool trans_STY2(DisasContext *ctx, arg_STY2 *a)
20019732b024SMichael Rolnik {
20029732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20039732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
20049732b024SMichael Rolnik 
20059732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
20069732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
20079732b024SMichael Rolnik     gen_set_yaddr(addr);
20089732b024SMichael Rolnik 
20099732b024SMichael Rolnik     tcg_temp_free_i32(addr);
20109732b024SMichael Rolnik 
20119732b024SMichael Rolnik     return true;
20129732b024SMichael Rolnik }
20139732b024SMichael Rolnik 
20149732b024SMichael Rolnik static bool trans_STY3(DisasContext *ctx, arg_STY3 *a)
20159732b024SMichael Rolnik {
20169732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20179732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
20189732b024SMichael Rolnik 
20199732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
20209732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
20219732b024SMichael Rolnik     gen_set_yaddr(addr);
20229732b024SMichael Rolnik 
20239732b024SMichael Rolnik     tcg_temp_free_i32(addr);
20249732b024SMichael Rolnik 
20259732b024SMichael Rolnik     return true;
20269732b024SMichael Rolnik }
20279732b024SMichael Rolnik 
20289732b024SMichael Rolnik static bool trans_STDY(DisasContext *ctx, arg_STDY *a)
20299732b024SMichael Rolnik {
20309732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20319732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
20329732b024SMichael Rolnik 
20339732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
20349732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
20359732b024SMichael Rolnik 
20369732b024SMichael Rolnik     tcg_temp_free_i32(addr);
20379732b024SMichael Rolnik 
20389732b024SMichael Rolnik     return true;
20399732b024SMichael Rolnik }
20409732b024SMichael Rolnik 
20419732b024SMichael Rolnik /*
20429732b024SMichael Rolnik  * Stores one byte indirect with or without displacement from a register to data
20439732b024SMichael Rolnik  * space. For parts with SRAM, the data space consists of the Register File, I/O
20449732b024SMichael Rolnik  * memory, and internal SRAM (and external SRAM if applicable). For parts
20459732b024SMichael Rolnik  * without SRAM, the data space consists of the Register File only. The EEPROM
20469732b024SMichael Rolnik  * has a separate address space.
20479732b024SMichael Rolnik  *
20489732b024SMichael Rolnik  * The data location is pointed to by the Y (16 bits) Pointer Register in the
20499732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
20509732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
20519732b024SMichael Rolnik  * RAMPY in register in the I/O area has to be changed.
20529732b024SMichael Rolnik  *
20539732b024SMichael Rolnik  * The Y-pointer Register can either be left unchanged by the operation, or it
20549732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
20559732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer
20569732b024SMichael Rolnik  * Register. Note that only the low byte of the Y-pointer is updated in devices
20579732b024SMichael Rolnik  * with no more than 256 bytes data space. For such devices, the high byte of
20589732b024SMichael Rolnik  * the pointer is not used by this instruction and can be used for other
20599732b024SMichael Rolnik  * purposes. The RAMPY Register in the I/O area is updated in parts with more
20609732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
20619732b024SMichael Rolnik  * decrement / displacement is added to the entire 24-bit address on such
20629732b024SMichael Rolnik  * devices.
20639732b024SMichael Rolnik  */
20649732b024SMichael Rolnik static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a)
20659732b024SMichael Rolnik {
20669732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20679732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
20689732b024SMichael Rolnik 
20699732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
20709732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
20719732b024SMichael Rolnik 
20729732b024SMichael Rolnik     gen_set_zaddr(addr);
20739732b024SMichael Rolnik 
20749732b024SMichael Rolnik     tcg_temp_free_i32(addr);
20759732b024SMichael Rolnik 
20769732b024SMichael Rolnik     return true;
20779732b024SMichael Rolnik }
20789732b024SMichael Rolnik 
20799732b024SMichael Rolnik static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a)
20809732b024SMichael Rolnik {
20819732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20829732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
20839732b024SMichael Rolnik 
20849732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
20859732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
20869732b024SMichael Rolnik 
20879732b024SMichael Rolnik     gen_set_zaddr(addr);
20889732b024SMichael Rolnik 
20899732b024SMichael Rolnik     tcg_temp_free_i32(addr);
20909732b024SMichael Rolnik 
20919732b024SMichael Rolnik     return true;
20929732b024SMichael Rolnik }
20939732b024SMichael Rolnik 
20949732b024SMichael Rolnik static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a)
20959732b024SMichael Rolnik {
20969732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
20979732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
20989732b024SMichael Rolnik 
20999732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
21009732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
21019732b024SMichael Rolnik 
21029732b024SMichael Rolnik     tcg_temp_free_i32(addr);
21039732b024SMichael Rolnik 
21049732b024SMichael Rolnik     return true;
21059732b024SMichael Rolnik }
21069732b024SMichael Rolnik 
21079732b024SMichael Rolnik /*
21089732b024SMichael Rolnik  *  Loads one byte pointed to by the Z-register into the destination
21099732b024SMichael Rolnik  *  register Rd. This instruction features a 100% space effective constant
21109732b024SMichael Rolnik  *  initialization or constant data fetch. The Program memory is organized in
21119732b024SMichael Rolnik  *  16-bit words while the Z-pointer is a byte address. Thus, the least
21129732b024SMichael Rolnik  *  significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high
21139732b024SMichael Rolnik  *  byte (ZLSB = 1). This instruction can address the first 64KB (32K words) of
21149732b024SMichael Rolnik  *  Program memory. The Zpointer Register can either be left unchanged by the
21159732b024SMichael Rolnik  *  operation, or it can be incremented. The incrementation does not apply to
21169732b024SMichael Rolnik  *  the RAMPZ Register.
21179732b024SMichael Rolnik  *
21189732b024SMichael Rolnik  *  Devices with Self-Programming capability can use the LPM instruction to read
21199732b024SMichael Rolnik  *  the Fuse and Lock bit values.
21209732b024SMichael Rolnik  */
21219732b024SMichael Rolnik static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a)
21229732b024SMichael Rolnik {
21239732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) {
21249732b024SMichael Rolnik         return true;
21259732b024SMichael Rolnik     }
21269732b024SMichael Rolnik 
21279732b024SMichael Rolnik     TCGv Rd = cpu_r[0];
21289732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
21299732b024SMichael Rolnik     TCGv H = cpu_r[31];
21309732b024SMichael Rolnik     TCGv L = cpu_r[30];
21319732b024SMichael Rolnik 
21329732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
21339732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
21349732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
21359732b024SMichael Rolnik 
21369732b024SMichael Rolnik     tcg_temp_free_i32(addr);
21379732b024SMichael Rolnik 
21389732b024SMichael Rolnik     return true;
21399732b024SMichael Rolnik }
21409732b024SMichael Rolnik 
21419732b024SMichael Rolnik static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a)
21429732b024SMichael Rolnik {
21439732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) {
21449732b024SMichael Rolnik         return true;
21459732b024SMichael Rolnik     }
21469732b024SMichael Rolnik 
21479732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
21489732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
21499732b024SMichael Rolnik     TCGv H = cpu_r[31];
21509732b024SMichael Rolnik     TCGv L = cpu_r[30];
21519732b024SMichael Rolnik 
21529732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
21539732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
21549732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
21559732b024SMichael Rolnik 
21569732b024SMichael Rolnik     tcg_temp_free_i32(addr);
21579732b024SMichael Rolnik 
21589732b024SMichael Rolnik     return true;
21599732b024SMichael Rolnik }
21609732b024SMichael Rolnik 
21619732b024SMichael Rolnik static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a)
21629732b024SMichael Rolnik {
21639732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPMX)) {
21649732b024SMichael Rolnik         return true;
21659732b024SMichael Rolnik     }
21669732b024SMichael Rolnik 
21679732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
21689732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
21699732b024SMichael Rolnik     TCGv H = cpu_r[31];
21709732b024SMichael Rolnik     TCGv L = cpu_r[30];
21719732b024SMichael Rolnik 
21729732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
21739732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
21749732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
21759732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
21769732b024SMichael Rolnik     tcg_gen_andi_tl(L, addr, 0xff);
21779732b024SMichael Rolnik     tcg_gen_shri_tl(addr, addr, 8);
21789732b024SMichael Rolnik     tcg_gen_andi_tl(H, addr, 0xff);
21799732b024SMichael Rolnik 
21809732b024SMichael Rolnik     tcg_temp_free_i32(addr);
21819732b024SMichael Rolnik 
21829732b024SMichael Rolnik     return true;
21839732b024SMichael Rolnik }
21849732b024SMichael Rolnik 
21859732b024SMichael Rolnik /*
21869732b024SMichael Rolnik  *  Loads one byte pointed to by the Z-register and the RAMPZ Register in
21879732b024SMichael Rolnik  *  the I/O space, and places this byte in the destination register Rd. This
21889732b024SMichael Rolnik  *  instruction features a 100% space effective constant initialization or
21899732b024SMichael Rolnik  *  constant data fetch. The Program memory is organized in 16-bit words while
21909732b024SMichael Rolnik  *  the Z-pointer is a byte address. Thus, the least significant bit of the
21919732b024SMichael Rolnik  *  Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This
21929732b024SMichael Rolnik  *  instruction can address the entire Program memory space. The Z-pointer
21939732b024SMichael Rolnik  *  Register can either be left unchanged by the operation, or it can be
21949732b024SMichael Rolnik  *  incremented. The incrementation applies to the entire 24-bit concatenation
21959732b024SMichael Rolnik  *  of the RAMPZ and Z-pointer Registers.
21969732b024SMichael Rolnik  *
21979732b024SMichael Rolnik  *  Devices with Self-Programming capability can use the ELPM instruction to
21989732b024SMichael Rolnik  *  read the Fuse and Lock bit value.
21999732b024SMichael Rolnik  */
22009732b024SMichael Rolnik static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a)
22019732b024SMichael Rolnik {
22029732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) {
22039732b024SMichael Rolnik         return true;
22049732b024SMichael Rolnik     }
22059732b024SMichael Rolnik 
22069732b024SMichael Rolnik     TCGv Rd = cpu_r[0];
22079732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
22089732b024SMichael Rolnik 
22099732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
22109732b024SMichael Rolnik 
22119732b024SMichael Rolnik     tcg_temp_free_i32(addr);
22129732b024SMichael Rolnik 
22139732b024SMichael Rolnik     return true;
22149732b024SMichael Rolnik }
22159732b024SMichael Rolnik 
22169732b024SMichael Rolnik static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a)
22179732b024SMichael Rolnik {
22189732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) {
22199732b024SMichael Rolnik         return true;
22209732b024SMichael Rolnik     }
22219732b024SMichael Rolnik 
22229732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
22239732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
22249732b024SMichael Rolnik 
22259732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
22269732b024SMichael Rolnik 
22279732b024SMichael Rolnik     tcg_temp_free_i32(addr);
22289732b024SMichael Rolnik 
22299732b024SMichael Rolnik     return true;
22309732b024SMichael Rolnik }
22319732b024SMichael Rolnik 
22329732b024SMichael Rolnik static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a)
22339732b024SMichael Rolnik {
22349732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPMX)) {
22359732b024SMichael Rolnik         return true;
22369732b024SMichael Rolnik     }
22379732b024SMichael Rolnik 
22389732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
22399732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
22409732b024SMichael Rolnik 
22419732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
22429732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
22439732b024SMichael Rolnik     gen_set_zaddr(addr);
22449732b024SMichael Rolnik 
22459732b024SMichael Rolnik     tcg_temp_free_i32(addr);
22469732b024SMichael Rolnik 
22479732b024SMichael Rolnik     return true;
22489732b024SMichael Rolnik }
22499732b024SMichael Rolnik 
22509732b024SMichael Rolnik /*
22519732b024SMichael Rolnik  *  SPM can be used to erase a page in the Program memory, to write a page
22529732b024SMichael Rolnik  *  in the Program memory (that is already erased), and to set Boot Loader Lock
22539732b024SMichael Rolnik  *  bits. In some devices, the Program memory can be written one word at a time,
22549732b024SMichael Rolnik  *  in other devices an entire page can be programmed simultaneously after first
22559732b024SMichael Rolnik  *  filling a temporary page buffer. In all cases, the Program memory must be
22569732b024SMichael Rolnik  *  erased one page at a time. When erasing the Program memory, the RAMPZ and
22579732b024SMichael Rolnik  *  Z-register are used as page address. When writing the Program memory, the
22589732b024SMichael Rolnik  *  RAMPZ and Z-register are used as page or word address, and the R1:R0
22599732b024SMichael Rolnik  *  register pair is used as data(1). When setting the Boot Loader Lock bits,
22609732b024SMichael Rolnik  *  the R1:R0 register pair is used as data. Refer to the device documentation
22619732b024SMichael Rolnik  *  for detailed description of SPM usage. This instruction can address the
22629732b024SMichael Rolnik  *  entire Program memory.
22639732b024SMichael Rolnik  *
22649732b024SMichael Rolnik  *  The SPM instruction is not available in all devices. Refer to the device
22659732b024SMichael Rolnik  *  specific instruction set summary.
22669732b024SMichael Rolnik  *
22679732b024SMichael Rolnik  *  Note: 1. R1 determines the instruction high byte, and R0 determines the
22689732b024SMichael Rolnik  *  instruction low byte.
22699732b024SMichael Rolnik  */
22709732b024SMichael Rolnik static bool trans_SPM(DisasContext *ctx, arg_SPM *a)
22719732b024SMichael Rolnik {
22729732b024SMichael Rolnik     /* TODO */
22739732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_SPM)) {
22749732b024SMichael Rolnik         return true;
22759732b024SMichael Rolnik     }
22769732b024SMichael Rolnik 
22779732b024SMichael Rolnik     return true;
22789732b024SMichael Rolnik }
22799732b024SMichael Rolnik 
22809732b024SMichael Rolnik static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a)
22819732b024SMichael Rolnik {
22829732b024SMichael Rolnik     /* TODO */
22839732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_SPMX)) {
22849732b024SMichael Rolnik         return true;
22859732b024SMichael Rolnik     }
22869732b024SMichael Rolnik 
22879732b024SMichael Rolnik     return true;
22889732b024SMichael Rolnik }
22899732b024SMichael Rolnik 
22909732b024SMichael Rolnik /*
22919732b024SMichael Rolnik  *  Loads data from the I/O Space (Ports, Timers, Configuration Registers,
22929732b024SMichael Rolnik  *  etc.) into register Rd in the Register File.
22939732b024SMichael Rolnik  */
22949732b024SMichael Rolnik static bool trans_IN(DisasContext *ctx, arg_IN *a)
22959732b024SMichael Rolnik {
22969732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
22979732b024SMichael Rolnik     TCGv port = tcg_const_i32(a->imm);
22989732b024SMichael Rolnik 
22999732b024SMichael Rolnik     gen_helper_inb(Rd, cpu_env, port);
23009732b024SMichael Rolnik 
23019732b024SMichael Rolnik     tcg_temp_free_i32(port);
23029732b024SMichael Rolnik 
23039732b024SMichael Rolnik     return true;
23049732b024SMichael Rolnik }
23059732b024SMichael Rolnik 
23069732b024SMichael Rolnik /*
23079732b024SMichael Rolnik  *  Stores data from register Rr in the Register File to I/O Space (Ports,
23089732b024SMichael Rolnik  *  Timers, Configuration Registers, etc.).
23099732b024SMichael Rolnik  */
23109732b024SMichael Rolnik static bool trans_OUT(DisasContext *ctx, arg_OUT *a)
23119732b024SMichael Rolnik {
23129732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23139732b024SMichael Rolnik     TCGv port = tcg_const_i32(a->imm);
23149732b024SMichael Rolnik 
23159732b024SMichael Rolnik     gen_helper_outb(cpu_env, port, Rd);
23169732b024SMichael Rolnik 
23179732b024SMichael Rolnik     tcg_temp_free_i32(port);
23189732b024SMichael Rolnik 
23199732b024SMichael Rolnik     return true;
23209732b024SMichael Rolnik }
23219732b024SMichael Rolnik 
23229732b024SMichael Rolnik /*
23239732b024SMichael Rolnik  *  This instruction stores the contents of register Rr on the STACK. The
23249732b024SMichael Rolnik  *  Stack Pointer is post-decremented by 1 after the PUSH.  This instruction is
23259732b024SMichael Rolnik  *  not available in all devices. Refer to the device specific instruction set
23269732b024SMichael Rolnik  *  summary.
23279732b024SMichael Rolnik  */
23289732b024SMichael Rolnik static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a)
23299732b024SMichael Rolnik {
23309732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23319732b024SMichael Rolnik 
23329732b024SMichael Rolnik     gen_data_store(ctx, Rd, cpu_sp);
23339732b024SMichael Rolnik     tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
23349732b024SMichael Rolnik 
23359732b024SMichael Rolnik     return true;
23369732b024SMichael Rolnik }
23379732b024SMichael Rolnik 
23389732b024SMichael Rolnik /*
23399732b024SMichael Rolnik  *  This instruction loads register Rd with a byte from the STACK. The Stack
23409732b024SMichael Rolnik  *  Pointer is pre-incremented by 1 before the POP.  This instruction is not
23419732b024SMichael Rolnik  *  available in all devices. Refer to the device specific instruction set
23429732b024SMichael Rolnik  *  summary.
23439732b024SMichael Rolnik  */
23449732b024SMichael Rolnik static bool trans_POP(DisasContext *ctx, arg_POP *a)
23459732b024SMichael Rolnik {
23469732b024SMichael Rolnik     /*
23479732b024SMichael Rolnik      * Using a temp to work around some strange behaviour:
23489732b024SMichael Rolnik      * tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
23499732b024SMichael Rolnik      * gen_data_load(ctx, Rd, cpu_sp);
23509732b024SMichael Rolnik      * seems to cause the add to happen twice.
23519732b024SMichael Rolnik      * This doesn't happen if either the add or the load is removed.
23529732b024SMichael Rolnik      */
23539732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
23549732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23559732b024SMichael Rolnik 
23569732b024SMichael Rolnik     tcg_gen_addi_tl(t1, cpu_sp, 1);
23579732b024SMichael Rolnik     gen_data_load(ctx, Rd, t1);
23589732b024SMichael Rolnik     tcg_gen_mov_tl(cpu_sp, t1);
23599732b024SMichael Rolnik 
23609732b024SMichael Rolnik     return true;
23619732b024SMichael Rolnik }
23629732b024SMichael Rolnik 
23639732b024SMichael Rolnik /*
23649732b024SMichael Rolnik  *  Exchanges one byte indirect between register and data space.  The data
23659732b024SMichael Rolnik  *  location is pointed to by the Z (16 bits) Pointer Register in the Register
23669732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
23679732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
23689732b024SMichael Rolnik  *  RAMPZ in register in the I/O area has to be changed.
23699732b024SMichael Rolnik  *
23709732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
23719732b024SMichael Rolnik  *  is especially suited for writing/reading status bits stored in SRAM.
23729732b024SMichael Rolnik  */
23739732b024SMichael Rolnik static bool trans_XCH(DisasContext *ctx, arg_XCH *a)
23749732b024SMichael Rolnik {
23759732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
23769732b024SMichael Rolnik         return true;
23779732b024SMichael Rolnik     }
23789732b024SMichael Rolnik 
23799732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
23809732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
23819732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
23829732b024SMichael Rolnik 
23839732b024SMichael Rolnik     gen_data_load(ctx, t0, addr);
23849732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
23859732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, t0);
23869732b024SMichael Rolnik 
23879732b024SMichael Rolnik     tcg_temp_free_i32(t0);
23889732b024SMichael Rolnik     tcg_temp_free_i32(addr);
23899732b024SMichael Rolnik 
23909732b024SMichael Rolnik     return true;
23919732b024SMichael Rolnik }
23929732b024SMichael Rolnik 
23939732b024SMichael Rolnik /*
23949732b024SMichael Rolnik  *  Load one byte indirect from data space to register and set bits in data
23959732b024SMichael Rolnik  *  space specified by the register. The instruction can only be used towards
23969732b024SMichael Rolnik  *  internal SRAM.  The data location is pointed to by the Z (16 bits) Pointer
23979732b024SMichael Rolnik  *  Register in the Register File. Memory access is limited to the current data
23989732b024SMichael Rolnik  *  segment of 64KB. To access another data segment in devices with more than
23999732b024SMichael Rolnik  *  64KB data space, the RAMPZ in register in the I/O area has to be changed.
24009732b024SMichael Rolnik  *
24019732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
24029732b024SMichael Rolnik  *  is especially suited for setting status bits stored in SRAM.
24039732b024SMichael Rolnik  */
24049732b024SMichael Rolnik static bool trans_LAS(DisasContext *ctx, arg_LAS *a)
24059732b024SMichael Rolnik {
24069732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
24079732b024SMichael Rolnik         return true;
24089732b024SMichael Rolnik     }
24099732b024SMichael Rolnik 
24109732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rd];
24119732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
24129732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
24139732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
24149732b024SMichael Rolnik 
24159732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
24169732b024SMichael Rolnik     tcg_gen_or_tl(t1, t0, Rr);
24179732b024SMichael Rolnik     tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
24189732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
24199732b024SMichael Rolnik 
24209732b024SMichael Rolnik     tcg_temp_free_i32(t1);
24219732b024SMichael Rolnik     tcg_temp_free_i32(t0);
24229732b024SMichael Rolnik     tcg_temp_free_i32(addr);
24239732b024SMichael Rolnik 
24249732b024SMichael Rolnik     return true;
24259732b024SMichael Rolnik }
24269732b024SMichael Rolnik 
24279732b024SMichael Rolnik /*
24289732b024SMichael Rolnik  *  Load one byte indirect from data space to register and stores and clear
24299732b024SMichael Rolnik  *  the bits in data space specified by the register. The instruction can
24309732b024SMichael Rolnik  *  only be used towards internal SRAM.  The data location is pointed to by
24319732b024SMichael Rolnik  *  the Z (16 bits) Pointer Register in the Register File. Memory access is
24329732b024SMichael Rolnik  *  limited to the current data segment of 64KB. To access another data
24339732b024SMichael Rolnik  *  segment in devices with more than 64KB data space, the RAMPZ in register
24349732b024SMichael Rolnik  *  in the I/O area has to be changed.
24359732b024SMichael Rolnik  *
24369732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
24379732b024SMichael Rolnik  *  is especially suited for clearing status bits stored in SRAM.
24389732b024SMichael Rolnik  */
24399732b024SMichael Rolnik static bool trans_LAC(DisasContext *ctx, arg_LAC *a)
24409732b024SMichael Rolnik {
24419732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
24429732b024SMichael Rolnik         return true;
24439732b024SMichael Rolnik     }
24449732b024SMichael Rolnik 
24459732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rd];
24469732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
24479732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
24489732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
24499732b024SMichael Rolnik 
24509732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
24519732b024SMichael Rolnik     tcg_gen_andc_tl(t1, t0, Rr); /* t1 = t0 & (0xff - Rr) = t0 & ~Rr */
24529732b024SMichael Rolnik     tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
24539732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
24549732b024SMichael Rolnik 
24559732b024SMichael Rolnik     tcg_temp_free_i32(t1);
24569732b024SMichael Rolnik     tcg_temp_free_i32(t0);
24579732b024SMichael Rolnik     tcg_temp_free_i32(addr);
24589732b024SMichael Rolnik 
24599732b024SMichael Rolnik     return true;
24609732b024SMichael Rolnik }
24619732b024SMichael Rolnik 
24629732b024SMichael Rolnik 
24639732b024SMichael Rolnik /*
24649732b024SMichael Rolnik  *  Load one byte indirect from data space to register and toggles bits in
24659732b024SMichael Rolnik  *  the data space specified by the register.  The instruction can only be used
24669732b024SMichael Rolnik  *  towards SRAM.  The data location is pointed to by the Z (16 bits) Pointer
24679732b024SMichael Rolnik  *  Register in the Register File. Memory access is limited to the current data
24689732b024SMichael Rolnik  *  segment of 64KB. To access another data segment in devices with more than
24699732b024SMichael Rolnik  *  64KB data space, the RAMPZ in register in the I/O area has to be changed.
24709732b024SMichael Rolnik  *
24719732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
24729732b024SMichael Rolnik  *  is especially suited for changing status bits stored in SRAM.
24739732b024SMichael Rolnik  */
24749732b024SMichael Rolnik static bool trans_LAT(DisasContext *ctx, arg_LAT *a)
24759732b024SMichael Rolnik {
24769732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
24779732b024SMichael Rolnik         return true;
24789732b024SMichael Rolnik     }
24799732b024SMichael Rolnik 
24809732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
24819732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
24829732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
24839732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
24849732b024SMichael Rolnik 
24859732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
24869732b024SMichael Rolnik     tcg_gen_xor_tl(t1, t0, Rd);
24879732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, t0); /* Rd = t0 */
24889732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
24899732b024SMichael Rolnik 
24909732b024SMichael Rolnik     tcg_temp_free_i32(t1);
24919732b024SMichael Rolnik     tcg_temp_free_i32(t0);
24929732b024SMichael Rolnik     tcg_temp_free_i32(addr);
24939732b024SMichael Rolnik 
24949732b024SMichael Rolnik     return true;
24959732b024SMichael Rolnik }
2496*5718cef0SMichael Rolnik 
2497*5718cef0SMichael Rolnik /*
2498*5718cef0SMichael Rolnik  * Bit and Bit-test Instructions
2499*5718cef0SMichael Rolnik  */
2500*5718cef0SMichael Rolnik static void gen_rshift_ZNVSf(TCGv R)
2501*5718cef0SMichael Rolnik {
2502*5718cef0SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
2503*5718cef0SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
2504*5718cef0SMichael Rolnik     tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf);
2505*5718cef0SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
2506*5718cef0SMichael Rolnik }
2507*5718cef0SMichael Rolnik 
2508*5718cef0SMichael Rolnik /*
2509*5718cef0SMichael Rolnik  *  Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is
2510*5718cef0SMichael Rolnik  *  loaded into the C Flag of the SREG. This operation effectively divides an
2511*5718cef0SMichael Rolnik  *  unsigned value by two. The C Flag can be used to round the result.
2512*5718cef0SMichael Rolnik  */
2513*5718cef0SMichael Rolnik static bool trans_LSR(DisasContext *ctx, arg_LSR *a)
2514*5718cef0SMichael Rolnik {
2515*5718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2516*5718cef0SMichael Rolnik 
2517*5718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Cf, Rd, 1);
2518*5718cef0SMichael Rolnik     tcg_gen_shri_tl(Rd, Rd, 1);
2519*5718cef0SMichael Rolnik 
2520*5718cef0SMichael Rolnik     /* update status register */
2521*5718cef0SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, Rd, 0); /* Zf = Rd == 0 */
2522*5718cef0SMichael Rolnik     tcg_gen_movi_tl(cpu_Nf, 0);
2523*5718cef0SMichael Rolnik     tcg_gen_mov_tl(cpu_Vf, cpu_Cf);
2524*5718cef0SMichael Rolnik     tcg_gen_mov_tl(cpu_Sf, cpu_Vf);
2525*5718cef0SMichael Rolnik 
2526*5718cef0SMichael Rolnik     return true;
2527*5718cef0SMichael Rolnik }
2528*5718cef0SMichael Rolnik 
2529*5718cef0SMichael Rolnik /*
2530*5718cef0SMichael Rolnik  *  Shifts all bits in Rd one place to the right. The C Flag is shifted into
2531*5718cef0SMichael Rolnik  *  bit 7 of Rd. Bit 0 is shifted into the C Flag.  This operation, combined
2532*5718cef0SMichael Rolnik  *  with ASR, effectively divides multi-byte signed values by two. Combined with
2533*5718cef0SMichael Rolnik  *  LSR it effectively divides multi-byte unsigned values by two. The Carry Flag
2534*5718cef0SMichael Rolnik  *  can be used to round the result.
2535*5718cef0SMichael Rolnik  */
2536*5718cef0SMichael Rolnik static bool trans_ROR(DisasContext *ctx, arg_ROR *a)
2537*5718cef0SMichael Rolnik {
2538*5718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2539*5718cef0SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
2540*5718cef0SMichael Rolnik 
2541*5718cef0SMichael Rolnik     tcg_gen_shli_tl(t0, cpu_Cf, 7);
2542*5718cef0SMichael Rolnik 
2543*5718cef0SMichael Rolnik     /* update status register */
2544*5718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Cf, Rd, 1);
2545*5718cef0SMichael Rolnik 
2546*5718cef0SMichael Rolnik     /* update output register */
2547*5718cef0SMichael Rolnik     tcg_gen_shri_tl(Rd, Rd, 1);
2548*5718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, Rd, t0);
2549*5718cef0SMichael Rolnik 
2550*5718cef0SMichael Rolnik     /* update status register */
2551*5718cef0SMichael Rolnik     gen_rshift_ZNVSf(Rd);
2552*5718cef0SMichael Rolnik 
2553*5718cef0SMichael Rolnik     tcg_temp_free_i32(t0);
2554*5718cef0SMichael Rolnik 
2555*5718cef0SMichael Rolnik     return true;
2556*5718cef0SMichael Rolnik }
2557*5718cef0SMichael Rolnik 
2558*5718cef0SMichael Rolnik /*
2559*5718cef0SMichael Rolnik  *  Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0
2560*5718cef0SMichael Rolnik  *  is loaded into the C Flag of the SREG. This operation effectively divides a
2561*5718cef0SMichael Rolnik  *  signed value by two without changing its sign. The Carry Flag can be used to
2562*5718cef0SMichael Rolnik  *  round the result.
2563*5718cef0SMichael Rolnik  */
2564*5718cef0SMichael Rolnik static bool trans_ASR(DisasContext *ctx, arg_ASR *a)
2565*5718cef0SMichael Rolnik {
2566*5718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2567*5718cef0SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
2568*5718cef0SMichael Rolnik 
2569*5718cef0SMichael Rolnik     /* update status register */
2570*5718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */
2571*5718cef0SMichael Rolnik 
2572*5718cef0SMichael Rolnik     /* update output register */
2573*5718cef0SMichael Rolnik     tcg_gen_andi_tl(t0, Rd, 0x80); /* Rd = (Rd & 0x80) | (Rd >> 1) */
2574*5718cef0SMichael Rolnik     tcg_gen_shri_tl(Rd, Rd, 1);
2575*5718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, Rd, t0);
2576*5718cef0SMichael Rolnik 
2577*5718cef0SMichael Rolnik     /* update status register */
2578*5718cef0SMichael Rolnik     gen_rshift_ZNVSf(Rd);
2579*5718cef0SMichael Rolnik 
2580*5718cef0SMichael Rolnik     tcg_temp_free_i32(t0);
2581*5718cef0SMichael Rolnik 
2582*5718cef0SMichael Rolnik     return true;
2583*5718cef0SMichael Rolnik }
2584*5718cef0SMichael Rolnik 
2585*5718cef0SMichael Rolnik /*
2586*5718cef0SMichael Rolnik  *  Swaps high and low nibbles in a register.
2587*5718cef0SMichael Rolnik  */
2588*5718cef0SMichael Rolnik static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a)
2589*5718cef0SMichael Rolnik {
2590*5718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2591*5718cef0SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
2592*5718cef0SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
2593*5718cef0SMichael Rolnik 
2594*5718cef0SMichael Rolnik     tcg_gen_andi_tl(t0, Rd, 0x0f);
2595*5718cef0SMichael Rolnik     tcg_gen_shli_tl(t0, t0, 4);
2596*5718cef0SMichael Rolnik     tcg_gen_andi_tl(t1, Rd, 0xf0);
2597*5718cef0SMichael Rolnik     tcg_gen_shri_tl(t1, t1, 4);
2598*5718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, t0, t1);
2599*5718cef0SMichael Rolnik 
2600*5718cef0SMichael Rolnik     tcg_temp_free_i32(t1);
2601*5718cef0SMichael Rolnik     tcg_temp_free_i32(t0);
2602*5718cef0SMichael Rolnik 
2603*5718cef0SMichael Rolnik     return true;
2604*5718cef0SMichael Rolnik }
2605*5718cef0SMichael Rolnik 
2606*5718cef0SMichael Rolnik /*
2607*5718cef0SMichael Rolnik  *  Sets a specified bit in an I/O Register. This instruction operates on
2608*5718cef0SMichael Rolnik  *  the lower 32 I/O Registers -- addresses 0-31.
2609*5718cef0SMichael Rolnik  */
2610*5718cef0SMichael Rolnik static bool trans_SBI(DisasContext *ctx, arg_SBI *a)
2611*5718cef0SMichael Rolnik {
2612*5718cef0SMichael Rolnik     TCGv data = tcg_temp_new_i32();
2613*5718cef0SMichael Rolnik     TCGv port = tcg_const_i32(a->reg);
2614*5718cef0SMichael Rolnik 
2615*5718cef0SMichael Rolnik     gen_helper_inb(data, cpu_env, port);
2616*5718cef0SMichael Rolnik     tcg_gen_ori_tl(data, data, 1 << a->bit);
2617*5718cef0SMichael Rolnik     gen_helper_outb(cpu_env, port, data);
2618*5718cef0SMichael Rolnik 
2619*5718cef0SMichael Rolnik     tcg_temp_free_i32(port);
2620*5718cef0SMichael Rolnik     tcg_temp_free_i32(data);
2621*5718cef0SMichael Rolnik 
2622*5718cef0SMichael Rolnik     return true;
2623*5718cef0SMichael Rolnik }
2624*5718cef0SMichael Rolnik 
2625*5718cef0SMichael Rolnik /*
2626*5718cef0SMichael Rolnik  *  Clears a specified bit in an I/O Register. This instruction operates on
2627*5718cef0SMichael Rolnik  *  the lower 32 I/O Registers -- addresses 0-31.
2628*5718cef0SMichael Rolnik  */
2629*5718cef0SMichael Rolnik static bool trans_CBI(DisasContext *ctx, arg_CBI *a)
2630*5718cef0SMichael Rolnik {
2631*5718cef0SMichael Rolnik     TCGv data = tcg_temp_new_i32();
2632*5718cef0SMichael Rolnik     TCGv port = tcg_const_i32(a->reg);
2633*5718cef0SMichael Rolnik 
2634*5718cef0SMichael Rolnik     gen_helper_inb(data, cpu_env, port);
2635*5718cef0SMichael Rolnik     tcg_gen_andi_tl(data, data, ~(1 << a->bit));
2636*5718cef0SMichael Rolnik     gen_helper_outb(cpu_env, port, data);
2637*5718cef0SMichael Rolnik 
2638*5718cef0SMichael Rolnik     tcg_temp_free_i32(data);
2639*5718cef0SMichael Rolnik     tcg_temp_free_i32(port);
2640*5718cef0SMichael Rolnik 
2641*5718cef0SMichael Rolnik     return true;
2642*5718cef0SMichael Rolnik }
2643*5718cef0SMichael Rolnik 
2644*5718cef0SMichael Rolnik /*
2645*5718cef0SMichael Rolnik  *  Stores bit b from Rd to the T Flag in SREG (Status Register).
2646*5718cef0SMichael Rolnik  */
2647*5718cef0SMichael Rolnik static bool trans_BST(DisasContext *ctx, arg_BST *a)
2648*5718cef0SMichael Rolnik {
2649*5718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2650*5718cef0SMichael Rolnik 
2651*5718cef0SMichael Rolnik     tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit);
2652*5718cef0SMichael Rolnik     tcg_gen_shri_tl(cpu_Tf, cpu_Tf, a->bit);
2653*5718cef0SMichael Rolnik 
2654*5718cef0SMichael Rolnik     return true;
2655*5718cef0SMichael Rolnik }
2656*5718cef0SMichael Rolnik 
2657*5718cef0SMichael Rolnik /*
2658*5718cef0SMichael Rolnik  *  Copies the T Flag in the SREG (Status Register) to bit b in register Rd.
2659*5718cef0SMichael Rolnik  */
2660*5718cef0SMichael Rolnik static bool trans_BLD(DisasContext *ctx, arg_BLD *a)
2661*5718cef0SMichael Rolnik {
2662*5718cef0SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2663*5718cef0SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
2664*5718cef0SMichael Rolnik 
2665*5718cef0SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */
2666*5718cef0SMichael Rolnik     tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */
2667*5718cef0SMichael Rolnik     tcg_gen_or_tl(Rd, Rd, t1);
2668*5718cef0SMichael Rolnik 
2669*5718cef0SMichael Rolnik     tcg_temp_free_i32(t1);
2670*5718cef0SMichael Rolnik 
2671*5718cef0SMichael Rolnik     return true;
2672*5718cef0SMichael Rolnik }
2673*5718cef0SMichael Rolnik 
2674*5718cef0SMichael Rolnik /*
2675*5718cef0SMichael Rolnik  *  Sets a single Flag or bit in SREG.
2676*5718cef0SMichael Rolnik  */
2677*5718cef0SMichael Rolnik static bool trans_BSET(DisasContext *ctx, arg_BSET *a)
2678*5718cef0SMichael Rolnik {
2679*5718cef0SMichael Rolnik     switch (a->bit) {
2680*5718cef0SMichael Rolnik     case 0x00:
2681*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Cf, 0x01);
2682*5718cef0SMichael Rolnik         break;
2683*5718cef0SMichael Rolnik     case 0x01:
2684*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Zf, 0x01);
2685*5718cef0SMichael Rolnik         break;
2686*5718cef0SMichael Rolnik     case 0x02:
2687*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Nf, 0x01);
2688*5718cef0SMichael Rolnik         break;
2689*5718cef0SMichael Rolnik     case 0x03:
2690*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Vf, 0x01);
2691*5718cef0SMichael Rolnik         break;
2692*5718cef0SMichael Rolnik     case 0x04:
2693*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Sf, 0x01);
2694*5718cef0SMichael Rolnik         break;
2695*5718cef0SMichael Rolnik     case 0x05:
2696*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Hf, 0x01);
2697*5718cef0SMichael Rolnik         break;
2698*5718cef0SMichael Rolnik     case 0x06:
2699*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Tf, 0x01);
2700*5718cef0SMichael Rolnik         break;
2701*5718cef0SMichael Rolnik     case 0x07:
2702*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_If, 0x01);
2703*5718cef0SMichael Rolnik         break;
2704*5718cef0SMichael Rolnik     }
2705*5718cef0SMichael Rolnik 
2706*5718cef0SMichael Rolnik     return true;
2707*5718cef0SMichael Rolnik }
2708*5718cef0SMichael Rolnik 
2709*5718cef0SMichael Rolnik /*
2710*5718cef0SMichael Rolnik  *  Clears a single Flag in SREG.
2711*5718cef0SMichael Rolnik  */
2712*5718cef0SMichael Rolnik static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a)
2713*5718cef0SMichael Rolnik {
2714*5718cef0SMichael Rolnik     switch (a->bit) {
2715*5718cef0SMichael Rolnik     case 0x00:
2716*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Cf, 0x00);
2717*5718cef0SMichael Rolnik         break;
2718*5718cef0SMichael Rolnik     case 0x01:
2719*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Zf, 0x00);
2720*5718cef0SMichael Rolnik         break;
2721*5718cef0SMichael Rolnik     case 0x02:
2722*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Nf, 0x00);
2723*5718cef0SMichael Rolnik         break;
2724*5718cef0SMichael Rolnik     case 0x03:
2725*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Vf, 0x00);
2726*5718cef0SMichael Rolnik         break;
2727*5718cef0SMichael Rolnik     case 0x04:
2728*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Sf, 0x00);
2729*5718cef0SMichael Rolnik         break;
2730*5718cef0SMichael Rolnik     case 0x05:
2731*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Hf, 0x00);
2732*5718cef0SMichael Rolnik         break;
2733*5718cef0SMichael Rolnik     case 0x06:
2734*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_Tf, 0x00);
2735*5718cef0SMichael Rolnik         break;
2736*5718cef0SMichael Rolnik     case 0x07:
2737*5718cef0SMichael Rolnik         tcg_gen_movi_tl(cpu_If, 0x00);
2738*5718cef0SMichael Rolnik         break;
2739*5718cef0SMichael Rolnik     }
2740*5718cef0SMichael Rolnik 
2741*5718cef0SMichael Rolnik     return true;
2742*5718cef0SMichael Rolnik }
2743