xref: /openbmc/qemu/target/avr/translate.c (revision 865f3bb9)
1e03feba0SMichael Rolnik /*
2e03feba0SMichael Rolnik  * QEMU AVR CPU
3e03feba0SMichael Rolnik  *
4e03feba0SMichael Rolnik  * Copyright (c) 2019-2020 Michael Rolnik
5e03feba0SMichael Rolnik  *
6e03feba0SMichael Rolnik  * This library is free software; you can redistribute it and/or
7e03feba0SMichael Rolnik  * modify it under the terms of the GNU Lesser General Public
8e03feba0SMichael Rolnik  * License as published by the Free Software Foundation; either
9e03feba0SMichael Rolnik  * version 2.1 of the License, or (at your option) any later version.
10e03feba0SMichael Rolnik  *
11e03feba0SMichael Rolnik  * This library is distributed in the hope that it will be useful,
12e03feba0SMichael Rolnik  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13e03feba0SMichael Rolnik  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14e03feba0SMichael Rolnik  * Lesser General Public License for more details.
15e03feba0SMichael Rolnik  *
16e03feba0SMichael Rolnik  * You should have received a copy of the GNU Lesser General Public
17e03feba0SMichael Rolnik  * License along with this library; if not, see
18e03feba0SMichael Rolnik  * <http://www.gnu.org/licenses/lgpl-2.1.html>
19e03feba0SMichael Rolnik  */
20e03feba0SMichael Rolnik 
21e03feba0SMichael Rolnik #include "qemu/osdep.h"
22e03feba0SMichael Rolnik #include "qemu/qemu-print.h"
23e03feba0SMichael Rolnik #include "tcg/tcg.h"
24e03feba0SMichael Rolnik #include "cpu.h"
25e03feba0SMichael Rolnik #include "exec/exec-all.h"
26e03feba0SMichael Rolnik #include "tcg/tcg-op.h"
27e03feba0SMichael Rolnik #include "exec/cpu_ldst.h"
28e03feba0SMichael Rolnik #include "exec/helper-proto.h"
29e03feba0SMichael Rolnik #include "exec/helper-gen.h"
30e03feba0SMichael Rolnik #include "exec/log.h"
31e03feba0SMichael Rolnik #include "exec/translator.h"
32e03feba0SMichael Rolnik #include "exec/gen-icount.h"
33e03feba0SMichael Rolnik 
34e03feba0SMichael Rolnik /*
35e03feba0SMichael Rolnik  *  Define if you want a BREAK instruction translated to a breakpoint
36e03feba0SMichael Rolnik  *  Active debugging connection is assumed
37e03feba0SMichael Rolnik  *  This is for
38e03feba0SMichael Rolnik  *  https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tests
39e03feba0SMichael Rolnik  *  tests
40e03feba0SMichael Rolnik  */
41e03feba0SMichael Rolnik #undef BREAKPOINT_ON_BREAK
42e03feba0SMichael Rolnik 
43e03feba0SMichael Rolnik static TCGv cpu_pc;
44e03feba0SMichael Rolnik 
45e03feba0SMichael Rolnik static TCGv cpu_Cf;
46e03feba0SMichael Rolnik static TCGv cpu_Zf;
47e03feba0SMichael Rolnik static TCGv cpu_Nf;
48e03feba0SMichael Rolnik static TCGv cpu_Vf;
49e03feba0SMichael Rolnik static TCGv cpu_Sf;
50e03feba0SMichael Rolnik static TCGv cpu_Hf;
51e03feba0SMichael Rolnik static TCGv cpu_Tf;
52e03feba0SMichael Rolnik static TCGv cpu_If;
53e03feba0SMichael Rolnik 
54e03feba0SMichael Rolnik static TCGv cpu_rampD;
55e03feba0SMichael Rolnik static TCGv cpu_rampX;
56e03feba0SMichael Rolnik static TCGv cpu_rampY;
57e03feba0SMichael Rolnik static TCGv cpu_rampZ;
58e03feba0SMichael Rolnik 
59e03feba0SMichael Rolnik static TCGv cpu_r[NUMBER_OF_CPU_REGISTERS];
60e03feba0SMichael Rolnik static TCGv cpu_eind;
61e03feba0SMichael Rolnik static TCGv cpu_sp;
62e03feba0SMichael Rolnik 
63e03feba0SMichael Rolnik static TCGv cpu_skip;
64e03feba0SMichael Rolnik 
65e03feba0SMichael Rolnik static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = {
66e03feba0SMichael Rolnik     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
67e03feba0SMichael Rolnik     "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
68e03feba0SMichael Rolnik     "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
69e03feba0SMichael Rolnik     "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
70e03feba0SMichael Rolnik };
71e03feba0SMichael Rolnik #define REG(x) (cpu_r[x])
72e03feba0SMichael Rolnik 
73e03feba0SMichael Rolnik enum {
74e03feba0SMichael Rolnik     DISAS_EXIT   = DISAS_TARGET_0,  /* We want return to the cpu main loop.  */
75e03feba0SMichael Rolnik     DISAS_LOOKUP = DISAS_TARGET_1,  /* We have a variable condition exit.  */
76e03feba0SMichael Rolnik     DISAS_CHAIN  = DISAS_TARGET_2,  /* We have a single condition exit.  */
77e03feba0SMichael Rolnik };
78e03feba0SMichael Rolnik 
79e03feba0SMichael Rolnik typedef struct DisasContext DisasContext;
80e03feba0SMichael Rolnik 
81e03feba0SMichael Rolnik /* This is the state at translation time. */
82e03feba0SMichael Rolnik struct DisasContext {
83e03feba0SMichael Rolnik     TranslationBlock *tb;
84e03feba0SMichael Rolnik 
85e03feba0SMichael Rolnik     CPUAVRState *env;
86e03feba0SMichael Rolnik     CPUState *cs;
87e03feba0SMichael Rolnik 
88e03feba0SMichael Rolnik     target_long npc;
89e03feba0SMichael Rolnik     uint32_t opcode;
90e03feba0SMichael Rolnik 
91e03feba0SMichael Rolnik     /* Routine used to access memory */
92e03feba0SMichael Rolnik     int memidx;
93e03feba0SMichael Rolnik     int bstate;
94e03feba0SMichael Rolnik     int singlestep;
95e03feba0SMichael Rolnik 
96e03feba0SMichael Rolnik     /*
97e03feba0SMichael Rolnik      * some AVR instructions can make the following instruction to be skipped
98e03feba0SMichael Rolnik      * Let's name those instructions
99e03feba0SMichael Rolnik      *     A   - instruction that can skip the next one
100e03feba0SMichael Rolnik      *     B   - instruction that can be skipped. this depends on execution of A
101e03feba0SMichael Rolnik      * there are two scenarios
102e03feba0SMichael Rolnik      * 1. A and B belong to the same translation block
103e03feba0SMichael Rolnik      * 2. A is the last instruction in the translation block and B is the last
104e03feba0SMichael Rolnik      *
105e03feba0SMichael Rolnik      * following variables are used to simplify the skipping logic, they are
106e03feba0SMichael Rolnik      * used in the following manner (sketch)
107e03feba0SMichael Rolnik      *
108e03feba0SMichael Rolnik      * TCGLabel *skip_label = NULL;
109e03feba0SMichael Rolnik      * if (ctx.skip_cond != TCG_COND_NEVER) {
110e03feba0SMichael Rolnik      *     skip_label = gen_new_label();
111e03feba0SMichael Rolnik      *     tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label);
112e03feba0SMichael Rolnik      * }
113e03feba0SMichael Rolnik      *
114e03feba0SMichael Rolnik      * if (free_skip_var0) {
115e03feba0SMichael Rolnik      *     tcg_temp_free(skip_var0);
116e03feba0SMichael Rolnik      *     free_skip_var0 = false;
117e03feba0SMichael Rolnik      * }
118e03feba0SMichael Rolnik      *
119e03feba0SMichael Rolnik      * translate(&ctx);
120e03feba0SMichael Rolnik      *
121e03feba0SMichael Rolnik      * if (skip_label) {
122e03feba0SMichael Rolnik      *     gen_set_label(skip_label);
123e03feba0SMichael Rolnik      * }
124e03feba0SMichael Rolnik      */
125e03feba0SMichael Rolnik     TCGv skip_var0;
126e03feba0SMichael Rolnik     TCGv skip_var1;
127e03feba0SMichael Rolnik     TCGCond skip_cond;
128e03feba0SMichael Rolnik     bool free_skip_var0;
129e03feba0SMichael Rolnik };
130e03feba0SMichael Rolnik 
131*865f3bb9SMichael Rolnik static int to_regs_16_31_by_one(DisasContext *ctx, int indx)
132*865f3bb9SMichael Rolnik {
133*865f3bb9SMichael Rolnik     return 16 + (indx % 16);
134*865f3bb9SMichael Rolnik }
135*865f3bb9SMichael Rolnik 
136*865f3bb9SMichael Rolnik static int to_regs_16_23_by_one(DisasContext *ctx, int indx)
137*865f3bb9SMichael Rolnik {
138*865f3bb9SMichael Rolnik     return 16 + (indx % 8);
139*865f3bb9SMichael Rolnik }
140*865f3bb9SMichael Rolnik 
141*865f3bb9SMichael Rolnik static int to_regs_24_30_by_two(DisasContext *ctx, int indx)
142*865f3bb9SMichael Rolnik {
143*865f3bb9SMichael Rolnik     return 24 + (indx % 4) * 2;
144*865f3bb9SMichael Rolnik }
145*865f3bb9SMichael Rolnik 
146*865f3bb9SMichael Rolnik 
147e03feba0SMichael Rolnik static bool avr_have_feature(DisasContext *ctx, int feature)
148e03feba0SMichael Rolnik {
149e03feba0SMichael Rolnik     if (!avr_feature(ctx->env, feature)) {
150e03feba0SMichael Rolnik         gen_helper_unsupported(cpu_env);
151e03feba0SMichael Rolnik         ctx->bstate = DISAS_NORETURN;
152e03feba0SMichael Rolnik         return false;
153e03feba0SMichael Rolnik     }
154e03feba0SMichael Rolnik     return true;
155e03feba0SMichael Rolnik }
156e03feba0SMichael Rolnik 
157e03feba0SMichael Rolnik static bool decode_insn(DisasContext *ctx, uint16_t insn);
158e03feba0SMichael Rolnik #include "decode_insn.inc.c"
159*865f3bb9SMichael Rolnik 
160*865f3bb9SMichael Rolnik /*
161*865f3bb9SMichael Rolnik  * Arithmetic Instructions
162*865f3bb9SMichael Rolnik  */
163*865f3bb9SMichael Rolnik 
164*865f3bb9SMichael Rolnik /*
165*865f3bb9SMichael Rolnik  * Utility functions for updating status registers:
166*865f3bb9SMichael Rolnik  *
167*865f3bb9SMichael Rolnik  *   - gen_add_CHf()
168*865f3bb9SMichael Rolnik  *   - gen_add_Vf()
169*865f3bb9SMichael Rolnik  *   - gen_sub_CHf()
170*865f3bb9SMichael Rolnik  *   - gen_sub_Vf()
171*865f3bb9SMichael Rolnik  *   - gen_NSf()
172*865f3bb9SMichael Rolnik  *   - gen_ZNSf()
173*865f3bb9SMichael Rolnik  *
174*865f3bb9SMichael Rolnik  */
175*865f3bb9SMichael Rolnik 
176*865f3bb9SMichael Rolnik static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr)
177*865f3bb9SMichael Rolnik {
178*865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
179*865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
180*865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
181*865f3bb9SMichael Rolnik 
182*865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */
183*865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */
184*865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */
185*865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */
186*865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t3);
187*865f3bb9SMichael Rolnik 
188*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */
189*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */
190*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
191*865f3bb9SMichael Rolnik 
192*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t3);
193*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
194*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
195*865f3bb9SMichael Rolnik }
196*865f3bb9SMichael Rolnik 
197*865f3bb9SMichael Rolnik static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
198*865f3bb9SMichael Rolnik {
199*865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
200*865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
201*865f3bb9SMichael Rolnik 
202*865f3bb9SMichael Rolnik     /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */
203*865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & ~(Rd ^ Rr) */
204*865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
205*865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
206*865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t1, t1, t2);
207*865f3bb9SMichael Rolnik 
208*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
209*865f3bb9SMichael Rolnik 
210*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
211*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
212*865f3bb9SMichael Rolnik }
213*865f3bb9SMichael Rolnik 
214*865f3bb9SMichael Rolnik static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
215*865f3bb9SMichael Rolnik {
216*865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
217*865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
218*865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
219*865f3bb9SMichael Rolnik 
220*865f3bb9SMichael Rolnik     tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */
221*865f3bb9SMichael Rolnik     tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */
222*865f3bb9SMichael Rolnik     tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */
223*865f3bb9SMichael Rolnik     tcg_gen_and_tl(t3, t3, R);
224*865f3bb9SMichael Rolnik     tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */
225*865f3bb9SMichael Rolnik 
226*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */
227*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */
228*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
229*865f3bb9SMichael Rolnik 
230*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t3);
231*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
232*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
233*865f3bb9SMichael Rolnik }
234*865f3bb9SMichael Rolnik 
235*865f3bb9SMichael Rolnik static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
236*865f3bb9SMichael Rolnik {
237*865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
238*865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
239*865f3bb9SMichael Rolnik 
240*865f3bb9SMichael Rolnik     /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */
241*865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & (Rd ^ R) */
242*865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
243*865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
244*865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, t1, t2);
245*865f3bb9SMichael Rolnik 
246*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
247*865f3bb9SMichael Rolnik 
248*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
249*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
250*865f3bb9SMichael Rolnik }
251*865f3bb9SMichael Rolnik 
252*865f3bb9SMichael Rolnik static void gen_NSf(TCGv R)
253*865f3bb9SMichael Rolnik {
254*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
255*865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
256*865f3bb9SMichael Rolnik }
257*865f3bb9SMichael Rolnik 
258*865f3bb9SMichael Rolnik static void gen_ZNSf(TCGv R)
259*865f3bb9SMichael Rolnik {
260*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
261*865f3bb9SMichael Rolnik 
262*865f3bb9SMichael Rolnik     /* update status register */
263*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
264*865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
265*865f3bb9SMichael Rolnik }
266*865f3bb9SMichael Rolnik 
267*865f3bb9SMichael Rolnik /*
268*865f3bb9SMichael Rolnik  *  Adds two registers without the C Flag and places the result in the
269*865f3bb9SMichael Rolnik  *  destination register Rd.
270*865f3bb9SMichael Rolnik  */
271*865f3bb9SMichael Rolnik static bool trans_ADD(DisasContext *ctx, arg_ADD *a)
272*865f3bb9SMichael Rolnik {
273*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
274*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
275*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
276*865f3bb9SMichael Rolnik 
277*865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */
278*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
279*865f3bb9SMichael Rolnik 
280*865f3bb9SMichael Rolnik     /* update status register */
281*865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
282*865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
283*865f3bb9SMichael Rolnik     gen_ZNSf(R);
284*865f3bb9SMichael Rolnik 
285*865f3bb9SMichael Rolnik     /* update output registers */
286*865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
287*865f3bb9SMichael Rolnik 
288*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
289*865f3bb9SMichael Rolnik 
290*865f3bb9SMichael Rolnik     return true;
291*865f3bb9SMichael Rolnik }
292*865f3bb9SMichael Rolnik 
293*865f3bb9SMichael Rolnik /*
294*865f3bb9SMichael Rolnik  *  Adds two registers and the contents of the C Flag and places the result in
295*865f3bb9SMichael Rolnik  *  the destination register Rd.
296*865f3bb9SMichael Rolnik  */
297*865f3bb9SMichael Rolnik static bool trans_ADC(DisasContext *ctx, arg_ADC *a)
298*865f3bb9SMichael Rolnik {
299*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
300*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
301*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
302*865f3bb9SMichael Rolnik 
303*865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */
304*865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, R, cpu_Cf);
305*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
306*865f3bb9SMichael Rolnik 
307*865f3bb9SMichael Rolnik     /* update status register */
308*865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
309*865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
310*865f3bb9SMichael Rolnik     gen_ZNSf(R);
311*865f3bb9SMichael Rolnik 
312*865f3bb9SMichael Rolnik     /* update output registers */
313*865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
314*865f3bb9SMichael Rolnik 
315*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
316*865f3bb9SMichael Rolnik 
317*865f3bb9SMichael Rolnik     return true;
318*865f3bb9SMichael Rolnik }
319*865f3bb9SMichael Rolnik 
320*865f3bb9SMichael Rolnik /*
321*865f3bb9SMichael Rolnik  *  Adds an immediate value (0 - 63) to a register pair and places the result
322*865f3bb9SMichael Rolnik  *  in the register pair. This instruction operates on the upper four register
323*865f3bb9SMichael Rolnik  *  pairs, and is well suited for operations on the pointer registers.  This
324*865f3bb9SMichael Rolnik  *  instruction is not available in all devices. Refer to the device specific
325*865f3bb9SMichael Rolnik  *  instruction set summary.
326*865f3bb9SMichael Rolnik  */
327*865f3bb9SMichael Rolnik static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a)
328*865f3bb9SMichael Rolnik {
329*865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
330*865f3bb9SMichael Rolnik         return true;
331*865f3bb9SMichael Rolnik     }
332*865f3bb9SMichael Rolnik 
333*865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
334*865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
335*865f3bb9SMichael Rolnik     int Imm = (a->imm);
336*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
337*865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
338*865f3bb9SMichael Rolnik 
339*865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
340*865f3bb9SMichael Rolnik     tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */
341*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
342*865f3bb9SMichael Rolnik 
343*865f3bb9SMichael Rolnik     /* update status register */
344*865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
345*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15);
346*865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */
347*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15);
348*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
349*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
350*865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */
351*865f3bb9SMichael Rolnik 
352*865f3bb9SMichael Rolnik     /* update output registers */
353*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
354*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
355*865f3bb9SMichael Rolnik 
356*865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rd);
357*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
358*865f3bb9SMichael Rolnik 
359*865f3bb9SMichael Rolnik     return true;
360*865f3bb9SMichael Rolnik }
361*865f3bb9SMichael Rolnik 
362*865f3bb9SMichael Rolnik /*
363*865f3bb9SMichael Rolnik  *  Subtracts two registers and places the result in the destination
364*865f3bb9SMichael Rolnik  *  register Rd.
365*865f3bb9SMichael Rolnik  */
366*865f3bb9SMichael Rolnik static bool trans_SUB(DisasContext *ctx, arg_SUB *a)
367*865f3bb9SMichael Rolnik {
368*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
369*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
370*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
371*865f3bb9SMichael Rolnik 
372*865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
373*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
374*865f3bb9SMichael Rolnik 
375*865f3bb9SMichael Rolnik     /* update status register */
376*865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
377*865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
378*865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
379*865f3bb9SMichael Rolnik     gen_ZNSf(R);
380*865f3bb9SMichael Rolnik 
381*865f3bb9SMichael Rolnik     /* update output registers */
382*865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
383*865f3bb9SMichael Rolnik 
384*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
385*865f3bb9SMichael Rolnik 
386*865f3bb9SMichael Rolnik     return true;
387*865f3bb9SMichael Rolnik }
388*865f3bb9SMichael Rolnik 
389*865f3bb9SMichael Rolnik /*
390*865f3bb9SMichael Rolnik  *  Subtracts a register and a constant and places the result in the
391*865f3bb9SMichael Rolnik  *  destination register Rd. This instruction is working on Register R16 to R31
392*865f3bb9SMichael Rolnik  *  and is very well suited for operations on the X, Y, and Z-pointers.
393*865f3bb9SMichael Rolnik  */
394*865f3bb9SMichael Rolnik static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a)
395*865f3bb9SMichael Rolnik {
396*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
397*865f3bb9SMichael Rolnik     TCGv Rr = tcg_const_i32(a->imm);
398*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
399*865f3bb9SMichael Rolnik 
400*865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */
401*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
402*865f3bb9SMichael Rolnik 
403*865f3bb9SMichael Rolnik     /* update status register */
404*865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
405*865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
406*865f3bb9SMichael Rolnik     gen_ZNSf(R);
407*865f3bb9SMichael Rolnik 
408*865f3bb9SMichael Rolnik     /* update output registers */
409*865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
410*865f3bb9SMichael Rolnik 
411*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
412*865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rr);
413*865f3bb9SMichael Rolnik 
414*865f3bb9SMichael Rolnik     return true;
415*865f3bb9SMichael Rolnik }
416*865f3bb9SMichael Rolnik 
417*865f3bb9SMichael Rolnik /*
418*865f3bb9SMichael Rolnik  *  Subtracts two registers and subtracts with the C Flag and places the
419*865f3bb9SMichael Rolnik  *  result in the destination register Rd.
420*865f3bb9SMichael Rolnik  */
421*865f3bb9SMichael Rolnik static bool trans_SBC(DisasContext *ctx, arg_SBC *a)
422*865f3bb9SMichael Rolnik {
423*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
424*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
425*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
426*865f3bb9SMichael Rolnik     TCGv zero = tcg_const_i32(0);
427*865f3bb9SMichael Rolnik 
428*865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
429*865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
430*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
431*865f3bb9SMichael Rolnik 
432*865f3bb9SMichael Rolnik     /* update status register */
433*865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
434*865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
435*865f3bb9SMichael Rolnik     gen_NSf(R);
436*865f3bb9SMichael Rolnik 
437*865f3bb9SMichael Rolnik     /*
438*865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
439*865f3bb9SMichael Rolnik      * cleared otherwise.
440*865f3bb9SMichael Rolnik      */
441*865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
442*865f3bb9SMichael Rolnik 
443*865f3bb9SMichael Rolnik     /* update output registers */
444*865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
445*865f3bb9SMichael Rolnik 
446*865f3bb9SMichael Rolnik     tcg_temp_free_i32(zero);
447*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
448*865f3bb9SMichael Rolnik 
449*865f3bb9SMichael Rolnik     return true;
450*865f3bb9SMichael Rolnik }
451*865f3bb9SMichael Rolnik 
452*865f3bb9SMichael Rolnik /*
453*865f3bb9SMichael Rolnik  *  SBCI -- Subtract Immediate with Carry
454*865f3bb9SMichael Rolnik  */
455*865f3bb9SMichael Rolnik static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a)
456*865f3bb9SMichael Rolnik {
457*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
458*865f3bb9SMichael Rolnik     TCGv Rr = tcg_const_i32(a->imm);
459*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
460*865f3bb9SMichael Rolnik     TCGv zero = tcg_const_i32(0);
461*865f3bb9SMichael Rolnik 
462*865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
463*865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
464*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
465*865f3bb9SMichael Rolnik 
466*865f3bb9SMichael Rolnik     /* update status register */
467*865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
468*865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
469*865f3bb9SMichael Rolnik     gen_NSf(R);
470*865f3bb9SMichael Rolnik 
471*865f3bb9SMichael Rolnik     /*
472*865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
473*865f3bb9SMichael Rolnik      * cleared otherwise.
474*865f3bb9SMichael Rolnik      */
475*865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
476*865f3bb9SMichael Rolnik 
477*865f3bb9SMichael Rolnik     /* update output registers */
478*865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
479*865f3bb9SMichael Rolnik 
480*865f3bb9SMichael Rolnik     tcg_temp_free_i32(zero);
481*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
482*865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rr);
483*865f3bb9SMichael Rolnik 
484*865f3bb9SMichael Rolnik     return true;
485*865f3bb9SMichael Rolnik }
486*865f3bb9SMichael Rolnik 
487*865f3bb9SMichael Rolnik /*
488*865f3bb9SMichael Rolnik  *  Subtracts an immediate value (0-63) from a register pair and places the
489*865f3bb9SMichael Rolnik  *  result in the register pair. This instruction operates on the upper four
490*865f3bb9SMichael Rolnik  *  register pairs, and is well suited for operations on the Pointer Registers.
491*865f3bb9SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
492*865f3bb9SMichael Rolnik  *  specific instruction set summary.
493*865f3bb9SMichael Rolnik  */
494*865f3bb9SMichael Rolnik static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a)
495*865f3bb9SMichael Rolnik {
496*865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
497*865f3bb9SMichael Rolnik         return true;
498*865f3bb9SMichael Rolnik     }
499*865f3bb9SMichael Rolnik 
500*865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
501*865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
502*865f3bb9SMichael Rolnik     int Imm = (a->imm);
503*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
504*865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
505*865f3bb9SMichael Rolnik 
506*865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
507*865f3bb9SMichael Rolnik     tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */
508*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
509*865f3bb9SMichael Rolnik 
510*865f3bb9SMichael Rolnik     /* update status register */
511*865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, R, Rd);
512*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */
513*865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, Rd, R);
514*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */
515*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
516*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
517*865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
518*865f3bb9SMichael Rolnik 
519*865f3bb9SMichael Rolnik     /* update output registers */
520*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
521*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
522*865f3bb9SMichael Rolnik 
523*865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rd);
524*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
525*865f3bb9SMichael Rolnik 
526*865f3bb9SMichael Rolnik     return true;
527*865f3bb9SMichael Rolnik }
528*865f3bb9SMichael Rolnik 
529*865f3bb9SMichael Rolnik /*
530*865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and register
531*865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
532*865f3bb9SMichael Rolnik  */
533*865f3bb9SMichael Rolnik static bool trans_AND(DisasContext *ctx, arg_AND *a)
534*865f3bb9SMichael Rolnik {
535*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
536*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
537*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
538*865f3bb9SMichael Rolnik 
539*865f3bb9SMichael Rolnik     tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */
540*865f3bb9SMichael Rolnik 
541*865f3bb9SMichael Rolnik     /* update status register */
542*865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
543*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
544*865f3bb9SMichael Rolnik     gen_ZNSf(R);
545*865f3bb9SMichael Rolnik 
546*865f3bb9SMichael Rolnik     /* update output registers */
547*865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
548*865f3bb9SMichael Rolnik 
549*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
550*865f3bb9SMichael Rolnik 
551*865f3bb9SMichael Rolnik     return true;
552*865f3bb9SMichael Rolnik }
553*865f3bb9SMichael Rolnik 
554*865f3bb9SMichael Rolnik /*
555*865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and a constant
556*865f3bb9SMichael Rolnik  *  and places the result in the destination register Rd.
557*865f3bb9SMichael Rolnik  */
558*865f3bb9SMichael Rolnik static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a)
559*865f3bb9SMichael Rolnik {
560*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
561*865f3bb9SMichael Rolnik     int Imm = (a->imm);
562*865f3bb9SMichael Rolnik 
563*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */
564*865f3bb9SMichael Rolnik 
565*865f3bb9SMichael Rolnik     /* update status register */
566*865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
567*865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
568*865f3bb9SMichael Rolnik 
569*865f3bb9SMichael Rolnik     return true;
570*865f3bb9SMichael Rolnik }
571*865f3bb9SMichael Rolnik 
572*865f3bb9SMichael Rolnik /*
573*865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and register
574*865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
575*865f3bb9SMichael Rolnik  */
576*865f3bb9SMichael Rolnik static bool trans_OR(DisasContext *ctx, arg_OR *a)
577*865f3bb9SMichael Rolnik {
578*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
579*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
580*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
581*865f3bb9SMichael Rolnik 
582*865f3bb9SMichael Rolnik     tcg_gen_or_tl(R, Rd, Rr);
583*865f3bb9SMichael Rolnik 
584*865f3bb9SMichael Rolnik     /* update status register */
585*865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
586*865f3bb9SMichael Rolnik     gen_ZNSf(R);
587*865f3bb9SMichael Rolnik 
588*865f3bb9SMichael Rolnik     /* update output registers */
589*865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
590*865f3bb9SMichael Rolnik 
591*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
592*865f3bb9SMichael Rolnik 
593*865f3bb9SMichael Rolnik     return true;
594*865f3bb9SMichael Rolnik }
595*865f3bb9SMichael Rolnik 
596*865f3bb9SMichael Rolnik /*
597*865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and a
598*865f3bb9SMichael Rolnik  *  constant and places the result in the destination register Rd.
599*865f3bb9SMichael Rolnik  */
600*865f3bb9SMichael Rolnik static bool trans_ORI(DisasContext *ctx, arg_ORI *a)
601*865f3bb9SMichael Rolnik {
602*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
603*865f3bb9SMichael Rolnik     int Imm = (a->imm);
604*865f3bb9SMichael Rolnik 
605*865f3bb9SMichael Rolnik     tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */
606*865f3bb9SMichael Rolnik 
607*865f3bb9SMichael Rolnik     /* update status register */
608*865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
609*865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
610*865f3bb9SMichael Rolnik 
611*865f3bb9SMichael Rolnik     return true;
612*865f3bb9SMichael Rolnik }
613*865f3bb9SMichael Rolnik 
614*865f3bb9SMichael Rolnik /*
615*865f3bb9SMichael Rolnik  *  Performs the logical EOR between the contents of register Rd and
616*865f3bb9SMichael Rolnik  *  register Rr and places the result in the destination register Rd.
617*865f3bb9SMichael Rolnik  */
618*865f3bb9SMichael Rolnik static bool trans_EOR(DisasContext *ctx, arg_EOR *a)
619*865f3bb9SMichael Rolnik {
620*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
621*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
622*865f3bb9SMichael Rolnik 
623*865f3bb9SMichael Rolnik     tcg_gen_xor_tl(Rd, Rd, Rr);
624*865f3bb9SMichael Rolnik 
625*865f3bb9SMichael Rolnik     /* update status register */
626*865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
627*865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
628*865f3bb9SMichael Rolnik 
629*865f3bb9SMichael Rolnik     return true;
630*865f3bb9SMichael Rolnik }
631*865f3bb9SMichael Rolnik 
632*865f3bb9SMichael Rolnik /*
633*865f3bb9SMichael Rolnik  *  Clears the specified bits in register Rd. Performs the logical AND
634*865f3bb9SMichael Rolnik  *  between the contents of register Rd and the complement of the constant mask
635*865f3bb9SMichael Rolnik  *  K. The result will be placed in register Rd.
636*865f3bb9SMichael Rolnik  */
637*865f3bb9SMichael Rolnik static bool trans_COM(DisasContext *ctx, arg_COM *a)
638*865f3bb9SMichael Rolnik {
639*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
640*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
641*865f3bb9SMichael Rolnik 
642*865f3bb9SMichael Rolnik     tcg_gen_xori_tl(Rd, Rd, 0xff);
643*865f3bb9SMichael Rolnik 
644*865f3bb9SMichael Rolnik     /* update status register */
645*865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */
646*865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
647*865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
648*865f3bb9SMichael Rolnik 
649*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
650*865f3bb9SMichael Rolnik 
651*865f3bb9SMichael Rolnik     return true;
652*865f3bb9SMichael Rolnik }
653*865f3bb9SMichael Rolnik 
654*865f3bb9SMichael Rolnik /*
655*865f3bb9SMichael Rolnik  *  Replaces the contents of register Rd with its two's complement; the
656*865f3bb9SMichael Rolnik  *  value $80 is left unchanged.
657*865f3bb9SMichael Rolnik  */
658*865f3bb9SMichael Rolnik static bool trans_NEG(DisasContext *ctx, arg_NEG *a)
659*865f3bb9SMichael Rolnik {
660*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
661*865f3bb9SMichael Rolnik     TCGv t0 = tcg_const_i32(0);
662*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
663*865f3bb9SMichael Rolnik 
664*865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */
665*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
666*865f3bb9SMichael Rolnik 
667*865f3bb9SMichael Rolnik     /* update status register */
668*865f3bb9SMichael Rolnik     gen_sub_CHf(R, t0, Rd);
669*865f3bb9SMichael Rolnik     gen_sub_Vf(R, t0, Rd);
670*865f3bb9SMichael Rolnik     gen_ZNSf(R);
671*865f3bb9SMichael Rolnik 
672*865f3bb9SMichael Rolnik     /* update output registers */
673*865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
674*865f3bb9SMichael Rolnik 
675*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
676*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
677*865f3bb9SMichael Rolnik 
678*865f3bb9SMichael Rolnik     return true;
679*865f3bb9SMichael Rolnik }
680*865f3bb9SMichael Rolnik 
681*865f3bb9SMichael Rolnik /*
682*865f3bb9SMichael Rolnik  *  Adds one -1- to the contents of register Rd and places the result in the
683*865f3bb9SMichael Rolnik  *  destination register Rd.  The C Flag in SREG is not affected by the
684*865f3bb9SMichael Rolnik  *  operation, thus allowing the INC instruction to be used on a loop counter in
685*865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned numbers, only
686*865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently. When
687*865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
688*865f3bb9SMichael Rolnik  */
689*865f3bb9SMichael Rolnik static bool trans_INC(DisasContext *ctx, arg_INC *a)
690*865f3bb9SMichael Rolnik {
691*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
692*865f3bb9SMichael Rolnik 
693*865f3bb9SMichael Rolnik     tcg_gen_addi_tl(Rd, Rd, 1);
694*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff);
695*865f3bb9SMichael Rolnik 
696*865f3bb9SMichael Rolnik     /* update status register */
697*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */
698*865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
699*865f3bb9SMichael Rolnik 
700*865f3bb9SMichael Rolnik     return true;
701*865f3bb9SMichael Rolnik }
702*865f3bb9SMichael Rolnik 
703*865f3bb9SMichael Rolnik /*
704*865f3bb9SMichael Rolnik  *  Subtracts one -1- from the contents of register Rd and places the result
705*865f3bb9SMichael Rolnik  *  in the destination register Rd.  The C Flag in SREG is not affected by the
706*865f3bb9SMichael Rolnik  *  operation, thus allowing the DEC instruction to be used on a loop counter in
707*865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned values, only
708*865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently.  When
709*865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
710*865f3bb9SMichael Rolnik  */
711*865f3bb9SMichael Rolnik static bool trans_DEC(DisasContext *ctx, arg_DEC *a)
712*865f3bb9SMichael Rolnik {
713*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
714*865f3bb9SMichael Rolnik 
715*865f3bb9SMichael Rolnik     tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
716*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
717*865f3bb9SMichael Rolnik 
718*865f3bb9SMichael Rolnik     /* update status register */
719*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */
720*865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
721*865f3bb9SMichael Rolnik 
722*865f3bb9SMichael Rolnik     return true;
723*865f3bb9SMichael Rolnik }
724*865f3bb9SMichael Rolnik 
725*865f3bb9SMichael Rolnik /*
726*865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication.
727*865f3bb9SMichael Rolnik  */
728*865f3bb9SMichael Rolnik static bool trans_MUL(DisasContext *ctx, arg_MUL *a)
729*865f3bb9SMichael Rolnik {
730*865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
731*865f3bb9SMichael Rolnik         return true;
732*865f3bb9SMichael Rolnik     }
733*865f3bb9SMichael Rolnik 
734*865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
735*865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
736*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
737*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
738*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
739*865f3bb9SMichael Rolnik 
740*865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
741*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
742*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
743*865f3bb9SMichael Rolnik 
744*865f3bb9SMichael Rolnik     /* update status register */
745*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
746*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
747*865f3bb9SMichael Rolnik 
748*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
749*865f3bb9SMichael Rolnik 
750*865f3bb9SMichael Rolnik     return true;
751*865f3bb9SMichael Rolnik }
752*865f3bb9SMichael Rolnik 
753*865f3bb9SMichael Rolnik /*
754*865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication.
755*865f3bb9SMichael Rolnik  */
756*865f3bb9SMichael Rolnik static bool trans_MULS(DisasContext *ctx, arg_MULS *a)
757*865f3bb9SMichael Rolnik {
758*865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
759*865f3bb9SMichael Rolnik         return true;
760*865f3bb9SMichael Rolnik     }
761*865f3bb9SMichael Rolnik 
762*865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
763*865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
764*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
765*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
766*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
767*865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
768*865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
769*865f3bb9SMichael Rolnik 
770*865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
771*865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
772*865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
773*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
774*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
775*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
776*865f3bb9SMichael Rolnik 
777*865f3bb9SMichael Rolnik     /* update status register */
778*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
779*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
780*865f3bb9SMichael Rolnik 
781*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
782*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
783*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
784*865f3bb9SMichael Rolnik 
785*865f3bb9SMichael Rolnik     return true;
786*865f3bb9SMichael Rolnik }
787*865f3bb9SMichael Rolnik 
788*865f3bb9SMichael Rolnik /*
789*865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a
790*865f3bb9SMichael Rolnik  *  signed and an unsigned number.
791*865f3bb9SMichael Rolnik  */
792*865f3bb9SMichael Rolnik static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a)
793*865f3bb9SMichael Rolnik {
794*865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
795*865f3bb9SMichael Rolnik         return true;
796*865f3bb9SMichael Rolnik     }
797*865f3bb9SMichael Rolnik 
798*865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
799*865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
800*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
801*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
802*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
803*865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
804*865f3bb9SMichael Rolnik 
805*865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
806*865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
807*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */
808*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
809*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
810*865f3bb9SMichael Rolnik 
811*865f3bb9SMichael Rolnik     /* update status register */
812*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
813*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
814*865f3bb9SMichael Rolnik 
815*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
816*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
817*865f3bb9SMichael Rolnik 
818*865f3bb9SMichael Rolnik     return true;
819*865f3bb9SMichael Rolnik }
820*865f3bb9SMichael Rolnik 
821*865f3bb9SMichael Rolnik /*
822*865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned
823*865f3bb9SMichael Rolnik  *  multiplication and shifts the result one bit left.
824*865f3bb9SMichael Rolnik  */
825*865f3bb9SMichael Rolnik static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a)
826*865f3bb9SMichael Rolnik {
827*865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
828*865f3bb9SMichael Rolnik         return true;
829*865f3bb9SMichael Rolnik     }
830*865f3bb9SMichael Rolnik 
831*865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
832*865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
833*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
834*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
835*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
836*865f3bb9SMichael Rolnik 
837*865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
838*865f3bb9SMichael Rolnik 
839*865f3bb9SMichael Rolnik     /* update status register */
840*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
841*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
842*865f3bb9SMichael Rolnik 
843*865f3bb9SMichael Rolnik     /* update output registers */
844*865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
845*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
846*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
847*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
848*865f3bb9SMichael Rolnik 
849*865f3bb9SMichael Rolnik 
850*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
851*865f3bb9SMichael Rolnik 
852*865f3bb9SMichael Rolnik     return true;
853*865f3bb9SMichael Rolnik }
854*865f3bb9SMichael Rolnik 
855*865f3bb9SMichael Rolnik /*
856*865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
857*865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
858*865f3bb9SMichael Rolnik  */
859*865f3bb9SMichael Rolnik static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a)
860*865f3bb9SMichael Rolnik {
861*865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
862*865f3bb9SMichael Rolnik         return true;
863*865f3bb9SMichael Rolnik     }
864*865f3bb9SMichael Rolnik 
865*865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
866*865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
867*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
868*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
869*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
870*865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
871*865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
872*865f3bb9SMichael Rolnik 
873*865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
874*865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
875*865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
876*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
877*865f3bb9SMichael Rolnik 
878*865f3bb9SMichael Rolnik     /* update status register */
879*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
880*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
881*865f3bb9SMichael Rolnik 
882*865f3bb9SMichael Rolnik     /* update output registers */
883*865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
884*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
885*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
886*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
887*865f3bb9SMichael Rolnik 
888*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
889*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
890*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
891*865f3bb9SMichael Rolnik 
892*865f3bb9SMichael Rolnik     return true;
893*865f3bb9SMichael Rolnik }
894*865f3bb9SMichael Rolnik 
895*865f3bb9SMichael Rolnik /*
896*865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
897*865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
898*865f3bb9SMichael Rolnik  */
899*865f3bb9SMichael Rolnik static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a)
900*865f3bb9SMichael Rolnik {
901*865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
902*865f3bb9SMichael Rolnik         return true;
903*865f3bb9SMichael Rolnik     }
904*865f3bb9SMichael Rolnik 
905*865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
906*865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
907*865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
908*865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
909*865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
910*865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
911*865f3bb9SMichael Rolnik 
912*865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
913*865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
914*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
915*865f3bb9SMichael Rolnik 
916*865f3bb9SMichael Rolnik     /* update status register */
917*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
918*865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
919*865f3bb9SMichael Rolnik 
920*865f3bb9SMichael Rolnik     /* update output registers */
921*865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
922*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
923*865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
924*865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
925*865f3bb9SMichael Rolnik 
926*865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
927*865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
928*865f3bb9SMichael Rolnik 
929*865f3bb9SMichael Rolnik     return true;
930*865f3bb9SMichael Rolnik }
931*865f3bb9SMichael Rolnik 
932*865f3bb9SMichael Rolnik /*
933*865f3bb9SMichael Rolnik  *  The module is an instruction set extension to the AVR CPU, performing
934*865f3bb9SMichael Rolnik  *  DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in
935*865f3bb9SMichael Rolnik  *  the CPU register file, registers R0-R7, where LSB of data is placed in LSB
936*865f3bb9SMichael Rolnik  *  of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including
937*865f3bb9SMichael Rolnik  *  parity bits) is placed in registers R8- R15, organized in the register file
938*865f3bb9SMichael Rolnik  *  with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES
939*865f3bb9SMichael Rolnik  *  instruction performs one round in the DES algorithm. Sixteen rounds must be
940*865f3bb9SMichael Rolnik  *  executed in increasing order to form the correct DES ciphertext or
941*865f3bb9SMichael Rolnik  *  plaintext. Intermediate results are stored in the register file (R0-R15)
942*865f3bb9SMichael Rolnik  *  after each DES instruction. The instruction's operand (K) determines which
943*865f3bb9SMichael Rolnik  *  round is executed, and the half carry flag (H) determines whether encryption
944*865f3bb9SMichael Rolnik  *  or decryption is performed.  The DES algorithm is described in
945*865f3bb9SMichael Rolnik  *  "Specifications for the Data Encryption Standard" (Federal Information
946*865f3bb9SMichael Rolnik  *  Processing Standards Publication 46). Intermediate results in this
947*865f3bb9SMichael Rolnik  *  implementation differ from the standard because the initial permutation and
948*865f3bb9SMichael Rolnik  *  the inverse initial permutation are performed each iteration. This does not
949*865f3bb9SMichael Rolnik  *  affect the result in the final ciphertext or plaintext, but reduces
950*865f3bb9SMichael Rolnik  *  execution time.
951*865f3bb9SMichael Rolnik  */
952*865f3bb9SMichael Rolnik static bool trans_DES(DisasContext *ctx, arg_DES *a)
953*865f3bb9SMichael Rolnik {
954*865f3bb9SMichael Rolnik     /* TODO */
955*865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_DES)) {
956*865f3bb9SMichael Rolnik         return true;
957*865f3bb9SMichael Rolnik     }
958*865f3bb9SMichael Rolnik 
959*865f3bb9SMichael Rolnik     qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
960*865f3bb9SMichael Rolnik 
961*865f3bb9SMichael Rolnik     return true;
962*865f3bb9SMichael Rolnik }
963