xref: /openbmc/qemu/target/avr/translate.c (revision 9d316c75)
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 
146865f3bb9SMichael Rolnik 
147*9d316c75SMichael Rolnik static uint16_t next_word(DisasContext *ctx)
148*9d316c75SMichael Rolnik {
149*9d316c75SMichael Rolnik     return cpu_lduw_code(ctx->env, ctx->npc++ * 2);
150*9d316c75SMichael Rolnik }
151*9d316c75SMichael Rolnik 
152*9d316c75SMichael Rolnik static int append_16(DisasContext *ctx, int x)
153*9d316c75SMichael Rolnik {
154*9d316c75SMichael Rolnik     return x << 16 | next_word(ctx);
155*9d316c75SMichael Rolnik }
156*9d316c75SMichael Rolnik 
157e03feba0SMichael Rolnik static bool avr_have_feature(DisasContext *ctx, int feature)
158e03feba0SMichael Rolnik {
159e03feba0SMichael Rolnik     if (!avr_feature(ctx->env, feature)) {
160e03feba0SMichael Rolnik         gen_helper_unsupported(cpu_env);
161e03feba0SMichael Rolnik         ctx->bstate = DISAS_NORETURN;
162e03feba0SMichael Rolnik         return false;
163e03feba0SMichael Rolnik     }
164e03feba0SMichael Rolnik     return true;
165e03feba0SMichael Rolnik }
166e03feba0SMichael Rolnik 
167e03feba0SMichael Rolnik static bool decode_insn(DisasContext *ctx, uint16_t insn);
168e03feba0SMichael Rolnik #include "decode_insn.inc.c"
169865f3bb9SMichael Rolnik 
170865f3bb9SMichael Rolnik /*
171865f3bb9SMichael Rolnik  * Arithmetic Instructions
172865f3bb9SMichael Rolnik  */
173865f3bb9SMichael Rolnik 
174865f3bb9SMichael Rolnik /*
175865f3bb9SMichael Rolnik  * Utility functions for updating status registers:
176865f3bb9SMichael Rolnik  *
177865f3bb9SMichael Rolnik  *   - gen_add_CHf()
178865f3bb9SMichael Rolnik  *   - gen_add_Vf()
179865f3bb9SMichael Rolnik  *   - gen_sub_CHf()
180865f3bb9SMichael Rolnik  *   - gen_sub_Vf()
181865f3bb9SMichael Rolnik  *   - gen_NSf()
182865f3bb9SMichael Rolnik  *   - gen_ZNSf()
183865f3bb9SMichael Rolnik  *
184865f3bb9SMichael Rolnik  */
185865f3bb9SMichael Rolnik 
186865f3bb9SMichael Rolnik static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr)
187865f3bb9SMichael Rolnik {
188865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
189865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
190865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
191865f3bb9SMichael Rolnik 
192865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */
193865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */
194865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */
195865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */
196865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t3);
197865f3bb9SMichael Rolnik 
198865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */
199865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */
200865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
201865f3bb9SMichael Rolnik 
202865f3bb9SMichael Rolnik     tcg_temp_free_i32(t3);
203865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
204865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
205865f3bb9SMichael Rolnik }
206865f3bb9SMichael Rolnik 
207865f3bb9SMichael Rolnik static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
208865f3bb9SMichael Rolnik {
209865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
210865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
211865f3bb9SMichael Rolnik 
212865f3bb9SMichael Rolnik     /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */
213865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & ~(Rd ^ Rr) */
214865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
215865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
216865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t1, t1, t2);
217865f3bb9SMichael Rolnik 
218865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
219865f3bb9SMichael Rolnik 
220865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
221865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
222865f3bb9SMichael Rolnik }
223865f3bb9SMichael Rolnik 
224865f3bb9SMichael Rolnik static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
225865f3bb9SMichael Rolnik {
226865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
227865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
228865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
229865f3bb9SMichael Rolnik 
230865f3bb9SMichael Rolnik     tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */
231865f3bb9SMichael Rolnik     tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */
232865f3bb9SMichael Rolnik     tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */
233865f3bb9SMichael Rolnik     tcg_gen_and_tl(t3, t3, R);
234865f3bb9SMichael Rolnik     tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */
235865f3bb9SMichael Rolnik 
236865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */
237865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */
238865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
239865f3bb9SMichael Rolnik 
240865f3bb9SMichael Rolnik     tcg_temp_free_i32(t3);
241865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
242865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
243865f3bb9SMichael Rolnik }
244865f3bb9SMichael Rolnik 
245865f3bb9SMichael Rolnik static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
246865f3bb9SMichael Rolnik {
247865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
248865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
249865f3bb9SMichael Rolnik 
250865f3bb9SMichael Rolnik     /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */
251865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & (Rd ^ R) */
252865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
253865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
254865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, t1, t2);
255865f3bb9SMichael Rolnik 
256865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
257865f3bb9SMichael Rolnik 
258865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
259865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
260865f3bb9SMichael Rolnik }
261865f3bb9SMichael Rolnik 
262865f3bb9SMichael Rolnik static void gen_NSf(TCGv R)
263865f3bb9SMichael Rolnik {
264865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
265865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
266865f3bb9SMichael Rolnik }
267865f3bb9SMichael Rolnik 
268865f3bb9SMichael Rolnik static void gen_ZNSf(TCGv R)
269865f3bb9SMichael Rolnik {
270865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
271865f3bb9SMichael Rolnik 
272865f3bb9SMichael Rolnik     /* update status register */
273865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
274865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
275865f3bb9SMichael Rolnik }
276865f3bb9SMichael Rolnik 
277865f3bb9SMichael Rolnik /*
278865f3bb9SMichael Rolnik  *  Adds two registers without the C Flag and places the result in the
279865f3bb9SMichael Rolnik  *  destination register Rd.
280865f3bb9SMichael Rolnik  */
281865f3bb9SMichael Rolnik static bool trans_ADD(DisasContext *ctx, arg_ADD *a)
282865f3bb9SMichael Rolnik {
283865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
284865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
285865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
286865f3bb9SMichael Rolnik 
287865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */
288865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
289865f3bb9SMichael Rolnik 
290865f3bb9SMichael Rolnik     /* update status register */
291865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
292865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
293865f3bb9SMichael Rolnik     gen_ZNSf(R);
294865f3bb9SMichael Rolnik 
295865f3bb9SMichael Rolnik     /* update output registers */
296865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
297865f3bb9SMichael Rolnik 
298865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
299865f3bb9SMichael Rolnik 
300865f3bb9SMichael Rolnik     return true;
301865f3bb9SMichael Rolnik }
302865f3bb9SMichael Rolnik 
303865f3bb9SMichael Rolnik /*
304865f3bb9SMichael Rolnik  *  Adds two registers and the contents of the C Flag and places the result in
305865f3bb9SMichael Rolnik  *  the destination register Rd.
306865f3bb9SMichael Rolnik  */
307865f3bb9SMichael Rolnik static bool trans_ADC(DisasContext *ctx, arg_ADC *a)
308865f3bb9SMichael Rolnik {
309865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
310865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
311865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
312865f3bb9SMichael Rolnik 
313865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */
314865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, R, cpu_Cf);
315865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
316865f3bb9SMichael Rolnik 
317865f3bb9SMichael Rolnik     /* update status register */
318865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
319865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
320865f3bb9SMichael Rolnik     gen_ZNSf(R);
321865f3bb9SMichael Rolnik 
322865f3bb9SMichael Rolnik     /* update output registers */
323865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
324865f3bb9SMichael Rolnik 
325865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
326865f3bb9SMichael Rolnik 
327865f3bb9SMichael Rolnik     return true;
328865f3bb9SMichael Rolnik }
329865f3bb9SMichael Rolnik 
330865f3bb9SMichael Rolnik /*
331865f3bb9SMichael Rolnik  *  Adds an immediate value (0 - 63) to a register pair and places the result
332865f3bb9SMichael Rolnik  *  in the register pair. This instruction operates on the upper four register
333865f3bb9SMichael Rolnik  *  pairs, and is well suited for operations on the pointer registers.  This
334865f3bb9SMichael Rolnik  *  instruction is not available in all devices. Refer to the device specific
335865f3bb9SMichael Rolnik  *  instruction set summary.
336865f3bb9SMichael Rolnik  */
337865f3bb9SMichael Rolnik static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a)
338865f3bb9SMichael Rolnik {
339865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
340865f3bb9SMichael Rolnik         return true;
341865f3bb9SMichael Rolnik     }
342865f3bb9SMichael Rolnik 
343865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
344865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
345865f3bb9SMichael Rolnik     int Imm = (a->imm);
346865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
347865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
348865f3bb9SMichael Rolnik 
349865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
350865f3bb9SMichael Rolnik     tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */
351865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
352865f3bb9SMichael Rolnik 
353865f3bb9SMichael Rolnik     /* update status register */
354865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
355865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15);
356865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */
357865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15);
358865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
359865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
360865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */
361865f3bb9SMichael Rolnik 
362865f3bb9SMichael Rolnik     /* update output registers */
363865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
364865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
365865f3bb9SMichael Rolnik 
366865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rd);
367865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
368865f3bb9SMichael Rolnik 
369865f3bb9SMichael Rolnik     return true;
370865f3bb9SMichael Rolnik }
371865f3bb9SMichael Rolnik 
372865f3bb9SMichael Rolnik /*
373865f3bb9SMichael Rolnik  *  Subtracts two registers and places the result in the destination
374865f3bb9SMichael Rolnik  *  register Rd.
375865f3bb9SMichael Rolnik  */
376865f3bb9SMichael Rolnik static bool trans_SUB(DisasContext *ctx, arg_SUB *a)
377865f3bb9SMichael Rolnik {
378865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
379865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
380865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
381865f3bb9SMichael Rolnik 
382865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
383865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
384865f3bb9SMichael Rolnik 
385865f3bb9SMichael Rolnik     /* update status register */
386865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
387865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
388865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
389865f3bb9SMichael Rolnik     gen_ZNSf(R);
390865f3bb9SMichael Rolnik 
391865f3bb9SMichael Rolnik     /* update output registers */
392865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
393865f3bb9SMichael Rolnik 
394865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
395865f3bb9SMichael Rolnik 
396865f3bb9SMichael Rolnik     return true;
397865f3bb9SMichael Rolnik }
398865f3bb9SMichael Rolnik 
399865f3bb9SMichael Rolnik /*
400865f3bb9SMichael Rolnik  *  Subtracts a register and a constant and places the result in the
401865f3bb9SMichael Rolnik  *  destination register Rd. This instruction is working on Register R16 to R31
402865f3bb9SMichael Rolnik  *  and is very well suited for operations on the X, Y, and Z-pointers.
403865f3bb9SMichael Rolnik  */
404865f3bb9SMichael Rolnik static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a)
405865f3bb9SMichael Rolnik {
406865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
407865f3bb9SMichael Rolnik     TCGv Rr = tcg_const_i32(a->imm);
408865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
409865f3bb9SMichael Rolnik 
410865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */
411865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
412865f3bb9SMichael Rolnik 
413865f3bb9SMichael Rolnik     /* update status register */
414865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
415865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
416865f3bb9SMichael Rolnik     gen_ZNSf(R);
417865f3bb9SMichael Rolnik 
418865f3bb9SMichael Rolnik     /* update output registers */
419865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
420865f3bb9SMichael Rolnik 
421865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
422865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rr);
423865f3bb9SMichael Rolnik 
424865f3bb9SMichael Rolnik     return true;
425865f3bb9SMichael Rolnik }
426865f3bb9SMichael Rolnik 
427865f3bb9SMichael Rolnik /*
428865f3bb9SMichael Rolnik  *  Subtracts two registers and subtracts with the C Flag and places the
429865f3bb9SMichael Rolnik  *  result in the destination register Rd.
430865f3bb9SMichael Rolnik  */
431865f3bb9SMichael Rolnik static bool trans_SBC(DisasContext *ctx, arg_SBC *a)
432865f3bb9SMichael Rolnik {
433865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
434865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
435865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
436865f3bb9SMichael Rolnik     TCGv zero = tcg_const_i32(0);
437865f3bb9SMichael Rolnik 
438865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
439865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
440865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
441865f3bb9SMichael Rolnik 
442865f3bb9SMichael Rolnik     /* update status register */
443865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
444865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
445865f3bb9SMichael Rolnik     gen_NSf(R);
446865f3bb9SMichael Rolnik 
447865f3bb9SMichael Rolnik     /*
448865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
449865f3bb9SMichael Rolnik      * cleared otherwise.
450865f3bb9SMichael Rolnik      */
451865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
452865f3bb9SMichael Rolnik 
453865f3bb9SMichael Rolnik     /* update output registers */
454865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
455865f3bb9SMichael Rolnik 
456865f3bb9SMichael Rolnik     tcg_temp_free_i32(zero);
457865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
458865f3bb9SMichael Rolnik 
459865f3bb9SMichael Rolnik     return true;
460865f3bb9SMichael Rolnik }
461865f3bb9SMichael Rolnik 
462865f3bb9SMichael Rolnik /*
463865f3bb9SMichael Rolnik  *  SBCI -- Subtract Immediate with Carry
464865f3bb9SMichael Rolnik  */
465865f3bb9SMichael Rolnik static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a)
466865f3bb9SMichael Rolnik {
467865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
468865f3bb9SMichael Rolnik     TCGv Rr = tcg_const_i32(a->imm);
469865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
470865f3bb9SMichael Rolnik     TCGv zero = tcg_const_i32(0);
471865f3bb9SMichael Rolnik 
472865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
473865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
474865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
475865f3bb9SMichael Rolnik 
476865f3bb9SMichael Rolnik     /* update status register */
477865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
478865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
479865f3bb9SMichael Rolnik     gen_NSf(R);
480865f3bb9SMichael Rolnik 
481865f3bb9SMichael Rolnik     /*
482865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
483865f3bb9SMichael Rolnik      * cleared otherwise.
484865f3bb9SMichael Rolnik      */
485865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
486865f3bb9SMichael Rolnik 
487865f3bb9SMichael Rolnik     /* update output registers */
488865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
489865f3bb9SMichael Rolnik 
490865f3bb9SMichael Rolnik     tcg_temp_free_i32(zero);
491865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
492865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rr);
493865f3bb9SMichael Rolnik 
494865f3bb9SMichael Rolnik     return true;
495865f3bb9SMichael Rolnik }
496865f3bb9SMichael Rolnik 
497865f3bb9SMichael Rolnik /*
498865f3bb9SMichael Rolnik  *  Subtracts an immediate value (0-63) from a register pair and places the
499865f3bb9SMichael Rolnik  *  result in the register pair. This instruction operates on the upper four
500865f3bb9SMichael Rolnik  *  register pairs, and is well suited for operations on the Pointer Registers.
501865f3bb9SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
502865f3bb9SMichael Rolnik  *  specific instruction set summary.
503865f3bb9SMichael Rolnik  */
504865f3bb9SMichael Rolnik static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a)
505865f3bb9SMichael Rolnik {
506865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
507865f3bb9SMichael Rolnik         return true;
508865f3bb9SMichael Rolnik     }
509865f3bb9SMichael Rolnik 
510865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
511865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
512865f3bb9SMichael Rolnik     int Imm = (a->imm);
513865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
514865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
515865f3bb9SMichael Rolnik 
516865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
517865f3bb9SMichael Rolnik     tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */
518865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
519865f3bb9SMichael Rolnik 
520865f3bb9SMichael Rolnik     /* update status register */
521865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, R, Rd);
522865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */
523865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, Rd, R);
524865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */
525865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
526865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
527865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
528865f3bb9SMichael Rolnik 
529865f3bb9SMichael Rolnik     /* update output registers */
530865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
531865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
532865f3bb9SMichael Rolnik 
533865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rd);
534865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
535865f3bb9SMichael Rolnik 
536865f3bb9SMichael Rolnik     return true;
537865f3bb9SMichael Rolnik }
538865f3bb9SMichael Rolnik 
539865f3bb9SMichael Rolnik /*
540865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and register
541865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
542865f3bb9SMichael Rolnik  */
543865f3bb9SMichael Rolnik static bool trans_AND(DisasContext *ctx, arg_AND *a)
544865f3bb9SMichael Rolnik {
545865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
546865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
547865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
548865f3bb9SMichael Rolnik 
549865f3bb9SMichael Rolnik     tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */
550865f3bb9SMichael Rolnik 
551865f3bb9SMichael Rolnik     /* update status register */
552865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
553865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
554865f3bb9SMichael Rolnik     gen_ZNSf(R);
555865f3bb9SMichael Rolnik 
556865f3bb9SMichael Rolnik     /* update output registers */
557865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
558865f3bb9SMichael Rolnik 
559865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
560865f3bb9SMichael Rolnik 
561865f3bb9SMichael Rolnik     return true;
562865f3bb9SMichael Rolnik }
563865f3bb9SMichael Rolnik 
564865f3bb9SMichael Rolnik /*
565865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and a constant
566865f3bb9SMichael Rolnik  *  and places the result in the destination register Rd.
567865f3bb9SMichael Rolnik  */
568865f3bb9SMichael Rolnik static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a)
569865f3bb9SMichael Rolnik {
570865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
571865f3bb9SMichael Rolnik     int Imm = (a->imm);
572865f3bb9SMichael Rolnik 
573865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */
574865f3bb9SMichael Rolnik 
575865f3bb9SMichael Rolnik     /* update status register */
576865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
577865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
578865f3bb9SMichael Rolnik 
579865f3bb9SMichael Rolnik     return true;
580865f3bb9SMichael Rolnik }
581865f3bb9SMichael Rolnik 
582865f3bb9SMichael Rolnik /*
583865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and register
584865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
585865f3bb9SMichael Rolnik  */
586865f3bb9SMichael Rolnik static bool trans_OR(DisasContext *ctx, arg_OR *a)
587865f3bb9SMichael Rolnik {
588865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
589865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
590865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
591865f3bb9SMichael Rolnik 
592865f3bb9SMichael Rolnik     tcg_gen_or_tl(R, Rd, Rr);
593865f3bb9SMichael Rolnik 
594865f3bb9SMichael Rolnik     /* update status register */
595865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
596865f3bb9SMichael Rolnik     gen_ZNSf(R);
597865f3bb9SMichael Rolnik 
598865f3bb9SMichael Rolnik     /* update output registers */
599865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
600865f3bb9SMichael Rolnik 
601865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
602865f3bb9SMichael Rolnik 
603865f3bb9SMichael Rolnik     return true;
604865f3bb9SMichael Rolnik }
605865f3bb9SMichael Rolnik 
606865f3bb9SMichael Rolnik /*
607865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and a
608865f3bb9SMichael Rolnik  *  constant and places the result in the destination register Rd.
609865f3bb9SMichael Rolnik  */
610865f3bb9SMichael Rolnik static bool trans_ORI(DisasContext *ctx, arg_ORI *a)
611865f3bb9SMichael Rolnik {
612865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
613865f3bb9SMichael Rolnik     int Imm = (a->imm);
614865f3bb9SMichael Rolnik 
615865f3bb9SMichael Rolnik     tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */
616865f3bb9SMichael Rolnik 
617865f3bb9SMichael Rolnik     /* update status register */
618865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
619865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
620865f3bb9SMichael Rolnik 
621865f3bb9SMichael Rolnik     return true;
622865f3bb9SMichael Rolnik }
623865f3bb9SMichael Rolnik 
624865f3bb9SMichael Rolnik /*
625865f3bb9SMichael Rolnik  *  Performs the logical EOR between the contents of register Rd and
626865f3bb9SMichael Rolnik  *  register Rr and places the result in the destination register Rd.
627865f3bb9SMichael Rolnik  */
628865f3bb9SMichael Rolnik static bool trans_EOR(DisasContext *ctx, arg_EOR *a)
629865f3bb9SMichael Rolnik {
630865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
631865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
632865f3bb9SMichael Rolnik 
633865f3bb9SMichael Rolnik     tcg_gen_xor_tl(Rd, Rd, Rr);
634865f3bb9SMichael Rolnik 
635865f3bb9SMichael Rolnik     /* update status register */
636865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
637865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
638865f3bb9SMichael Rolnik 
639865f3bb9SMichael Rolnik     return true;
640865f3bb9SMichael Rolnik }
641865f3bb9SMichael Rolnik 
642865f3bb9SMichael Rolnik /*
643865f3bb9SMichael Rolnik  *  Clears the specified bits in register Rd. Performs the logical AND
644865f3bb9SMichael Rolnik  *  between the contents of register Rd and the complement of the constant mask
645865f3bb9SMichael Rolnik  *  K. The result will be placed in register Rd.
646865f3bb9SMichael Rolnik  */
647865f3bb9SMichael Rolnik static bool trans_COM(DisasContext *ctx, arg_COM *a)
648865f3bb9SMichael Rolnik {
649865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
650865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
651865f3bb9SMichael Rolnik 
652865f3bb9SMichael Rolnik     tcg_gen_xori_tl(Rd, Rd, 0xff);
653865f3bb9SMichael Rolnik 
654865f3bb9SMichael Rolnik     /* update status register */
655865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */
656865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
657865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
658865f3bb9SMichael Rolnik 
659865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
660865f3bb9SMichael Rolnik 
661865f3bb9SMichael Rolnik     return true;
662865f3bb9SMichael Rolnik }
663865f3bb9SMichael Rolnik 
664865f3bb9SMichael Rolnik /*
665865f3bb9SMichael Rolnik  *  Replaces the contents of register Rd with its two's complement; the
666865f3bb9SMichael Rolnik  *  value $80 is left unchanged.
667865f3bb9SMichael Rolnik  */
668865f3bb9SMichael Rolnik static bool trans_NEG(DisasContext *ctx, arg_NEG *a)
669865f3bb9SMichael Rolnik {
670865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
671865f3bb9SMichael Rolnik     TCGv t0 = tcg_const_i32(0);
672865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
673865f3bb9SMichael Rolnik 
674865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */
675865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
676865f3bb9SMichael Rolnik 
677865f3bb9SMichael Rolnik     /* update status register */
678865f3bb9SMichael Rolnik     gen_sub_CHf(R, t0, Rd);
679865f3bb9SMichael Rolnik     gen_sub_Vf(R, t0, Rd);
680865f3bb9SMichael Rolnik     gen_ZNSf(R);
681865f3bb9SMichael Rolnik 
682865f3bb9SMichael Rolnik     /* update output registers */
683865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
684865f3bb9SMichael Rolnik 
685865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
686865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
687865f3bb9SMichael Rolnik 
688865f3bb9SMichael Rolnik     return true;
689865f3bb9SMichael Rolnik }
690865f3bb9SMichael Rolnik 
691865f3bb9SMichael Rolnik /*
692865f3bb9SMichael Rolnik  *  Adds one -1- to the contents of register Rd and places the result in the
693865f3bb9SMichael Rolnik  *  destination register Rd.  The C Flag in SREG is not affected by the
694865f3bb9SMichael Rolnik  *  operation, thus allowing the INC instruction to be used on a loop counter in
695865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned numbers, only
696865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently. When
697865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
698865f3bb9SMichael Rolnik  */
699865f3bb9SMichael Rolnik static bool trans_INC(DisasContext *ctx, arg_INC *a)
700865f3bb9SMichael Rolnik {
701865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
702865f3bb9SMichael Rolnik 
703865f3bb9SMichael Rolnik     tcg_gen_addi_tl(Rd, Rd, 1);
704865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff);
705865f3bb9SMichael Rolnik 
706865f3bb9SMichael Rolnik     /* update status register */
707865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */
708865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
709865f3bb9SMichael Rolnik 
710865f3bb9SMichael Rolnik     return true;
711865f3bb9SMichael Rolnik }
712865f3bb9SMichael Rolnik 
713865f3bb9SMichael Rolnik /*
714865f3bb9SMichael Rolnik  *  Subtracts one -1- from the contents of register Rd and places the result
715865f3bb9SMichael Rolnik  *  in the destination register Rd.  The C Flag in SREG is not affected by the
716865f3bb9SMichael Rolnik  *  operation, thus allowing the DEC instruction to be used on a loop counter in
717865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned values, only
718865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently.  When
719865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
720865f3bb9SMichael Rolnik  */
721865f3bb9SMichael Rolnik static bool trans_DEC(DisasContext *ctx, arg_DEC *a)
722865f3bb9SMichael Rolnik {
723865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
724865f3bb9SMichael Rolnik 
725865f3bb9SMichael Rolnik     tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
726865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
727865f3bb9SMichael Rolnik 
728865f3bb9SMichael Rolnik     /* update status register */
729865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */
730865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
731865f3bb9SMichael Rolnik 
732865f3bb9SMichael Rolnik     return true;
733865f3bb9SMichael Rolnik }
734865f3bb9SMichael Rolnik 
735865f3bb9SMichael Rolnik /*
736865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication.
737865f3bb9SMichael Rolnik  */
738865f3bb9SMichael Rolnik static bool trans_MUL(DisasContext *ctx, arg_MUL *a)
739865f3bb9SMichael Rolnik {
740865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
741865f3bb9SMichael Rolnik         return true;
742865f3bb9SMichael Rolnik     }
743865f3bb9SMichael Rolnik 
744865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
745865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
746865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
747865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
748865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
749865f3bb9SMichael Rolnik 
750865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
751865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
752865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
753865f3bb9SMichael Rolnik 
754865f3bb9SMichael Rolnik     /* update status register */
755865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
756865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
757865f3bb9SMichael Rolnik 
758865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
759865f3bb9SMichael Rolnik 
760865f3bb9SMichael Rolnik     return true;
761865f3bb9SMichael Rolnik }
762865f3bb9SMichael Rolnik 
763865f3bb9SMichael Rolnik /*
764865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication.
765865f3bb9SMichael Rolnik  */
766865f3bb9SMichael Rolnik static bool trans_MULS(DisasContext *ctx, arg_MULS *a)
767865f3bb9SMichael Rolnik {
768865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
769865f3bb9SMichael Rolnik         return true;
770865f3bb9SMichael Rolnik     }
771865f3bb9SMichael Rolnik 
772865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
773865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
774865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
775865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
776865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
777865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
778865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
779865f3bb9SMichael Rolnik 
780865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
781865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
782865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
783865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
784865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
785865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
786865f3bb9SMichael Rolnik 
787865f3bb9SMichael Rolnik     /* update status register */
788865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
789865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
790865f3bb9SMichael Rolnik 
791865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
792865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
793865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
794865f3bb9SMichael Rolnik 
795865f3bb9SMichael Rolnik     return true;
796865f3bb9SMichael Rolnik }
797865f3bb9SMichael Rolnik 
798865f3bb9SMichael Rolnik /*
799865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a
800865f3bb9SMichael Rolnik  *  signed and an unsigned number.
801865f3bb9SMichael Rolnik  */
802865f3bb9SMichael Rolnik static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a)
803865f3bb9SMichael Rolnik {
804865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
805865f3bb9SMichael Rolnik         return true;
806865f3bb9SMichael Rolnik     }
807865f3bb9SMichael Rolnik 
808865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
809865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
810865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
811865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
812865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
813865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
814865f3bb9SMichael Rolnik 
815865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
816865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
817865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */
818865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
819865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
820865f3bb9SMichael Rolnik 
821865f3bb9SMichael Rolnik     /* update status register */
822865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
823865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
824865f3bb9SMichael Rolnik 
825865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
826865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
827865f3bb9SMichael Rolnik 
828865f3bb9SMichael Rolnik     return true;
829865f3bb9SMichael Rolnik }
830865f3bb9SMichael Rolnik 
831865f3bb9SMichael Rolnik /*
832865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned
833865f3bb9SMichael Rolnik  *  multiplication and shifts the result one bit left.
834865f3bb9SMichael Rolnik  */
835865f3bb9SMichael Rolnik static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a)
836865f3bb9SMichael Rolnik {
837865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
838865f3bb9SMichael Rolnik         return true;
839865f3bb9SMichael Rolnik     }
840865f3bb9SMichael Rolnik 
841865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
842865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
843865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
844865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
845865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
846865f3bb9SMichael Rolnik 
847865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
848865f3bb9SMichael Rolnik 
849865f3bb9SMichael Rolnik     /* update status register */
850865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
851865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
852865f3bb9SMichael Rolnik 
853865f3bb9SMichael Rolnik     /* update output registers */
854865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
855865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
856865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
857865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
858865f3bb9SMichael Rolnik 
859865f3bb9SMichael Rolnik 
860865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
861865f3bb9SMichael Rolnik 
862865f3bb9SMichael Rolnik     return true;
863865f3bb9SMichael Rolnik }
864865f3bb9SMichael Rolnik 
865865f3bb9SMichael Rolnik /*
866865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
867865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
868865f3bb9SMichael Rolnik  */
869865f3bb9SMichael Rolnik static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a)
870865f3bb9SMichael Rolnik {
871865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
872865f3bb9SMichael Rolnik         return true;
873865f3bb9SMichael Rolnik     }
874865f3bb9SMichael Rolnik 
875865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
876865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
877865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
878865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
879865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
880865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
881865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
882865f3bb9SMichael Rolnik 
883865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
884865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
885865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
886865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
887865f3bb9SMichael Rolnik 
888865f3bb9SMichael Rolnik     /* update status register */
889865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
890865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
891865f3bb9SMichael Rolnik 
892865f3bb9SMichael Rolnik     /* update output registers */
893865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
894865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
895865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
896865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
897865f3bb9SMichael Rolnik 
898865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
899865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
900865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
901865f3bb9SMichael Rolnik 
902865f3bb9SMichael Rolnik     return true;
903865f3bb9SMichael Rolnik }
904865f3bb9SMichael Rolnik 
905865f3bb9SMichael Rolnik /*
906865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
907865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
908865f3bb9SMichael Rolnik  */
909865f3bb9SMichael Rolnik static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a)
910865f3bb9SMichael Rolnik {
911865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
912865f3bb9SMichael Rolnik         return true;
913865f3bb9SMichael Rolnik     }
914865f3bb9SMichael Rolnik 
915865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
916865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
917865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
918865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
919865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
920865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
921865f3bb9SMichael Rolnik 
922865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
923865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
924865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
925865f3bb9SMichael Rolnik 
926865f3bb9SMichael Rolnik     /* update status register */
927865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
928865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
929865f3bb9SMichael Rolnik 
930865f3bb9SMichael Rolnik     /* update output registers */
931865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
932865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
933865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
934865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
935865f3bb9SMichael Rolnik 
936865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
937865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
938865f3bb9SMichael Rolnik 
939865f3bb9SMichael Rolnik     return true;
940865f3bb9SMichael Rolnik }
941865f3bb9SMichael Rolnik 
942865f3bb9SMichael Rolnik /*
943865f3bb9SMichael Rolnik  *  The module is an instruction set extension to the AVR CPU, performing
944865f3bb9SMichael Rolnik  *  DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in
945865f3bb9SMichael Rolnik  *  the CPU register file, registers R0-R7, where LSB of data is placed in LSB
946865f3bb9SMichael Rolnik  *  of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including
947865f3bb9SMichael Rolnik  *  parity bits) is placed in registers R8- R15, organized in the register file
948865f3bb9SMichael Rolnik  *  with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES
949865f3bb9SMichael Rolnik  *  instruction performs one round in the DES algorithm. Sixteen rounds must be
950865f3bb9SMichael Rolnik  *  executed in increasing order to form the correct DES ciphertext or
951865f3bb9SMichael Rolnik  *  plaintext. Intermediate results are stored in the register file (R0-R15)
952865f3bb9SMichael Rolnik  *  after each DES instruction. The instruction's operand (K) determines which
953865f3bb9SMichael Rolnik  *  round is executed, and the half carry flag (H) determines whether encryption
954865f3bb9SMichael Rolnik  *  or decryption is performed.  The DES algorithm is described in
955865f3bb9SMichael Rolnik  *  "Specifications for the Data Encryption Standard" (Federal Information
956865f3bb9SMichael Rolnik  *  Processing Standards Publication 46). Intermediate results in this
957865f3bb9SMichael Rolnik  *  implementation differ from the standard because the initial permutation and
958865f3bb9SMichael Rolnik  *  the inverse initial permutation are performed each iteration. This does not
959865f3bb9SMichael Rolnik  *  affect the result in the final ciphertext or plaintext, but reduces
960865f3bb9SMichael Rolnik  *  execution time.
961865f3bb9SMichael Rolnik  */
962865f3bb9SMichael Rolnik static bool trans_DES(DisasContext *ctx, arg_DES *a)
963865f3bb9SMichael Rolnik {
964865f3bb9SMichael Rolnik     /* TODO */
965865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_DES)) {
966865f3bb9SMichael Rolnik         return true;
967865f3bb9SMichael Rolnik     }
968865f3bb9SMichael Rolnik 
969865f3bb9SMichael Rolnik     qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
970865f3bb9SMichael Rolnik 
971865f3bb9SMichael Rolnik     return true;
972865f3bb9SMichael Rolnik }
973*9d316c75SMichael Rolnik 
974*9d316c75SMichael Rolnik /*
975*9d316c75SMichael Rolnik  * Branch Instructions
976*9d316c75SMichael Rolnik  */
977*9d316c75SMichael Rolnik static void gen_jmp_ez(DisasContext *ctx)
978*9d316c75SMichael Rolnik {
979*9d316c75SMichael Rolnik     tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
980*9d316c75SMichael Rolnik     tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind);
981*9d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
982*9d316c75SMichael Rolnik }
983*9d316c75SMichael Rolnik 
984*9d316c75SMichael Rolnik static void gen_jmp_z(DisasContext *ctx)
985*9d316c75SMichael Rolnik {
986*9d316c75SMichael Rolnik     tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
987*9d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
988*9d316c75SMichael Rolnik }
989*9d316c75SMichael Rolnik 
990*9d316c75SMichael Rolnik static void gen_push_ret(DisasContext *ctx, int ret)
991*9d316c75SMichael Rolnik {
992*9d316c75SMichael Rolnik     if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
993*9d316c75SMichael Rolnik 
994*9d316c75SMichael Rolnik         TCGv t0 = tcg_const_i32((ret & 0x0000ff));
995*9d316c75SMichael Rolnik 
996*9d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB);
997*9d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
998*9d316c75SMichael Rolnik 
999*9d316c75SMichael Rolnik         tcg_temp_free_i32(t0);
1000*9d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
1001*9d316c75SMichael Rolnik 
1002*9d316c75SMichael Rolnik         TCGv t0 = tcg_const_i32((ret & 0x00ffff));
1003*9d316c75SMichael Rolnik 
1004*9d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
1005*9d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW);
1006*9d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
1007*9d316c75SMichael Rolnik 
1008*9d316c75SMichael Rolnik         tcg_temp_free_i32(t0);
1009*9d316c75SMichael Rolnik 
1010*9d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
1011*9d316c75SMichael Rolnik 
1012*9d316c75SMichael Rolnik         TCGv lo = tcg_const_i32((ret & 0x0000ff));
1013*9d316c75SMichael Rolnik         TCGv hi = tcg_const_i32((ret & 0xffff00) >> 8);
1014*9d316c75SMichael Rolnik 
1015*9d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
1016*9d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 2);
1017*9d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
1018*9d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
1019*9d316c75SMichael Rolnik 
1020*9d316c75SMichael Rolnik         tcg_temp_free_i32(lo);
1021*9d316c75SMichael Rolnik         tcg_temp_free_i32(hi);
1022*9d316c75SMichael Rolnik     }
1023*9d316c75SMichael Rolnik }
1024*9d316c75SMichael Rolnik 
1025*9d316c75SMichael Rolnik static void gen_pop_ret(DisasContext *ctx, TCGv ret)
1026*9d316c75SMichael Rolnik {
1027*9d316c75SMichael Rolnik     if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
1028*9d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
1029*9d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB);
1030*9d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
1031*9d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
1032*9d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW);
1033*9d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
1034*9d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
1035*9d316c75SMichael Rolnik         TCGv lo = tcg_temp_new_i32();
1036*9d316c75SMichael Rolnik         TCGv hi = tcg_temp_new_i32();
1037*9d316c75SMichael Rolnik 
1038*9d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
1039*9d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
1040*9d316c75SMichael Rolnik 
1041*9d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 2);
1042*9d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
1043*9d316c75SMichael Rolnik 
1044*9d316c75SMichael Rolnik         tcg_gen_deposit_tl(ret, lo, hi, 8, 16);
1045*9d316c75SMichael Rolnik 
1046*9d316c75SMichael Rolnik         tcg_temp_free_i32(lo);
1047*9d316c75SMichael Rolnik         tcg_temp_free_i32(hi);
1048*9d316c75SMichael Rolnik     }
1049*9d316c75SMichael Rolnik }
1050*9d316c75SMichael Rolnik 
1051*9d316c75SMichael Rolnik static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
1052*9d316c75SMichael Rolnik {
1053*9d316c75SMichael Rolnik     TranslationBlock *tb = ctx->tb;
1054*9d316c75SMichael Rolnik 
1055*9d316c75SMichael Rolnik     if (ctx->singlestep == 0) {
1056*9d316c75SMichael Rolnik         tcg_gen_goto_tb(n);
1057*9d316c75SMichael Rolnik         tcg_gen_movi_i32(cpu_pc, dest);
1058*9d316c75SMichael Rolnik         tcg_gen_exit_tb(tb, n);
1059*9d316c75SMichael Rolnik     } else {
1060*9d316c75SMichael Rolnik         tcg_gen_movi_i32(cpu_pc, dest);
1061*9d316c75SMichael Rolnik         gen_helper_debug(cpu_env);
1062*9d316c75SMichael Rolnik         tcg_gen_exit_tb(NULL, 0);
1063*9d316c75SMichael Rolnik     }
1064*9d316c75SMichael Rolnik     ctx->bstate = DISAS_NORETURN;
1065*9d316c75SMichael Rolnik }
1066*9d316c75SMichael Rolnik 
1067*9d316c75SMichael Rolnik /*
1068*9d316c75SMichael Rolnik  *  Relative jump to an address within PC - 2K +1 and PC + 2K (words). For
1069*9d316c75SMichael Rolnik  *  AVR microcontrollers with Program memory not exceeding 4K words (8KB) this
1070*9d316c75SMichael Rolnik  *  instruction can address the entire memory from every address location. See
1071*9d316c75SMichael Rolnik  *  also JMP.
1072*9d316c75SMichael Rolnik  */
1073*9d316c75SMichael Rolnik static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a)
1074*9d316c75SMichael Rolnik {
1075*9d316c75SMichael Rolnik     int dst = ctx->npc + a->imm;
1076*9d316c75SMichael Rolnik 
1077*9d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, dst);
1078*9d316c75SMichael Rolnik 
1079*9d316c75SMichael Rolnik     return true;
1080*9d316c75SMichael Rolnik }
1081*9d316c75SMichael Rolnik 
1082*9d316c75SMichael Rolnik /*
1083*9d316c75SMichael Rolnik  *  Indirect jump to the address pointed to by the Z (16 bits) Pointer
1084*9d316c75SMichael Rolnik  *  Register in the Register File. The Z-pointer Register is 16 bits wide and
1085*9d316c75SMichael Rolnik  *  allows jump within the lowest 64K words (128KB) section of Program memory.
1086*9d316c75SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
1087*9d316c75SMichael Rolnik  *  specific instruction set summary.
1088*9d316c75SMichael Rolnik  */
1089*9d316c75SMichael Rolnik static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a)
1090*9d316c75SMichael Rolnik {
1091*9d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) {
1092*9d316c75SMichael Rolnik         return true;
1093*9d316c75SMichael Rolnik     }
1094*9d316c75SMichael Rolnik 
1095*9d316c75SMichael Rolnik     gen_jmp_z(ctx);
1096*9d316c75SMichael Rolnik 
1097*9d316c75SMichael Rolnik     return true;
1098*9d316c75SMichael Rolnik }
1099*9d316c75SMichael Rolnik 
1100*9d316c75SMichael Rolnik /*
1101*9d316c75SMichael Rolnik  *  Indirect jump to the address pointed to by the Z (16 bits) Pointer
1102*9d316c75SMichael Rolnik  *  Register in the Register File and the EIND Register in the I/O space. This
1103*9d316c75SMichael Rolnik  *  instruction allows for indirect jumps to the entire 4M (words) Program
1104*9d316c75SMichael Rolnik  *  memory space. See also IJMP.  This instruction is not available in all
1105*9d316c75SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.
1106*9d316c75SMichael Rolnik  */
1107*9d316c75SMichael Rolnik static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a)
1108*9d316c75SMichael Rolnik {
1109*9d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) {
1110*9d316c75SMichael Rolnik         return true;
1111*9d316c75SMichael Rolnik     }
1112*9d316c75SMichael Rolnik 
1113*9d316c75SMichael Rolnik     gen_jmp_ez(ctx);
1114*9d316c75SMichael Rolnik     return true;
1115*9d316c75SMichael Rolnik }
1116*9d316c75SMichael Rolnik 
1117*9d316c75SMichael Rolnik /*
1118*9d316c75SMichael Rolnik  *  Jump to an address within the entire 4M (words) Program memory. See also
1119*9d316c75SMichael Rolnik  *  RJMP.  This instruction is not available in all devices. Refer to the device
1120*9d316c75SMichael Rolnik  *  specific instruction set summary.0
1121*9d316c75SMichael Rolnik  */
1122*9d316c75SMichael Rolnik static bool trans_JMP(DisasContext *ctx, arg_JMP *a)
1123*9d316c75SMichael Rolnik {
1124*9d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) {
1125*9d316c75SMichael Rolnik         return true;
1126*9d316c75SMichael Rolnik     }
1127*9d316c75SMichael Rolnik 
1128*9d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, a->imm);
1129*9d316c75SMichael Rolnik 
1130*9d316c75SMichael Rolnik     return true;
1131*9d316c75SMichael Rolnik }
1132*9d316c75SMichael Rolnik 
1133*9d316c75SMichael Rolnik /*
1134*9d316c75SMichael Rolnik  *  Relative call to an address within PC - 2K + 1 and PC + 2K (words). The
1135*9d316c75SMichael Rolnik  *  return address (the instruction after the RCALL) is stored onto the Stack.
1136*9d316c75SMichael Rolnik  *  See also CALL. For AVR microcontrollers with Program memory not exceeding 4K
1137*9d316c75SMichael Rolnik  *  words (8KB) this instruction can address the entire memory from every
1138*9d316c75SMichael Rolnik  *  address location. The Stack Pointer uses a post-decrement scheme during
1139*9d316c75SMichael Rolnik  *  RCALL.
1140*9d316c75SMichael Rolnik  */
1141*9d316c75SMichael Rolnik static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a)
1142*9d316c75SMichael Rolnik {
1143*9d316c75SMichael Rolnik     int ret = ctx->npc;
1144*9d316c75SMichael Rolnik     int dst = ctx->npc + a->imm;
1145*9d316c75SMichael Rolnik 
1146*9d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
1147*9d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, dst);
1148*9d316c75SMichael Rolnik 
1149*9d316c75SMichael Rolnik     return true;
1150*9d316c75SMichael Rolnik }
1151*9d316c75SMichael Rolnik 
1152*9d316c75SMichael Rolnik /*
1153*9d316c75SMichael Rolnik  *  Calls to a subroutine within the entire 4M (words) Program memory. The
1154*9d316c75SMichael Rolnik  *  return address (to the instruction after the CALL) will be stored onto the
1155*9d316c75SMichael Rolnik  *  Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme during
1156*9d316c75SMichael Rolnik  *  CALL.  This instruction is not available in all devices. Refer to the device
1157*9d316c75SMichael Rolnik  *  specific instruction set summary.
1158*9d316c75SMichael Rolnik  */
1159*9d316c75SMichael Rolnik static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a)
1160*9d316c75SMichael Rolnik {
1161*9d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) {
1162*9d316c75SMichael Rolnik         return true;
1163*9d316c75SMichael Rolnik     }
1164*9d316c75SMichael Rolnik 
1165*9d316c75SMichael Rolnik     int ret = ctx->npc;
1166*9d316c75SMichael Rolnik 
1167*9d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
1168*9d316c75SMichael Rolnik     gen_jmp_z(ctx);
1169*9d316c75SMichael Rolnik 
1170*9d316c75SMichael Rolnik     return true;
1171*9d316c75SMichael Rolnik }
1172*9d316c75SMichael Rolnik 
1173*9d316c75SMichael Rolnik /*
1174*9d316c75SMichael Rolnik  *  Indirect call of a subroutine pointed to by the Z (16 bits) Pointer
1175*9d316c75SMichael Rolnik  *  Register in the Register File and the EIND Register in the I/O space. This
1176*9d316c75SMichael Rolnik  *  instruction allows for indirect calls to the entire 4M (words) Program
1177*9d316c75SMichael Rolnik  *  memory space. See also ICALL. The Stack Pointer uses a post-decrement scheme
1178*9d316c75SMichael Rolnik  *  during EICALL.  This instruction is not available in all devices. Refer to
1179*9d316c75SMichael Rolnik  *  the device specific instruction set summary.
1180*9d316c75SMichael Rolnik  */
1181*9d316c75SMichael Rolnik static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a)
1182*9d316c75SMichael Rolnik {
1183*9d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) {
1184*9d316c75SMichael Rolnik         return true;
1185*9d316c75SMichael Rolnik     }
1186*9d316c75SMichael Rolnik 
1187*9d316c75SMichael Rolnik     int ret = ctx->npc;
1188*9d316c75SMichael Rolnik 
1189*9d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
1190*9d316c75SMichael Rolnik     gen_jmp_ez(ctx);
1191*9d316c75SMichael Rolnik     return true;
1192*9d316c75SMichael Rolnik }
1193*9d316c75SMichael Rolnik 
1194*9d316c75SMichael Rolnik /*
1195*9d316c75SMichael Rolnik  *  Calls to a subroutine within the entire Program memory. The return
1196*9d316c75SMichael Rolnik  *  address (to the instruction after the CALL) will be stored onto the Stack.
1197*9d316c75SMichael Rolnik  *  (See also RCALL). The Stack Pointer uses a post-decrement scheme during
1198*9d316c75SMichael Rolnik  *  CALL.  This instruction is not available in all devices. Refer to the device
1199*9d316c75SMichael Rolnik  *  specific instruction set summary.
1200*9d316c75SMichael Rolnik  */
1201*9d316c75SMichael Rolnik static bool trans_CALL(DisasContext *ctx, arg_CALL *a)
1202*9d316c75SMichael Rolnik {
1203*9d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) {
1204*9d316c75SMichael Rolnik         return true;
1205*9d316c75SMichael Rolnik     }
1206*9d316c75SMichael Rolnik 
1207*9d316c75SMichael Rolnik     int Imm = a->imm;
1208*9d316c75SMichael Rolnik     int ret = ctx->npc;
1209*9d316c75SMichael Rolnik 
1210*9d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
1211*9d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, Imm);
1212*9d316c75SMichael Rolnik 
1213*9d316c75SMichael Rolnik     return true;
1214*9d316c75SMichael Rolnik }
1215*9d316c75SMichael Rolnik 
1216*9d316c75SMichael Rolnik /*
1217*9d316c75SMichael Rolnik  *  Returns from subroutine. The return address is loaded from the STACK.
1218*9d316c75SMichael Rolnik  *  The Stack Pointer uses a preincrement scheme during RET.
1219*9d316c75SMichael Rolnik  */
1220*9d316c75SMichael Rolnik static bool trans_RET(DisasContext *ctx, arg_RET *a)
1221*9d316c75SMichael Rolnik {
1222*9d316c75SMichael Rolnik     gen_pop_ret(ctx, cpu_pc);
1223*9d316c75SMichael Rolnik 
1224*9d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
1225*9d316c75SMichael Rolnik     return true;
1226*9d316c75SMichael Rolnik }
1227*9d316c75SMichael Rolnik 
1228*9d316c75SMichael Rolnik /*
1229*9d316c75SMichael Rolnik  *  Returns from interrupt. The return address is loaded from the STACK and
1230*9d316c75SMichael Rolnik  *  the Global Interrupt Flag is set.  Note that the Status Register is not
1231*9d316c75SMichael Rolnik  *  automatically stored when entering an interrupt routine, and it is not
1232*9d316c75SMichael Rolnik  *  restored when returning from an interrupt routine. This must be handled by
1233*9d316c75SMichael Rolnik  *  the application program. The Stack Pointer uses a pre-increment scheme
1234*9d316c75SMichael Rolnik  *  during RETI.
1235*9d316c75SMichael Rolnik  */
1236*9d316c75SMichael Rolnik static bool trans_RETI(DisasContext *ctx, arg_RETI *a)
1237*9d316c75SMichael Rolnik {
1238*9d316c75SMichael Rolnik     gen_pop_ret(ctx, cpu_pc);
1239*9d316c75SMichael Rolnik     tcg_gen_movi_tl(cpu_If, 1);
1240*9d316c75SMichael Rolnik 
1241*9d316c75SMichael Rolnik     /* Need to return to main loop to re-evaluate interrupts.  */
1242*9d316c75SMichael Rolnik     ctx->bstate = DISAS_EXIT;
1243*9d316c75SMichael Rolnik     return true;
1244*9d316c75SMichael Rolnik }
1245*9d316c75SMichael Rolnik 
1246*9d316c75SMichael Rolnik /*
1247*9d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr, and
1248*9d316c75SMichael Rolnik  *  skips the next instruction if Rd = Rr.
1249*9d316c75SMichael Rolnik  */
1250*9d316c75SMichael Rolnik static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a)
1251*9d316c75SMichael Rolnik {
1252*9d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
1253*9d316c75SMichael Rolnik     ctx->skip_var0 = cpu_r[a->rd];
1254*9d316c75SMichael Rolnik     ctx->skip_var1 = cpu_r[a->rr];
1255*9d316c75SMichael Rolnik     return true;
1256*9d316c75SMichael Rolnik }
1257*9d316c75SMichael Rolnik 
1258*9d316c75SMichael Rolnik /*
1259*9d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr.
1260*9d316c75SMichael Rolnik  *  None of the registers are changed. All conditional branches can be used
1261*9d316c75SMichael Rolnik  *  after this instruction.
1262*9d316c75SMichael Rolnik  */
1263*9d316c75SMichael Rolnik static bool trans_CP(DisasContext *ctx, arg_CP *a)
1264*9d316c75SMichael Rolnik {
1265*9d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1266*9d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
1267*9d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
1268*9d316c75SMichael Rolnik 
1269*9d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
1270*9d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
1271*9d316c75SMichael Rolnik 
1272*9d316c75SMichael Rolnik     /* update status register */
1273*9d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
1274*9d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
1275*9d316c75SMichael Rolnik     gen_ZNSf(R);
1276*9d316c75SMichael Rolnik 
1277*9d316c75SMichael Rolnik     tcg_temp_free_i32(R);
1278*9d316c75SMichael Rolnik 
1279*9d316c75SMichael Rolnik     return true;
1280*9d316c75SMichael Rolnik }
1281*9d316c75SMichael Rolnik 
1282*9d316c75SMichael Rolnik /*
1283*9d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr and
1284*9d316c75SMichael Rolnik  *  also takes into account the previous carry. None of the registers are
1285*9d316c75SMichael Rolnik  *  changed. All conditional branches can be used after this instruction.
1286*9d316c75SMichael Rolnik  */
1287*9d316c75SMichael Rolnik static bool trans_CPC(DisasContext *ctx, arg_CPC *a)
1288*9d316c75SMichael Rolnik {
1289*9d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1290*9d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
1291*9d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
1292*9d316c75SMichael Rolnik     TCGv zero = tcg_const_i32(0);
1293*9d316c75SMichael Rolnik 
1294*9d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
1295*9d316c75SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
1296*9d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
1297*9d316c75SMichael Rolnik     /* update status register */
1298*9d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
1299*9d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
1300*9d316c75SMichael Rolnik     gen_NSf(R);
1301*9d316c75SMichael Rolnik 
1302*9d316c75SMichael Rolnik     /*
1303*9d316c75SMichael Rolnik      * Previous value remains unchanged when the result is zero;
1304*9d316c75SMichael Rolnik      * cleared otherwise.
1305*9d316c75SMichael Rolnik      */
1306*9d316c75SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
1307*9d316c75SMichael Rolnik 
1308*9d316c75SMichael Rolnik     tcg_temp_free_i32(zero);
1309*9d316c75SMichael Rolnik     tcg_temp_free_i32(R);
1310*9d316c75SMichael Rolnik 
1311*9d316c75SMichael Rolnik     return true;
1312*9d316c75SMichael Rolnik }
1313*9d316c75SMichael Rolnik 
1314*9d316c75SMichael Rolnik /*
1315*9d316c75SMichael Rolnik  *  This instruction performs a compare between register Rd and a constant.
1316*9d316c75SMichael Rolnik  *  The register is not changed. All conditional branches can be used after this
1317*9d316c75SMichael Rolnik  *  instruction.
1318*9d316c75SMichael Rolnik  */
1319*9d316c75SMichael Rolnik static bool trans_CPI(DisasContext *ctx, arg_CPI *a)
1320*9d316c75SMichael Rolnik {
1321*9d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1322*9d316c75SMichael Rolnik     int Imm = a->imm;
1323*9d316c75SMichael Rolnik     TCGv Rr = tcg_const_i32(Imm);
1324*9d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
1325*9d316c75SMichael Rolnik 
1326*9d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
1327*9d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
1328*9d316c75SMichael Rolnik 
1329*9d316c75SMichael Rolnik     /* update status register */
1330*9d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
1331*9d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
1332*9d316c75SMichael Rolnik     gen_ZNSf(R);
1333*9d316c75SMichael Rolnik 
1334*9d316c75SMichael Rolnik     tcg_temp_free_i32(R);
1335*9d316c75SMichael Rolnik     tcg_temp_free_i32(Rr);
1336*9d316c75SMichael Rolnik 
1337*9d316c75SMichael Rolnik     return true;
1338*9d316c75SMichael Rolnik }
1339*9d316c75SMichael Rolnik 
1340*9d316c75SMichael Rolnik /*
1341*9d316c75SMichael Rolnik  *  This instruction tests a single bit in a register and skips the next
1342*9d316c75SMichael Rolnik  *  instruction if the bit is cleared.
1343*9d316c75SMichael Rolnik  */
1344*9d316c75SMichael Rolnik static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a)
1345*9d316c75SMichael Rolnik {
1346*9d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
1347*9d316c75SMichael Rolnik 
1348*9d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
1349*9d316c75SMichael Rolnik     ctx->skip_var0 = tcg_temp_new();
1350*9d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
1351*9d316c75SMichael Rolnik 
1352*9d316c75SMichael Rolnik     tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
1353*9d316c75SMichael Rolnik     return true;
1354*9d316c75SMichael Rolnik }
1355*9d316c75SMichael Rolnik 
1356*9d316c75SMichael Rolnik /*
1357*9d316c75SMichael Rolnik  *  This instruction tests a single bit in a register and skips the next
1358*9d316c75SMichael Rolnik  *  instruction if the bit is set.
1359*9d316c75SMichael Rolnik  */
1360*9d316c75SMichael Rolnik static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a)
1361*9d316c75SMichael Rolnik {
1362*9d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
1363*9d316c75SMichael Rolnik 
1364*9d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_NE;
1365*9d316c75SMichael Rolnik     ctx->skip_var0 = tcg_temp_new();
1366*9d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
1367*9d316c75SMichael Rolnik 
1368*9d316c75SMichael Rolnik     tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
1369*9d316c75SMichael Rolnik     return true;
1370*9d316c75SMichael Rolnik }
1371*9d316c75SMichael Rolnik 
1372*9d316c75SMichael Rolnik /*
1373*9d316c75SMichael Rolnik  *  This instruction tests a single bit in an I/O Register and skips the
1374*9d316c75SMichael Rolnik  *  next instruction if the bit is cleared. This instruction operates on the
1375*9d316c75SMichael Rolnik  *  lower 32 I/O Registers -- addresses 0-31.
1376*9d316c75SMichael Rolnik  */
1377*9d316c75SMichael Rolnik static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a)
1378*9d316c75SMichael Rolnik {
1379*9d316c75SMichael Rolnik     TCGv temp = tcg_const_i32(a->reg);
1380*9d316c75SMichael Rolnik 
1381*9d316c75SMichael Rolnik     gen_helper_inb(temp, cpu_env, temp);
1382*9d316c75SMichael Rolnik     tcg_gen_andi_tl(temp, temp, 1 << a->bit);
1383*9d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
1384*9d316c75SMichael Rolnik     ctx->skip_var0 = temp;
1385*9d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
1386*9d316c75SMichael Rolnik 
1387*9d316c75SMichael Rolnik     return true;
1388*9d316c75SMichael Rolnik }
1389*9d316c75SMichael Rolnik 
1390*9d316c75SMichael Rolnik /*
1391*9d316c75SMichael Rolnik  *  This instruction tests a single bit in an I/O Register and skips the
1392*9d316c75SMichael Rolnik  *  next instruction if the bit is set. This instruction operates on the lower
1393*9d316c75SMichael Rolnik  *  32 I/O Registers -- addresses 0-31.
1394*9d316c75SMichael Rolnik  */
1395*9d316c75SMichael Rolnik static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a)
1396*9d316c75SMichael Rolnik {
1397*9d316c75SMichael Rolnik     TCGv temp = tcg_const_i32(a->reg);
1398*9d316c75SMichael Rolnik 
1399*9d316c75SMichael Rolnik     gen_helper_inb(temp, cpu_env, temp);
1400*9d316c75SMichael Rolnik     tcg_gen_andi_tl(temp, temp, 1 << a->bit);
1401*9d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_NE;
1402*9d316c75SMichael Rolnik     ctx->skip_var0 = temp;
1403*9d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
1404*9d316c75SMichael Rolnik 
1405*9d316c75SMichael Rolnik     return true;
1406*9d316c75SMichael Rolnik }
1407*9d316c75SMichael Rolnik 
1408*9d316c75SMichael Rolnik /*
1409*9d316c75SMichael Rolnik  *  Conditional relative branch. Tests a single bit in SREG and branches
1410*9d316c75SMichael Rolnik  *  relatively to PC if the bit is cleared. This instruction branches relatively
1411*9d316c75SMichael Rolnik  *  to PC in either direction (PC - 63 < = destination <= PC + 64). The
1412*9d316c75SMichael Rolnik  *  parameter k is the offset from PC and is represented in two's complement
1413*9d316c75SMichael Rolnik  *  form.
1414*9d316c75SMichael Rolnik  */
1415*9d316c75SMichael Rolnik static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a)
1416*9d316c75SMichael Rolnik {
1417*9d316c75SMichael Rolnik     TCGLabel *not_taken = gen_new_label();
1418*9d316c75SMichael Rolnik 
1419*9d316c75SMichael Rolnik     TCGv var;
1420*9d316c75SMichael Rolnik 
1421*9d316c75SMichael Rolnik     switch (a->bit) {
1422*9d316c75SMichael Rolnik     case 0x00:
1423*9d316c75SMichael Rolnik         var = cpu_Cf;
1424*9d316c75SMichael Rolnik         break;
1425*9d316c75SMichael Rolnik     case 0x01:
1426*9d316c75SMichael Rolnik         var = cpu_Zf;
1427*9d316c75SMichael Rolnik         break;
1428*9d316c75SMichael Rolnik     case 0x02:
1429*9d316c75SMichael Rolnik         var = cpu_Nf;
1430*9d316c75SMichael Rolnik         break;
1431*9d316c75SMichael Rolnik     case 0x03:
1432*9d316c75SMichael Rolnik         var = cpu_Vf;
1433*9d316c75SMichael Rolnik         break;
1434*9d316c75SMichael Rolnik     case 0x04:
1435*9d316c75SMichael Rolnik         var = cpu_Sf;
1436*9d316c75SMichael Rolnik         break;
1437*9d316c75SMichael Rolnik     case 0x05:
1438*9d316c75SMichael Rolnik         var = cpu_Hf;
1439*9d316c75SMichael Rolnik         break;
1440*9d316c75SMichael Rolnik     case 0x06:
1441*9d316c75SMichael Rolnik         var = cpu_Tf;
1442*9d316c75SMichael Rolnik         break;
1443*9d316c75SMichael Rolnik     case 0x07:
1444*9d316c75SMichael Rolnik         var = cpu_If;
1445*9d316c75SMichael Rolnik         break;
1446*9d316c75SMichael Rolnik     default:
1447*9d316c75SMichael Rolnik         g_assert_not_reached();
1448*9d316c75SMichael Rolnik     }
1449*9d316c75SMichael Rolnik 
1450*9d316c75SMichael Rolnik     tcg_gen_brcondi_i32(TCG_COND_NE, var, 0, not_taken);
1451*9d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, ctx->npc + a->imm);
1452*9d316c75SMichael Rolnik     gen_set_label(not_taken);
1453*9d316c75SMichael Rolnik 
1454*9d316c75SMichael Rolnik     ctx->bstate = DISAS_CHAIN;
1455*9d316c75SMichael Rolnik     return true;
1456*9d316c75SMichael Rolnik }
1457*9d316c75SMichael Rolnik 
1458*9d316c75SMichael Rolnik /*
1459*9d316c75SMichael Rolnik  *  Conditional relative branch. Tests a single bit in SREG and branches
1460*9d316c75SMichael Rolnik  *  relatively to PC if the bit is set. This instruction branches relatively to
1461*9d316c75SMichael Rolnik  *  PC in either direction (PC - 63 < = destination <= PC + 64). The parameter k
1462*9d316c75SMichael Rolnik  *  is the offset from PC and is represented in two's complement form.
1463*9d316c75SMichael Rolnik  */
1464*9d316c75SMichael Rolnik static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a)
1465*9d316c75SMichael Rolnik {
1466*9d316c75SMichael Rolnik     TCGLabel *not_taken = gen_new_label();
1467*9d316c75SMichael Rolnik 
1468*9d316c75SMichael Rolnik     TCGv var;
1469*9d316c75SMichael Rolnik 
1470*9d316c75SMichael Rolnik     switch (a->bit) {
1471*9d316c75SMichael Rolnik     case 0x00:
1472*9d316c75SMichael Rolnik         var = cpu_Cf;
1473*9d316c75SMichael Rolnik         break;
1474*9d316c75SMichael Rolnik     case 0x01:
1475*9d316c75SMichael Rolnik         var = cpu_Zf;
1476*9d316c75SMichael Rolnik         break;
1477*9d316c75SMichael Rolnik     case 0x02:
1478*9d316c75SMichael Rolnik         var = cpu_Nf;
1479*9d316c75SMichael Rolnik         break;
1480*9d316c75SMichael Rolnik     case 0x03:
1481*9d316c75SMichael Rolnik         var = cpu_Vf;
1482*9d316c75SMichael Rolnik         break;
1483*9d316c75SMichael Rolnik     case 0x04:
1484*9d316c75SMichael Rolnik         var = cpu_Sf;
1485*9d316c75SMichael Rolnik         break;
1486*9d316c75SMichael Rolnik     case 0x05:
1487*9d316c75SMichael Rolnik         var = cpu_Hf;
1488*9d316c75SMichael Rolnik         break;
1489*9d316c75SMichael Rolnik     case 0x06:
1490*9d316c75SMichael Rolnik         var = cpu_Tf;
1491*9d316c75SMichael Rolnik         break;
1492*9d316c75SMichael Rolnik     case 0x07:
1493*9d316c75SMichael Rolnik         var = cpu_If;
1494*9d316c75SMichael Rolnik         break;
1495*9d316c75SMichael Rolnik     default:
1496*9d316c75SMichael Rolnik         g_assert_not_reached();
1497*9d316c75SMichael Rolnik     }
1498*9d316c75SMichael Rolnik 
1499*9d316c75SMichael Rolnik     tcg_gen_brcondi_i32(TCG_COND_EQ, var, 0, not_taken);
1500*9d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, ctx->npc + a->imm);
1501*9d316c75SMichael Rolnik     gen_set_label(not_taken);
1502*9d316c75SMichael Rolnik 
1503*9d316c75SMichael Rolnik     ctx->bstate = DISAS_CHAIN;
1504*9d316c75SMichael Rolnik     return true;
1505*9d316c75SMichael Rolnik }
1506