xref: /openbmc/qemu/target/avr/translate.c (revision 9732b024)
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 
146*9732b024SMichael Rolnik static int to_regs_00_30_by_two(DisasContext *ctx, int indx)
147*9732b024SMichael Rolnik {
148*9732b024SMichael Rolnik     return (indx % 16) * 2;
149*9732b024SMichael Rolnik }
150865f3bb9SMichael Rolnik 
1519d316c75SMichael Rolnik static uint16_t next_word(DisasContext *ctx)
1529d316c75SMichael Rolnik {
1539d316c75SMichael Rolnik     return cpu_lduw_code(ctx->env, ctx->npc++ * 2);
1549d316c75SMichael Rolnik }
1559d316c75SMichael Rolnik 
1569d316c75SMichael Rolnik static int append_16(DisasContext *ctx, int x)
1579d316c75SMichael Rolnik {
1589d316c75SMichael Rolnik     return x << 16 | next_word(ctx);
1599d316c75SMichael Rolnik }
1609d316c75SMichael Rolnik 
161e03feba0SMichael Rolnik static bool avr_have_feature(DisasContext *ctx, int feature)
162e03feba0SMichael Rolnik {
163e03feba0SMichael Rolnik     if (!avr_feature(ctx->env, feature)) {
164e03feba0SMichael Rolnik         gen_helper_unsupported(cpu_env);
165e03feba0SMichael Rolnik         ctx->bstate = DISAS_NORETURN;
166e03feba0SMichael Rolnik         return false;
167e03feba0SMichael Rolnik     }
168e03feba0SMichael Rolnik     return true;
169e03feba0SMichael Rolnik }
170e03feba0SMichael Rolnik 
171e03feba0SMichael Rolnik static bool decode_insn(DisasContext *ctx, uint16_t insn);
172e03feba0SMichael Rolnik #include "decode_insn.inc.c"
173865f3bb9SMichael Rolnik 
174865f3bb9SMichael Rolnik /*
175865f3bb9SMichael Rolnik  * Arithmetic Instructions
176865f3bb9SMichael Rolnik  */
177865f3bb9SMichael Rolnik 
178865f3bb9SMichael Rolnik /*
179865f3bb9SMichael Rolnik  * Utility functions for updating status registers:
180865f3bb9SMichael Rolnik  *
181865f3bb9SMichael Rolnik  *   - gen_add_CHf()
182865f3bb9SMichael Rolnik  *   - gen_add_Vf()
183865f3bb9SMichael Rolnik  *   - gen_sub_CHf()
184865f3bb9SMichael Rolnik  *   - gen_sub_Vf()
185865f3bb9SMichael Rolnik  *   - gen_NSf()
186865f3bb9SMichael Rolnik  *   - gen_ZNSf()
187865f3bb9SMichael Rolnik  *
188865f3bb9SMichael Rolnik  */
189865f3bb9SMichael Rolnik 
190865f3bb9SMichael Rolnik static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr)
191865f3bb9SMichael Rolnik {
192865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
193865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
194865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
195865f3bb9SMichael Rolnik 
196865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */
197865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */
198865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */
199865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */
200865f3bb9SMichael Rolnik     tcg_gen_or_tl(t1, t1, t3);
201865f3bb9SMichael Rolnik 
202865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */
203865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */
204865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
205865f3bb9SMichael Rolnik 
206865f3bb9SMichael Rolnik     tcg_temp_free_i32(t3);
207865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
208865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
209865f3bb9SMichael Rolnik }
210865f3bb9SMichael Rolnik 
211865f3bb9SMichael Rolnik static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
212865f3bb9SMichael Rolnik {
213865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
214865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
215865f3bb9SMichael Rolnik 
216865f3bb9SMichael Rolnik     /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */
217865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & ~(Rd ^ Rr) */
218865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
219865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
220865f3bb9SMichael Rolnik     tcg_gen_andc_tl(t1, t1, t2);
221865f3bb9SMichael Rolnik 
222865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
223865f3bb9SMichael Rolnik 
224865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
225865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
226865f3bb9SMichael Rolnik }
227865f3bb9SMichael Rolnik 
228865f3bb9SMichael Rolnik static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
229865f3bb9SMichael Rolnik {
230865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
231865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
232865f3bb9SMichael Rolnik     TCGv t3 = tcg_temp_new_i32();
233865f3bb9SMichael Rolnik 
234865f3bb9SMichael Rolnik     tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */
235865f3bb9SMichael Rolnik     tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */
236865f3bb9SMichael Rolnik     tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */
237865f3bb9SMichael Rolnik     tcg_gen_and_tl(t3, t3, R);
238865f3bb9SMichael Rolnik     tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */
239865f3bb9SMichael Rolnik 
240865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */
241865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */
242865f3bb9SMichael Rolnik     tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
243865f3bb9SMichael Rolnik 
244865f3bb9SMichael Rolnik     tcg_temp_free_i32(t3);
245865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
246865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
247865f3bb9SMichael Rolnik }
248865f3bb9SMichael Rolnik 
249865f3bb9SMichael Rolnik static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
250865f3bb9SMichael Rolnik {
251865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
252865f3bb9SMichael Rolnik     TCGv t2 = tcg_temp_new_i32();
253865f3bb9SMichael Rolnik 
254865f3bb9SMichael Rolnik     /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */
255865f3bb9SMichael Rolnik     /*    = (Rd ^ R) & (Rd ^ R) */
256865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t1, Rd, R);
257865f3bb9SMichael Rolnik     tcg_gen_xor_tl(t2, Rd, Rr);
258865f3bb9SMichael Rolnik     tcg_gen_and_tl(t1, t1, t2);
259865f3bb9SMichael Rolnik 
260865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
261865f3bb9SMichael Rolnik 
262865f3bb9SMichael Rolnik     tcg_temp_free_i32(t2);
263865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
264865f3bb9SMichael Rolnik }
265865f3bb9SMichael Rolnik 
266865f3bb9SMichael Rolnik static void gen_NSf(TCGv R)
267865f3bb9SMichael Rolnik {
268865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
269865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
270865f3bb9SMichael Rolnik }
271865f3bb9SMichael Rolnik 
272865f3bb9SMichael Rolnik static void gen_ZNSf(TCGv R)
273865f3bb9SMichael Rolnik {
274865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
275865f3bb9SMichael Rolnik 
276865f3bb9SMichael Rolnik     /* update status register */
277865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
278865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
279865f3bb9SMichael Rolnik }
280865f3bb9SMichael Rolnik 
281865f3bb9SMichael Rolnik /*
282865f3bb9SMichael Rolnik  *  Adds two registers without the C Flag and places the result in the
283865f3bb9SMichael Rolnik  *  destination register Rd.
284865f3bb9SMichael Rolnik  */
285865f3bb9SMichael Rolnik static bool trans_ADD(DisasContext *ctx, arg_ADD *a)
286865f3bb9SMichael Rolnik {
287865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
288865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
289865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
290865f3bb9SMichael Rolnik 
291865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */
292865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
293865f3bb9SMichael Rolnik 
294865f3bb9SMichael Rolnik     /* update status register */
295865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
296865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
297865f3bb9SMichael Rolnik     gen_ZNSf(R);
298865f3bb9SMichael Rolnik 
299865f3bb9SMichael Rolnik     /* update output registers */
300865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
301865f3bb9SMichael Rolnik 
302865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
303865f3bb9SMichael Rolnik 
304865f3bb9SMichael Rolnik     return true;
305865f3bb9SMichael Rolnik }
306865f3bb9SMichael Rolnik 
307865f3bb9SMichael Rolnik /*
308865f3bb9SMichael Rolnik  *  Adds two registers and the contents of the C Flag and places the result in
309865f3bb9SMichael Rolnik  *  the destination register Rd.
310865f3bb9SMichael Rolnik  */
311865f3bb9SMichael Rolnik static bool trans_ADC(DisasContext *ctx, arg_ADC *a)
312865f3bb9SMichael Rolnik {
313865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
314865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
315865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
316865f3bb9SMichael Rolnik 
317865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */
318865f3bb9SMichael Rolnik     tcg_gen_add_tl(R, R, cpu_Cf);
319865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
320865f3bb9SMichael Rolnik 
321865f3bb9SMichael Rolnik     /* update status register */
322865f3bb9SMichael Rolnik     gen_add_CHf(R, Rd, Rr);
323865f3bb9SMichael Rolnik     gen_add_Vf(R, Rd, Rr);
324865f3bb9SMichael Rolnik     gen_ZNSf(R);
325865f3bb9SMichael Rolnik 
326865f3bb9SMichael Rolnik     /* update output registers */
327865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
328865f3bb9SMichael Rolnik 
329865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
330865f3bb9SMichael Rolnik 
331865f3bb9SMichael Rolnik     return true;
332865f3bb9SMichael Rolnik }
333865f3bb9SMichael Rolnik 
334865f3bb9SMichael Rolnik /*
335865f3bb9SMichael Rolnik  *  Adds an immediate value (0 - 63) to a register pair and places the result
336865f3bb9SMichael Rolnik  *  in the register pair. This instruction operates on the upper four register
337865f3bb9SMichael Rolnik  *  pairs, and is well suited for operations on the pointer registers.  This
338865f3bb9SMichael Rolnik  *  instruction is not available in all devices. Refer to the device specific
339865f3bb9SMichael Rolnik  *  instruction set summary.
340865f3bb9SMichael Rolnik  */
341865f3bb9SMichael Rolnik static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a)
342865f3bb9SMichael Rolnik {
343865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
344865f3bb9SMichael Rolnik         return true;
345865f3bb9SMichael Rolnik     }
346865f3bb9SMichael Rolnik 
347865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
348865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
349865f3bb9SMichael Rolnik     int Imm = (a->imm);
350865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
351865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
352865f3bb9SMichael Rolnik 
353865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
354865f3bb9SMichael Rolnik     tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */
355865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
356865f3bb9SMichael Rolnik 
357865f3bb9SMichael Rolnik     /* update status register */
358865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
359865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15);
360865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */
361865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15);
362865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
363865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
364865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */
365865f3bb9SMichael Rolnik 
366865f3bb9SMichael Rolnik     /* update output registers */
367865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
368865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
369865f3bb9SMichael Rolnik 
370865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rd);
371865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
372865f3bb9SMichael Rolnik 
373865f3bb9SMichael Rolnik     return true;
374865f3bb9SMichael Rolnik }
375865f3bb9SMichael Rolnik 
376865f3bb9SMichael Rolnik /*
377865f3bb9SMichael Rolnik  *  Subtracts two registers and places the result in the destination
378865f3bb9SMichael Rolnik  *  register Rd.
379865f3bb9SMichael Rolnik  */
380865f3bb9SMichael Rolnik static bool trans_SUB(DisasContext *ctx, arg_SUB *a)
381865f3bb9SMichael Rolnik {
382865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
383865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
384865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
385865f3bb9SMichael Rolnik 
386865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
387865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
388865f3bb9SMichael Rolnik 
389865f3bb9SMichael Rolnik     /* update status register */
390865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
391865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
392865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
393865f3bb9SMichael Rolnik     gen_ZNSf(R);
394865f3bb9SMichael Rolnik 
395865f3bb9SMichael Rolnik     /* update output registers */
396865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
397865f3bb9SMichael Rolnik 
398865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
399865f3bb9SMichael Rolnik 
400865f3bb9SMichael Rolnik     return true;
401865f3bb9SMichael Rolnik }
402865f3bb9SMichael Rolnik 
403865f3bb9SMichael Rolnik /*
404865f3bb9SMichael Rolnik  *  Subtracts a register and a constant and places the result in the
405865f3bb9SMichael Rolnik  *  destination register Rd. This instruction is working on Register R16 to R31
406865f3bb9SMichael Rolnik  *  and is very well suited for operations on the X, Y, and Z-pointers.
407865f3bb9SMichael Rolnik  */
408865f3bb9SMichael Rolnik static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a)
409865f3bb9SMichael Rolnik {
410865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
411865f3bb9SMichael Rolnik     TCGv Rr = tcg_const_i32(a->imm);
412865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
413865f3bb9SMichael Rolnik 
414865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */
415865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
416865f3bb9SMichael Rolnik 
417865f3bb9SMichael Rolnik     /* update status register */
418865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
419865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
420865f3bb9SMichael Rolnik     gen_ZNSf(R);
421865f3bb9SMichael Rolnik 
422865f3bb9SMichael Rolnik     /* update output registers */
423865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
424865f3bb9SMichael Rolnik 
425865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
426865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rr);
427865f3bb9SMichael Rolnik 
428865f3bb9SMichael Rolnik     return true;
429865f3bb9SMichael Rolnik }
430865f3bb9SMichael Rolnik 
431865f3bb9SMichael Rolnik /*
432865f3bb9SMichael Rolnik  *  Subtracts two registers and subtracts with the C Flag and places the
433865f3bb9SMichael Rolnik  *  result in the destination register Rd.
434865f3bb9SMichael Rolnik  */
435865f3bb9SMichael Rolnik static bool trans_SBC(DisasContext *ctx, arg_SBC *a)
436865f3bb9SMichael Rolnik {
437865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
438865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
439865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
440865f3bb9SMichael Rolnik     TCGv zero = tcg_const_i32(0);
441865f3bb9SMichael Rolnik 
442865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
443865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
444865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
445865f3bb9SMichael Rolnik 
446865f3bb9SMichael Rolnik     /* update status register */
447865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
448865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
449865f3bb9SMichael Rolnik     gen_NSf(R);
450865f3bb9SMichael Rolnik 
451865f3bb9SMichael Rolnik     /*
452865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
453865f3bb9SMichael Rolnik      * cleared otherwise.
454865f3bb9SMichael Rolnik      */
455865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
456865f3bb9SMichael Rolnik 
457865f3bb9SMichael Rolnik     /* update output registers */
458865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
459865f3bb9SMichael Rolnik 
460865f3bb9SMichael Rolnik     tcg_temp_free_i32(zero);
461865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
462865f3bb9SMichael Rolnik 
463865f3bb9SMichael Rolnik     return true;
464865f3bb9SMichael Rolnik }
465865f3bb9SMichael Rolnik 
466865f3bb9SMichael Rolnik /*
467865f3bb9SMichael Rolnik  *  SBCI -- Subtract Immediate with Carry
468865f3bb9SMichael Rolnik  */
469865f3bb9SMichael Rolnik static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a)
470865f3bb9SMichael Rolnik {
471865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
472865f3bb9SMichael Rolnik     TCGv Rr = tcg_const_i32(a->imm);
473865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
474865f3bb9SMichael Rolnik     TCGv zero = tcg_const_i32(0);
475865f3bb9SMichael Rolnik 
476865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
477865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
478865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
479865f3bb9SMichael Rolnik 
480865f3bb9SMichael Rolnik     /* update status register */
481865f3bb9SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
482865f3bb9SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
483865f3bb9SMichael Rolnik     gen_NSf(R);
484865f3bb9SMichael Rolnik 
485865f3bb9SMichael Rolnik     /*
486865f3bb9SMichael Rolnik      * Previous value remains unchanged when the result is zero;
487865f3bb9SMichael Rolnik      * cleared otherwise.
488865f3bb9SMichael Rolnik      */
489865f3bb9SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
490865f3bb9SMichael Rolnik 
491865f3bb9SMichael Rolnik     /* update output registers */
492865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
493865f3bb9SMichael Rolnik 
494865f3bb9SMichael Rolnik     tcg_temp_free_i32(zero);
495865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
496865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rr);
497865f3bb9SMichael Rolnik 
498865f3bb9SMichael Rolnik     return true;
499865f3bb9SMichael Rolnik }
500865f3bb9SMichael Rolnik 
501865f3bb9SMichael Rolnik /*
502865f3bb9SMichael Rolnik  *  Subtracts an immediate value (0-63) from a register pair and places the
503865f3bb9SMichael Rolnik  *  result in the register pair. This instruction operates on the upper four
504865f3bb9SMichael Rolnik  *  register pairs, and is well suited for operations on the Pointer Registers.
505865f3bb9SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
506865f3bb9SMichael Rolnik  *  specific instruction set summary.
507865f3bb9SMichael Rolnik  */
508865f3bb9SMichael Rolnik static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a)
509865f3bb9SMichael Rolnik {
510865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
511865f3bb9SMichael Rolnik         return true;
512865f3bb9SMichael Rolnik     }
513865f3bb9SMichael Rolnik 
514865f3bb9SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
515865f3bb9SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
516865f3bb9SMichael Rolnik     int Imm = (a->imm);
517865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
518865f3bb9SMichael Rolnik     TCGv Rd = tcg_temp_new_i32();
519865f3bb9SMichael Rolnik 
520865f3bb9SMichael Rolnik     tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
521865f3bb9SMichael Rolnik     tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */
522865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
523865f3bb9SMichael Rolnik 
524865f3bb9SMichael Rolnik     /* update status register */
525865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Cf, R, Rd);
526865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */
527865f3bb9SMichael Rolnik     tcg_gen_andc_tl(cpu_Vf, Rd, R);
528865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */
529865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
530865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
531865f3bb9SMichael Rolnik     tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
532865f3bb9SMichael Rolnik 
533865f3bb9SMichael Rolnik     /* update output registers */
534865f3bb9SMichael Rolnik     tcg_gen_andi_tl(RdL, R, 0xff);
535865f3bb9SMichael Rolnik     tcg_gen_shri_tl(RdH, R, 8);
536865f3bb9SMichael Rolnik 
537865f3bb9SMichael Rolnik     tcg_temp_free_i32(Rd);
538865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
539865f3bb9SMichael Rolnik 
540865f3bb9SMichael Rolnik     return true;
541865f3bb9SMichael Rolnik }
542865f3bb9SMichael Rolnik 
543865f3bb9SMichael Rolnik /*
544865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and register
545865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
546865f3bb9SMichael Rolnik  */
547865f3bb9SMichael Rolnik static bool trans_AND(DisasContext *ctx, arg_AND *a)
548865f3bb9SMichael Rolnik {
549865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
550865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
551865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
552865f3bb9SMichael Rolnik 
553865f3bb9SMichael Rolnik     tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */
554865f3bb9SMichael Rolnik 
555865f3bb9SMichael Rolnik     /* update status register */
556865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
557865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
558865f3bb9SMichael Rolnik     gen_ZNSf(R);
559865f3bb9SMichael Rolnik 
560865f3bb9SMichael Rolnik     /* update output registers */
561865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
562865f3bb9SMichael Rolnik 
563865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
564865f3bb9SMichael Rolnik 
565865f3bb9SMichael Rolnik     return true;
566865f3bb9SMichael Rolnik }
567865f3bb9SMichael Rolnik 
568865f3bb9SMichael Rolnik /*
569865f3bb9SMichael Rolnik  *  Performs the logical AND between the contents of register Rd and a constant
570865f3bb9SMichael Rolnik  *  and places the result in the destination register Rd.
571865f3bb9SMichael Rolnik  */
572865f3bb9SMichael Rolnik static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a)
573865f3bb9SMichael Rolnik {
574865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
575865f3bb9SMichael Rolnik     int Imm = (a->imm);
576865f3bb9SMichael Rolnik 
577865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */
578865f3bb9SMichael Rolnik 
579865f3bb9SMichael Rolnik     /* update status register */
580865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
581865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
582865f3bb9SMichael Rolnik 
583865f3bb9SMichael Rolnik     return true;
584865f3bb9SMichael Rolnik }
585865f3bb9SMichael Rolnik 
586865f3bb9SMichael Rolnik /*
587865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and register
588865f3bb9SMichael Rolnik  *  Rr and places the result in the destination register Rd.
589865f3bb9SMichael Rolnik  */
590865f3bb9SMichael Rolnik static bool trans_OR(DisasContext *ctx, arg_OR *a)
591865f3bb9SMichael Rolnik {
592865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
593865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
594865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
595865f3bb9SMichael Rolnik 
596865f3bb9SMichael Rolnik     tcg_gen_or_tl(R, Rd, Rr);
597865f3bb9SMichael Rolnik 
598865f3bb9SMichael Rolnik     /* update status register */
599865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
600865f3bb9SMichael Rolnik     gen_ZNSf(R);
601865f3bb9SMichael Rolnik 
602865f3bb9SMichael Rolnik     /* update output registers */
603865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
604865f3bb9SMichael Rolnik 
605865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
606865f3bb9SMichael Rolnik 
607865f3bb9SMichael Rolnik     return true;
608865f3bb9SMichael Rolnik }
609865f3bb9SMichael Rolnik 
610865f3bb9SMichael Rolnik /*
611865f3bb9SMichael Rolnik  *  Performs the logical OR between the contents of register Rd and a
612865f3bb9SMichael Rolnik  *  constant and places the result in the destination register Rd.
613865f3bb9SMichael Rolnik  */
614865f3bb9SMichael Rolnik static bool trans_ORI(DisasContext *ctx, arg_ORI *a)
615865f3bb9SMichael Rolnik {
616865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
617865f3bb9SMichael Rolnik     int Imm = (a->imm);
618865f3bb9SMichael Rolnik 
619865f3bb9SMichael Rolnik     tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */
620865f3bb9SMichael Rolnik 
621865f3bb9SMichael Rolnik     /* update status register */
622865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
623865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
624865f3bb9SMichael Rolnik 
625865f3bb9SMichael Rolnik     return true;
626865f3bb9SMichael Rolnik }
627865f3bb9SMichael Rolnik 
628865f3bb9SMichael Rolnik /*
629865f3bb9SMichael Rolnik  *  Performs the logical EOR between the contents of register Rd and
630865f3bb9SMichael Rolnik  *  register Rr and places the result in the destination register Rd.
631865f3bb9SMichael Rolnik  */
632865f3bb9SMichael Rolnik static bool trans_EOR(DisasContext *ctx, arg_EOR *a)
633865f3bb9SMichael Rolnik {
634865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
635865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
636865f3bb9SMichael Rolnik 
637865f3bb9SMichael Rolnik     tcg_gen_xor_tl(Rd, Rd, Rr);
638865f3bb9SMichael Rolnik 
639865f3bb9SMichael Rolnik     /* update status register */
640865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0);
641865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
642865f3bb9SMichael Rolnik 
643865f3bb9SMichael Rolnik     return true;
644865f3bb9SMichael Rolnik }
645865f3bb9SMichael Rolnik 
646865f3bb9SMichael Rolnik /*
647865f3bb9SMichael Rolnik  *  Clears the specified bits in register Rd. Performs the logical AND
648865f3bb9SMichael Rolnik  *  between the contents of register Rd and the complement of the constant mask
649865f3bb9SMichael Rolnik  *  K. The result will be placed in register Rd.
650865f3bb9SMichael Rolnik  */
651865f3bb9SMichael Rolnik static bool trans_COM(DisasContext *ctx, arg_COM *a)
652865f3bb9SMichael Rolnik {
653865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
654865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
655865f3bb9SMichael Rolnik 
656865f3bb9SMichael Rolnik     tcg_gen_xori_tl(Rd, Rd, 0xff);
657865f3bb9SMichael Rolnik 
658865f3bb9SMichael Rolnik     /* update status register */
659865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */
660865f3bb9SMichael Rolnik     tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
661865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
662865f3bb9SMichael Rolnik 
663865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
664865f3bb9SMichael Rolnik 
665865f3bb9SMichael Rolnik     return true;
666865f3bb9SMichael Rolnik }
667865f3bb9SMichael Rolnik 
668865f3bb9SMichael Rolnik /*
669865f3bb9SMichael Rolnik  *  Replaces the contents of register Rd with its two's complement; the
670865f3bb9SMichael Rolnik  *  value $80 is left unchanged.
671865f3bb9SMichael Rolnik  */
672865f3bb9SMichael Rolnik static bool trans_NEG(DisasContext *ctx, arg_NEG *a)
673865f3bb9SMichael Rolnik {
674865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
675865f3bb9SMichael Rolnik     TCGv t0 = tcg_const_i32(0);
676865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
677865f3bb9SMichael Rolnik 
678865f3bb9SMichael Rolnik     tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */
679865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
680865f3bb9SMichael Rolnik 
681865f3bb9SMichael Rolnik     /* update status register */
682865f3bb9SMichael Rolnik     gen_sub_CHf(R, t0, Rd);
683865f3bb9SMichael Rolnik     gen_sub_Vf(R, t0, Rd);
684865f3bb9SMichael Rolnik     gen_ZNSf(R);
685865f3bb9SMichael Rolnik 
686865f3bb9SMichael Rolnik     /* update output registers */
687865f3bb9SMichael Rolnik     tcg_gen_mov_tl(Rd, R);
688865f3bb9SMichael Rolnik 
689865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
690865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
691865f3bb9SMichael Rolnik 
692865f3bb9SMichael Rolnik     return true;
693865f3bb9SMichael Rolnik }
694865f3bb9SMichael Rolnik 
695865f3bb9SMichael Rolnik /*
696865f3bb9SMichael Rolnik  *  Adds one -1- to the contents of register Rd and places the result in the
697865f3bb9SMichael Rolnik  *  destination register Rd.  The C Flag in SREG is not affected by the
698865f3bb9SMichael Rolnik  *  operation, thus allowing the INC instruction to be used on a loop counter in
699865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned numbers, only
700865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently. When
701865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
702865f3bb9SMichael Rolnik  */
703865f3bb9SMichael Rolnik static bool trans_INC(DisasContext *ctx, arg_INC *a)
704865f3bb9SMichael Rolnik {
705865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
706865f3bb9SMichael Rolnik 
707865f3bb9SMichael Rolnik     tcg_gen_addi_tl(Rd, Rd, 1);
708865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff);
709865f3bb9SMichael Rolnik 
710865f3bb9SMichael Rolnik     /* update status register */
711865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */
712865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
713865f3bb9SMichael Rolnik 
714865f3bb9SMichael Rolnik     return true;
715865f3bb9SMichael Rolnik }
716865f3bb9SMichael Rolnik 
717865f3bb9SMichael Rolnik /*
718865f3bb9SMichael Rolnik  *  Subtracts one -1- from the contents of register Rd and places the result
719865f3bb9SMichael Rolnik  *  in the destination register Rd.  The C Flag in SREG is not affected by the
720865f3bb9SMichael Rolnik  *  operation, thus allowing the DEC instruction to be used on a loop counter in
721865f3bb9SMichael Rolnik  *  multiple-precision computations.  When operating on unsigned values, only
722865f3bb9SMichael Rolnik  *  BREQ and BRNE branches can be expected to perform consistently.  When
723865f3bb9SMichael Rolnik  *  operating on two's complement values, all signed branches are available.
724865f3bb9SMichael Rolnik  */
725865f3bb9SMichael Rolnik static bool trans_DEC(DisasContext *ctx, arg_DEC *a)
726865f3bb9SMichael Rolnik {
727865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
728865f3bb9SMichael Rolnik 
729865f3bb9SMichael Rolnik     tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
730865f3bb9SMichael Rolnik     tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
731865f3bb9SMichael Rolnik 
732865f3bb9SMichael Rolnik     /* update status register */
733865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */
734865f3bb9SMichael Rolnik     gen_ZNSf(Rd);
735865f3bb9SMichael Rolnik 
736865f3bb9SMichael Rolnik     return true;
737865f3bb9SMichael Rolnik }
738865f3bb9SMichael Rolnik 
739865f3bb9SMichael Rolnik /*
740865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication.
741865f3bb9SMichael Rolnik  */
742865f3bb9SMichael Rolnik static bool trans_MUL(DisasContext *ctx, arg_MUL *a)
743865f3bb9SMichael Rolnik {
744865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
745865f3bb9SMichael Rolnik         return true;
746865f3bb9SMichael Rolnik     }
747865f3bb9SMichael Rolnik 
748865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
749865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
750865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
751865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
752865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
753865f3bb9SMichael Rolnik 
754865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
755865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
756865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
757865f3bb9SMichael Rolnik 
758865f3bb9SMichael Rolnik     /* update status register */
759865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
760865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
761865f3bb9SMichael Rolnik 
762865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
763865f3bb9SMichael Rolnik 
764865f3bb9SMichael Rolnik     return true;
765865f3bb9SMichael Rolnik }
766865f3bb9SMichael Rolnik 
767865f3bb9SMichael Rolnik /*
768865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication.
769865f3bb9SMichael Rolnik  */
770865f3bb9SMichael Rolnik static bool trans_MULS(DisasContext *ctx, arg_MULS *a)
771865f3bb9SMichael Rolnik {
772865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
773865f3bb9SMichael Rolnik         return true;
774865f3bb9SMichael Rolnik     }
775865f3bb9SMichael Rolnik 
776865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
777865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
778865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
779865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
780865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
781865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
782865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
783865f3bb9SMichael Rolnik 
784865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
785865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
786865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
787865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
788865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
789865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
790865f3bb9SMichael Rolnik 
791865f3bb9SMichael Rolnik     /* update status register */
792865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
793865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
794865f3bb9SMichael Rolnik 
795865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
796865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
797865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
798865f3bb9SMichael Rolnik 
799865f3bb9SMichael Rolnik     return true;
800865f3bb9SMichael Rolnik }
801865f3bb9SMichael Rolnik 
802865f3bb9SMichael Rolnik /*
803865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a
804865f3bb9SMichael Rolnik  *  signed and an unsigned number.
805865f3bb9SMichael Rolnik  */
806865f3bb9SMichael Rolnik static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a)
807865f3bb9SMichael Rolnik {
808865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
809865f3bb9SMichael Rolnik         return true;
810865f3bb9SMichael Rolnik     }
811865f3bb9SMichael Rolnik 
812865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
813865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
814865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
815865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
816865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
817865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
818865f3bb9SMichael Rolnik 
819865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
820865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
821865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */
822865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
823865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
824865f3bb9SMichael Rolnik 
825865f3bb9SMichael Rolnik     /* update status register */
826865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
827865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
828865f3bb9SMichael Rolnik 
829865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
830865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
831865f3bb9SMichael Rolnik 
832865f3bb9SMichael Rolnik     return true;
833865f3bb9SMichael Rolnik }
834865f3bb9SMichael Rolnik 
835865f3bb9SMichael Rolnik /*
836865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit unsigned
837865f3bb9SMichael Rolnik  *  multiplication and shifts the result one bit left.
838865f3bb9SMichael Rolnik  */
839865f3bb9SMichael Rolnik static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a)
840865f3bb9SMichael Rolnik {
841865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
842865f3bb9SMichael Rolnik         return true;
843865f3bb9SMichael Rolnik     }
844865f3bb9SMichael Rolnik 
845865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
846865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
847865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
848865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
849865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
850865f3bb9SMichael Rolnik 
851865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
852865f3bb9SMichael Rolnik 
853865f3bb9SMichael Rolnik     /* update status register */
854865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
855865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
856865f3bb9SMichael Rolnik 
857865f3bb9SMichael Rolnik     /* update output registers */
858865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
859865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
860865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
861865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
862865f3bb9SMichael Rolnik 
863865f3bb9SMichael Rolnik 
864865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
865865f3bb9SMichael Rolnik 
866865f3bb9SMichael Rolnik     return true;
867865f3bb9SMichael Rolnik }
868865f3bb9SMichael Rolnik 
869865f3bb9SMichael Rolnik /*
870865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
871865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
872865f3bb9SMichael Rolnik  */
873865f3bb9SMichael Rolnik static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a)
874865f3bb9SMichael Rolnik {
875865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
876865f3bb9SMichael Rolnik         return true;
877865f3bb9SMichael Rolnik     }
878865f3bb9SMichael Rolnik 
879865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
880865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
881865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
882865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
883865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
884865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
885865f3bb9SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
886865f3bb9SMichael Rolnik 
887865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
888865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
889865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
890865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
891865f3bb9SMichael Rolnik 
892865f3bb9SMichael Rolnik     /* update status register */
893865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
894865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
895865f3bb9SMichael Rolnik 
896865f3bb9SMichael Rolnik     /* update output registers */
897865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
898865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
899865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
900865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
901865f3bb9SMichael Rolnik 
902865f3bb9SMichael Rolnik     tcg_temp_free_i32(t1);
903865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
904865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
905865f3bb9SMichael Rolnik 
906865f3bb9SMichael Rolnik     return true;
907865f3bb9SMichael Rolnik }
908865f3bb9SMichael Rolnik 
909865f3bb9SMichael Rolnik /*
910865f3bb9SMichael Rolnik  *  This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
911865f3bb9SMichael Rolnik  *  and shifts the result one bit left.
912865f3bb9SMichael Rolnik  */
913865f3bb9SMichael Rolnik static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a)
914865f3bb9SMichael Rolnik {
915865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
916865f3bb9SMichael Rolnik         return true;
917865f3bb9SMichael Rolnik     }
918865f3bb9SMichael Rolnik 
919865f3bb9SMichael Rolnik     TCGv R0 = cpu_r[0];
920865f3bb9SMichael Rolnik     TCGv R1 = cpu_r[1];
921865f3bb9SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
922865f3bb9SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
923865f3bb9SMichael Rolnik     TCGv R = tcg_temp_new_i32();
924865f3bb9SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
925865f3bb9SMichael Rolnik 
926865f3bb9SMichael Rolnik     tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
927865f3bb9SMichael Rolnik     tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
928865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
929865f3bb9SMichael Rolnik 
930865f3bb9SMichael Rolnik     /* update status register */
931865f3bb9SMichael Rolnik     tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
932865f3bb9SMichael Rolnik     tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
933865f3bb9SMichael Rolnik 
934865f3bb9SMichael Rolnik     /* update output registers */
935865f3bb9SMichael Rolnik     tcg_gen_shli_tl(R, R, 1);
936865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R0, R, 0xff);
937865f3bb9SMichael Rolnik     tcg_gen_shri_tl(R1, R, 8);
938865f3bb9SMichael Rolnik     tcg_gen_andi_tl(R1, R1, 0xff);
939865f3bb9SMichael Rolnik 
940865f3bb9SMichael Rolnik     tcg_temp_free_i32(t0);
941865f3bb9SMichael Rolnik     tcg_temp_free_i32(R);
942865f3bb9SMichael Rolnik 
943865f3bb9SMichael Rolnik     return true;
944865f3bb9SMichael Rolnik }
945865f3bb9SMichael Rolnik 
946865f3bb9SMichael Rolnik /*
947865f3bb9SMichael Rolnik  *  The module is an instruction set extension to the AVR CPU, performing
948865f3bb9SMichael Rolnik  *  DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in
949865f3bb9SMichael Rolnik  *  the CPU register file, registers R0-R7, where LSB of data is placed in LSB
950865f3bb9SMichael Rolnik  *  of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including
951865f3bb9SMichael Rolnik  *  parity bits) is placed in registers R8- R15, organized in the register file
952865f3bb9SMichael Rolnik  *  with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES
953865f3bb9SMichael Rolnik  *  instruction performs one round in the DES algorithm. Sixteen rounds must be
954865f3bb9SMichael Rolnik  *  executed in increasing order to form the correct DES ciphertext or
955865f3bb9SMichael Rolnik  *  plaintext. Intermediate results are stored in the register file (R0-R15)
956865f3bb9SMichael Rolnik  *  after each DES instruction. The instruction's operand (K) determines which
957865f3bb9SMichael Rolnik  *  round is executed, and the half carry flag (H) determines whether encryption
958865f3bb9SMichael Rolnik  *  or decryption is performed.  The DES algorithm is described in
959865f3bb9SMichael Rolnik  *  "Specifications for the Data Encryption Standard" (Federal Information
960865f3bb9SMichael Rolnik  *  Processing Standards Publication 46). Intermediate results in this
961865f3bb9SMichael Rolnik  *  implementation differ from the standard because the initial permutation and
962865f3bb9SMichael Rolnik  *  the inverse initial permutation are performed each iteration. This does not
963865f3bb9SMichael Rolnik  *  affect the result in the final ciphertext or plaintext, but reduces
964865f3bb9SMichael Rolnik  *  execution time.
965865f3bb9SMichael Rolnik  */
966865f3bb9SMichael Rolnik static bool trans_DES(DisasContext *ctx, arg_DES *a)
967865f3bb9SMichael Rolnik {
968865f3bb9SMichael Rolnik     /* TODO */
969865f3bb9SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_DES)) {
970865f3bb9SMichael Rolnik         return true;
971865f3bb9SMichael Rolnik     }
972865f3bb9SMichael Rolnik 
973865f3bb9SMichael Rolnik     qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
974865f3bb9SMichael Rolnik 
975865f3bb9SMichael Rolnik     return true;
976865f3bb9SMichael Rolnik }
9779d316c75SMichael Rolnik 
9789d316c75SMichael Rolnik /*
9799d316c75SMichael Rolnik  * Branch Instructions
9809d316c75SMichael Rolnik  */
9819d316c75SMichael Rolnik static void gen_jmp_ez(DisasContext *ctx)
9829d316c75SMichael Rolnik {
9839d316c75SMichael Rolnik     tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
9849d316c75SMichael Rolnik     tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind);
9859d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
9869d316c75SMichael Rolnik }
9879d316c75SMichael Rolnik 
9889d316c75SMichael Rolnik static void gen_jmp_z(DisasContext *ctx)
9899d316c75SMichael Rolnik {
9909d316c75SMichael Rolnik     tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8);
9919d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
9929d316c75SMichael Rolnik }
9939d316c75SMichael Rolnik 
9949d316c75SMichael Rolnik static void gen_push_ret(DisasContext *ctx, int ret)
9959d316c75SMichael Rolnik {
9969d316c75SMichael Rolnik     if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
9979d316c75SMichael Rolnik 
9989d316c75SMichael Rolnik         TCGv t0 = tcg_const_i32((ret & 0x0000ff));
9999d316c75SMichael Rolnik 
10009d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB);
10019d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10029d316c75SMichael Rolnik 
10039d316c75SMichael Rolnik         tcg_temp_free_i32(t0);
10049d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
10059d316c75SMichael Rolnik 
10069d316c75SMichael Rolnik         TCGv t0 = tcg_const_i32((ret & 0x00ffff));
10079d316c75SMichael Rolnik 
10089d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10099d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10109d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10119d316c75SMichael Rolnik 
10129d316c75SMichael Rolnik         tcg_temp_free_i32(t0);
10139d316c75SMichael Rolnik 
10149d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
10159d316c75SMichael Rolnik 
10169d316c75SMichael Rolnik         TCGv lo = tcg_const_i32((ret & 0x0000ff));
10179d316c75SMichael Rolnik         TCGv hi = tcg_const_i32((ret & 0xffff00) >> 8);
10189d316c75SMichael Rolnik 
10199d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
10209d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 2);
10219d316c75SMichael Rolnik         tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10229d316c75SMichael Rolnik         tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
10239d316c75SMichael Rolnik 
10249d316c75SMichael Rolnik         tcg_temp_free_i32(lo);
10259d316c75SMichael Rolnik         tcg_temp_free_i32(hi);
10269d316c75SMichael Rolnik     }
10279d316c75SMichael Rolnik }
10289d316c75SMichael Rolnik 
10299d316c75SMichael Rolnik static void gen_pop_ret(DisasContext *ctx, TCGv ret)
10309d316c75SMichael Rolnik {
10319d316c75SMichael Rolnik     if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) {
10329d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10339d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB);
10349d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) {
10359d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10369d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10379d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10389d316c75SMichael Rolnik     } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) {
10399d316c75SMichael Rolnik         TCGv lo = tcg_temp_new_i32();
10409d316c75SMichael Rolnik         TCGv hi = tcg_temp_new_i32();
10419d316c75SMichael Rolnik 
10429d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
10439d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW);
10449d316c75SMichael Rolnik 
10459d316c75SMichael Rolnik         tcg_gen_addi_tl(cpu_sp, cpu_sp, 2);
10469d316c75SMichael Rolnik         tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB);
10479d316c75SMichael Rolnik 
10489d316c75SMichael Rolnik         tcg_gen_deposit_tl(ret, lo, hi, 8, 16);
10499d316c75SMichael Rolnik 
10509d316c75SMichael Rolnik         tcg_temp_free_i32(lo);
10519d316c75SMichael Rolnik         tcg_temp_free_i32(hi);
10529d316c75SMichael Rolnik     }
10539d316c75SMichael Rolnik }
10549d316c75SMichael Rolnik 
10559d316c75SMichael Rolnik static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
10569d316c75SMichael Rolnik {
10579d316c75SMichael Rolnik     TranslationBlock *tb = ctx->tb;
10589d316c75SMichael Rolnik 
10599d316c75SMichael Rolnik     if (ctx->singlestep == 0) {
10609d316c75SMichael Rolnik         tcg_gen_goto_tb(n);
10619d316c75SMichael Rolnik         tcg_gen_movi_i32(cpu_pc, dest);
10629d316c75SMichael Rolnik         tcg_gen_exit_tb(tb, n);
10639d316c75SMichael Rolnik     } else {
10649d316c75SMichael Rolnik         tcg_gen_movi_i32(cpu_pc, dest);
10659d316c75SMichael Rolnik         gen_helper_debug(cpu_env);
10669d316c75SMichael Rolnik         tcg_gen_exit_tb(NULL, 0);
10679d316c75SMichael Rolnik     }
10689d316c75SMichael Rolnik     ctx->bstate = DISAS_NORETURN;
10699d316c75SMichael Rolnik }
10709d316c75SMichael Rolnik 
10719d316c75SMichael Rolnik /*
10729d316c75SMichael Rolnik  *  Relative jump to an address within PC - 2K +1 and PC + 2K (words). For
10739d316c75SMichael Rolnik  *  AVR microcontrollers with Program memory not exceeding 4K words (8KB) this
10749d316c75SMichael Rolnik  *  instruction can address the entire memory from every address location. See
10759d316c75SMichael Rolnik  *  also JMP.
10769d316c75SMichael Rolnik  */
10779d316c75SMichael Rolnik static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a)
10789d316c75SMichael Rolnik {
10799d316c75SMichael Rolnik     int dst = ctx->npc + a->imm;
10809d316c75SMichael Rolnik 
10819d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, dst);
10829d316c75SMichael Rolnik 
10839d316c75SMichael Rolnik     return true;
10849d316c75SMichael Rolnik }
10859d316c75SMichael Rolnik 
10869d316c75SMichael Rolnik /*
10879d316c75SMichael Rolnik  *  Indirect jump to the address pointed to by the Z (16 bits) Pointer
10889d316c75SMichael Rolnik  *  Register in the Register File. The Z-pointer Register is 16 bits wide and
10899d316c75SMichael Rolnik  *  allows jump within the lowest 64K words (128KB) section of Program memory.
10909d316c75SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
10919d316c75SMichael Rolnik  *  specific instruction set summary.
10929d316c75SMichael Rolnik  */
10939d316c75SMichael Rolnik static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a)
10949d316c75SMichael Rolnik {
10959d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) {
10969d316c75SMichael Rolnik         return true;
10979d316c75SMichael Rolnik     }
10989d316c75SMichael Rolnik 
10999d316c75SMichael Rolnik     gen_jmp_z(ctx);
11009d316c75SMichael Rolnik 
11019d316c75SMichael Rolnik     return true;
11029d316c75SMichael Rolnik }
11039d316c75SMichael Rolnik 
11049d316c75SMichael Rolnik /*
11059d316c75SMichael Rolnik  *  Indirect jump to the address pointed to by the Z (16 bits) Pointer
11069d316c75SMichael Rolnik  *  Register in the Register File and the EIND Register in the I/O space. This
11079d316c75SMichael Rolnik  *  instruction allows for indirect jumps to the entire 4M (words) Program
11089d316c75SMichael Rolnik  *  memory space. See also IJMP.  This instruction is not available in all
11099d316c75SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.
11109d316c75SMichael Rolnik  */
11119d316c75SMichael Rolnik static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a)
11129d316c75SMichael Rolnik {
11139d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) {
11149d316c75SMichael Rolnik         return true;
11159d316c75SMichael Rolnik     }
11169d316c75SMichael Rolnik 
11179d316c75SMichael Rolnik     gen_jmp_ez(ctx);
11189d316c75SMichael Rolnik     return true;
11199d316c75SMichael Rolnik }
11209d316c75SMichael Rolnik 
11219d316c75SMichael Rolnik /*
11229d316c75SMichael Rolnik  *  Jump to an address within the entire 4M (words) Program memory. See also
11239d316c75SMichael Rolnik  *  RJMP.  This instruction is not available in all devices. Refer to the device
11249d316c75SMichael Rolnik  *  specific instruction set summary.0
11259d316c75SMichael Rolnik  */
11269d316c75SMichael Rolnik static bool trans_JMP(DisasContext *ctx, arg_JMP *a)
11279d316c75SMichael Rolnik {
11289d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) {
11299d316c75SMichael Rolnik         return true;
11309d316c75SMichael Rolnik     }
11319d316c75SMichael Rolnik 
11329d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, a->imm);
11339d316c75SMichael Rolnik 
11349d316c75SMichael Rolnik     return true;
11359d316c75SMichael Rolnik }
11369d316c75SMichael Rolnik 
11379d316c75SMichael Rolnik /*
11389d316c75SMichael Rolnik  *  Relative call to an address within PC - 2K + 1 and PC + 2K (words). The
11399d316c75SMichael Rolnik  *  return address (the instruction after the RCALL) is stored onto the Stack.
11409d316c75SMichael Rolnik  *  See also CALL. For AVR microcontrollers with Program memory not exceeding 4K
11419d316c75SMichael Rolnik  *  words (8KB) this instruction can address the entire memory from every
11429d316c75SMichael Rolnik  *  address location. The Stack Pointer uses a post-decrement scheme during
11439d316c75SMichael Rolnik  *  RCALL.
11449d316c75SMichael Rolnik  */
11459d316c75SMichael Rolnik static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a)
11469d316c75SMichael Rolnik {
11479d316c75SMichael Rolnik     int ret = ctx->npc;
11489d316c75SMichael Rolnik     int dst = ctx->npc + a->imm;
11499d316c75SMichael Rolnik 
11509d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
11519d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, dst);
11529d316c75SMichael Rolnik 
11539d316c75SMichael Rolnik     return true;
11549d316c75SMichael Rolnik }
11559d316c75SMichael Rolnik 
11569d316c75SMichael Rolnik /*
11579d316c75SMichael Rolnik  *  Calls to a subroutine within the entire 4M (words) Program memory. The
11589d316c75SMichael Rolnik  *  return address (to the instruction after the CALL) will be stored onto the
11599d316c75SMichael Rolnik  *  Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme during
11609d316c75SMichael Rolnik  *  CALL.  This instruction is not available in all devices. Refer to the device
11619d316c75SMichael Rolnik  *  specific instruction set summary.
11629d316c75SMichael Rolnik  */
11639d316c75SMichael Rolnik static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a)
11649d316c75SMichael Rolnik {
11659d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) {
11669d316c75SMichael Rolnik         return true;
11679d316c75SMichael Rolnik     }
11689d316c75SMichael Rolnik 
11699d316c75SMichael Rolnik     int ret = ctx->npc;
11709d316c75SMichael Rolnik 
11719d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
11729d316c75SMichael Rolnik     gen_jmp_z(ctx);
11739d316c75SMichael Rolnik 
11749d316c75SMichael Rolnik     return true;
11759d316c75SMichael Rolnik }
11769d316c75SMichael Rolnik 
11779d316c75SMichael Rolnik /*
11789d316c75SMichael Rolnik  *  Indirect call of a subroutine pointed to by the Z (16 bits) Pointer
11799d316c75SMichael Rolnik  *  Register in the Register File and the EIND Register in the I/O space. This
11809d316c75SMichael Rolnik  *  instruction allows for indirect calls to the entire 4M (words) Program
11819d316c75SMichael Rolnik  *  memory space. See also ICALL. The Stack Pointer uses a post-decrement scheme
11829d316c75SMichael Rolnik  *  during EICALL.  This instruction is not available in all devices. Refer to
11839d316c75SMichael Rolnik  *  the device specific instruction set summary.
11849d316c75SMichael Rolnik  */
11859d316c75SMichael Rolnik static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a)
11869d316c75SMichael Rolnik {
11879d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) {
11889d316c75SMichael Rolnik         return true;
11899d316c75SMichael Rolnik     }
11909d316c75SMichael Rolnik 
11919d316c75SMichael Rolnik     int ret = ctx->npc;
11929d316c75SMichael Rolnik 
11939d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
11949d316c75SMichael Rolnik     gen_jmp_ez(ctx);
11959d316c75SMichael Rolnik     return true;
11969d316c75SMichael Rolnik }
11979d316c75SMichael Rolnik 
11989d316c75SMichael Rolnik /*
11999d316c75SMichael Rolnik  *  Calls to a subroutine within the entire Program memory. The return
12009d316c75SMichael Rolnik  *  address (to the instruction after the CALL) will be stored onto the Stack.
12019d316c75SMichael Rolnik  *  (See also RCALL). The Stack Pointer uses a post-decrement scheme during
12029d316c75SMichael Rolnik  *  CALL.  This instruction is not available in all devices. Refer to the device
12039d316c75SMichael Rolnik  *  specific instruction set summary.
12049d316c75SMichael Rolnik  */
12059d316c75SMichael Rolnik static bool trans_CALL(DisasContext *ctx, arg_CALL *a)
12069d316c75SMichael Rolnik {
12079d316c75SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) {
12089d316c75SMichael Rolnik         return true;
12099d316c75SMichael Rolnik     }
12109d316c75SMichael Rolnik 
12119d316c75SMichael Rolnik     int Imm = a->imm;
12129d316c75SMichael Rolnik     int ret = ctx->npc;
12139d316c75SMichael Rolnik 
12149d316c75SMichael Rolnik     gen_push_ret(ctx, ret);
12159d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, Imm);
12169d316c75SMichael Rolnik 
12179d316c75SMichael Rolnik     return true;
12189d316c75SMichael Rolnik }
12199d316c75SMichael Rolnik 
12209d316c75SMichael Rolnik /*
12219d316c75SMichael Rolnik  *  Returns from subroutine. The return address is loaded from the STACK.
12229d316c75SMichael Rolnik  *  The Stack Pointer uses a preincrement scheme during RET.
12239d316c75SMichael Rolnik  */
12249d316c75SMichael Rolnik static bool trans_RET(DisasContext *ctx, arg_RET *a)
12259d316c75SMichael Rolnik {
12269d316c75SMichael Rolnik     gen_pop_ret(ctx, cpu_pc);
12279d316c75SMichael Rolnik 
12289d316c75SMichael Rolnik     ctx->bstate = DISAS_LOOKUP;
12299d316c75SMichael Rolnik     return true;
12309d316c75SMichael Rolnik }
12319d316c75SMichael Rolnik 
12329d316c75SMichael Rolnik /*
12339d316c75SMichael Rolnik  *  Returns from interrupt. The return address is loaded from the STACK and
12349d316c75SMichael Rolnik  *  the Global Interrupt Flag is set.  Note that the Status Register is not
12359d316c75SMichael Rolnik  *  automatically stored when entering an interrupt routine, and it is not
12369d316c75SMichael Rolnik  *  restored when returning from an interrupt routine. This must be handled by
12379d316c75SMichael Rolnik  *  the application program. The Stack Pointer uses a pre-increment scheme
12389d316c75SMichael Rolnik  *  during RETI.
12399d316c75SMichael Rolnik  */
12409d316c75SMichael Rolnik static bool trans_RETI(DisasContext *ctx, arg_RETI *a)
12419d316c75SMichael Rolnik {
12429d316c75SMichael Rolnik     gen_pop_ret(ctx, cpu_pc);
12439d316c75SMichael Rolnik     tcg_gen_movi_tl(cpu_If, 1);
12449d316c75SMichael Rolnik 
12459d316c75SMichael Rolnik     /* Need to return to main loop to re-evaluate interrupts.  */
12469d316c75SMichael Rolnik     ctx->bstate = DISAS_EXIT;
12479d316c75SMichael Rolnik     return true;
12489d316c75SMichael Rolnik }
12499d316c75SMichael Rolnik 
12509d316c75SMichael Rolnik /*
12519d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr, and
12529d316c75SMichael Rolnik  *  skips the next instruction if Rd = Rr.
12539d316c75SMichael Rolnik  */
12549d316c75SMichael Rolnik static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a)
12559d316c75SMichael Rolnik {
12569d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
12579d316c75SMichael Rolnik     ctx->skip_var0 = cpu_r[a->rd];
12589d316c75SMichael Rolnik     ctx->skip_var1 = cpu_r[a->rr];
12599d316c75SMichael Rolnik     return true;
12609d316c75SMichael Rolnik }
12619d316c75SMichael Rolnik 
12629d316c75SMichael Rolnik /*
12639d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr.
12649d316c75SMichael Rolnik  *  None of the registers are changed. All conditional branches can be used
12659d316c75SMichael Rolnik  *  after this instruction.
12669d316c75SMichael Rolnik  */
12679d316c75SMichael Rolnik static bool trans_CP(DisasContext *ctx, arg_CP *a)
12689d316c75SMichael Rolnik {
12699d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
12709d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
12719d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
12729d316c75SMichael Rolnik 
12739d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
12749d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
12759d316c75SMichael Rolnik 
12769d316c75SMichael Rolnik     /* update status register */
12779d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
12789d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
12799d316c75SMichael Rolnik     gen_ZNSf(R);
12809d316c75SMichael Rolnik 
12819d316c75SMichael Rolnik     tcg_temp_free_i32(R);
12829d316c75SMichael Rolnik 
12839d316c75SMichael Rolnik     return true;
12849d316c75SMichael Rolnik }
12859d316c75SMichael Rolnik 
12869d316c75SMichael Rolnik /*
12879d316c75SMichael Rolnik  *  This instruction performs a compare between two registers Rd and Rr and
12889d316c75SMichael Rolnik  *  also takes into account the previous carry. None of the registers are
12899d316c75SMichael Rolnik  *  changed. All conditional branches can be used after this instruction.
12909d316c75SMichael Rolnik  */
12919d316c75SMichael Rolnik static bool trans_CPC(DisasContext *ctx, arg_CPC *a)
12929d316c75SMichael Rolnik {
12939d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
12949d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
12959d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
12969d316c75SMichael Rolnik     TCGv zero = tcg_const_i32(0);
12979d316c75SMichael Rolnik 
12989d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
12999d316c75SMichael Rolnik     tcg_gen_sub_tl(R, R, cpu_Cf);
13009d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
13019d316c75SMichael Rolnik     /* update status register */
13029d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
13039d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
13049d316c75SMichael Rolnik     gen_NSf(R);
13059d316c75SMichael Rolnik 
13069d316c75SMichael Rolnik     /*
13079d316c75SMichael Rolnik      * Previous value remains unchanged when the result is zero;
13089d316c75SMichael Rolnik      * cleared otherwise.
13099d316c75SMichael Rolnik      */
13109d316c75SMichael Rolnik     tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
13119d316c75SMichael Rolnik 
13129d316c75SMichael Rolnik     tcg_temp_free_i32(zero);
13139d316c75SMichael Rolnik     tcg_temp_free_i32(R);
13149d316c75SMichael Rolnik 
13159d316c75SMichael Rolnik     return true;
13169d316c75SMichael Rolnik }
13179d316c75SMichael Rolnik 
13189d316c75SMichael Rolnik /*
13199d316c75SMichael Rolnik  *  This instruction performs a compare between register Rd and a constant.
13209d316c75SMichael Rolnik  *  The register is not changed. All conditional branches can be used after this
13219d316c75SMichael Rolnik  *  instruction.
13229d316c75SMichael Rolnik  */
13239d316c75SMichael Rolnik static bool trans_CPI(DisasContext *ctx, arg_CPI *a)
13249d316c75SMichael Rolnik {
13259d316c75SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
13269d316c75SMichael Rolnik     int Imm = a->imm;
13279d316c75SMichael Rolnik     TCGv Rr = tcg_const_i32(Imm);
13289d316c75SMichael Rolnik     TCGv R = tcg_temp_new_i32();
13299d316c75SMichael Rolnik 
13309d316c75SMichael Rolnik     tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
13319d316c75SMichael Rolnik     tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
13329d316c75SMichael Rolnik 
13339d316c75SMichael Rolnik     /* update status register */
13349d316c75SMichael Rolnik     gen_sub_CHf(R, Rd, Rr);
13359d316c75SMichael Rolnik     gen_sub_Vf(R, Rd, Rr);
13369d316c75SMichael Rolnik     gen_ZNSf(R);
13379d316c75SMichael Rolnik 
13389d316c75SMichael Rolnik     tcg_temp_free_i32(R);
13399d316c75SMichael Rolnik     tcg_temp_free_i32(Rr);
13409d316c75SMichael Rolnik 
13419d316c75SMichael Rolnik     return true;
13429d316c75SMichael Rolnik }
13439d316c75SMichael Rolnik 
13449d316c75SMichael Rolnik /*
13459d316c75SMichael Rolnik  *  This instruction tests a single bit in a register and skips the next
13469d316c75SMichael Rolnik  *  instruction if the bit is cleared.
13479d316c75SMichael Rolnik  */
13489d316c75SMichael Rolnik static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a)
13499d316c75SMichael Rolnik {
13509d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
13519d316c75SMichael Rolnik 
13529d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
13539d316c75SMichael Rolnik     ctx->skip_var0 = tcg_temp_new();
13549d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
13559d316c75SMichael Rolnik 
13569d316c75SMichael Rolnik     tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
13579d316c75SMichael Rolnik     return true;
13589d316c75SMichael Rolnik }
13599d316c75SMichael Rolnik 
13609d316c75SMichael Rolnik /*
13619d316c75SMichael Rolnik  *  This instruction tests a single bit in a register and skips the next
13629d316c75SMichael Rolnik  *  instruction if the bit is set.
13639d316c75SMichael Rolnik  */
13649d316c75SMichael Rolnik static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a)
13659d316c75SMichael Rolnik {
13669d316c75SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
13679d316c75SMichael Rolnik 
13689d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_NE;
13699d316c75SMichael Rolnik     ctx->skip_var0 = tcg_temp_new();
13709d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
13719d316c75SMichael Rolnik 
13729d316c75SMichael Rolnik     tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit);
13739d316c75SMichael Rolnik     return true;
13749d316c75SMichael Rolnik }
13759d316c75SMichael Rolnik 
13769d316c75SMichael Rolnik /*
13779d316c75SMichael Rolnik  *  This instruction tests a single bit in an I/O Register and skips the
13789d316c75SMichael Rolnik  *  next instruction if the bit is cleared. This instruction operates on the
13799d316c75SMichael Rolnik  *  lower 32 I/O Registers -- addresses 0-31.
13809d316c75SMichael Rolnik  */
13819d316c75SMichael Rolnik static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a)
13829d316c75SMichael Rolnik {
13839d316c75SMichael Rolnik     TCGv temp = tcg_const_i32(a->reg);
13849d316c75SMichael Rolnik 
13859d316c75SMichael Rolnik     gen_helper_inb(temp, cpu_env, temp);
13869d316c75SMichael Rolnik     tcg_gen_andi_tl(temp, temp, 1 << a->bit);
13879d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_EQ;
13889d316c75SMichael Rolnik     ctx->skip_var0 = temp;
13899d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
13909d316c75SMichael Rolnik 
13919d316c75SMichael Rolnik     return true;
13929d316c75SMichael Rolnik }
13939d316c75SMichael Rolnik 
13949d316c75SMichael Rolnik /*
13959d316c75SMichael Rolnik  *  This instruction tests a single bit in an I/O Register and skips the
13969d316c75SMichael Rolnik  *  next instruction if the bit is set. This instruction operates on the lower
13979d316c75SMichael Rolnik  *  32 I/O Registers -- addresses 0-31.
13989d316c75SMichael Rolnik  */
13999d316c75SMichael Rolnik static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a)
14009d316c75SMichael Rolnik {
14019d316c75SMichael Rolnik     TCGv temp = tcg_const_i32(a->reg);
14029d316c75SMichael Rolnik 
14039d316c75SMichael Rolnik     gen_helper_inb(temp, cpu_env, temp);
14049d316c75SMichael Rolnik     tcg_gen_andi_tl(temp, temp, 1 << a->bit);
14059d316c75SMichael Rolnik     ctx->skip_cond = TCG_COND_NE;
14069d316c75SMichael Rolnik     ctx->skip_var0 = temp;
14079d316c75SMichael Rolnik     ctx->free_skip_var0 = true;
14089d316c75SMichael Rolnik 
14099d316c75SMichael Rolnik     return true;
14109d316c75SMichael Rolnik }
14119d316c75SMichael Rolnik 
14129d316c75SMichael Rolnik /*
14139d316c75SMichael Rolnik  *  Conditional relative branch. Tests a single bit in SREG and branches
14149d316c75SMichael Rolnik  *  relatively to PC if the bit is cleared. This instruction branches relatively
14159d316c75SMichael Rolnik  *  to PC in either direction (PC - 63 < = destination <= PC + 64). The
14169d316c75SMichael Rolnik  *  parameter k is the offset from PC and is represented in two's complement
14179d316c75SMichael Rolnik  *  form.
14189d316c75SMichael Rolnik  */
14199d316c75SMichael Rolnik static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a)
14209d316c75SMichael Rolnik {
14219d316c75SMichael Rolnik     TCGLabel *not_taken = gen_new_label();
14229d316c75SMichael Rolnik 
14239d316c75SMichael Rolnik     TCGv var;
14249d316c75SMichael Rolnik 
14259d316c75SMichael Rolnik     switch (a->bit) {
14269d316c75SMichael Rolnik     case 0x00:
14279d316c75SMichael Rolnik         var = cpu_Cf;
14289d316c75SMichael Rolnik         break;
14299d316c75SMichael Rolnik     case 0x01:
14309d316c75SMichael Rolnik         var = cpu_Zf;
14319d316c75SMichael Rolnik         break;
14329d316c75SMichael Rolnik     case 0x02:
14339d316c75SMichael Rolnik         var = cpu_Nf;
14349d316c75SMichael Rolnik         break;
14359d316c75SMichael Rolnik     case 0x03:
14369d316c75SMichael Rolnik         var = cpu_Vf;
14379d316c75SMichael Rolnik         break;
14389d316c75SMichael Rolnik     case 0x04:
14399d316c75SMichael Rolnik         var = cpu_Sf;
14409d316c75SMichael Rolnik         break;
14419d316c75SMichael Rolnik     case 0x05:
14429d316c75SMichael Rolnik         var = cpu_Hf;
14439d316c75SMichael Rolnik         break;
14449d316c75SMichael Rolnik     case 0x06:
14459d316c75SMichael Rolnik         var = cpu_Tf;
14469d316c75SMichael Rolnik         break;
14479d316c75SMichael Rolnik     case 0x07:
14489d316c75SMichael Rolnik         var = cpu_If;
14499d316c75SMichael Rolnik         break;
14509d316c75SMichael Rolnik     default:
14519d316c75SMichael Rolnik         g_assert_not_reached();
14529d316c75SMichael Rolnik     }
14539d316c75SMichael Rolnik 
14549d316c75SMichael Rolnik     tcg_gen_brcondi_i32(TCG_COND_NE, var, 0, not_taken);
14559d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, ctx->npc + a->imm);
14569d316c75SMichael Rolnik     gen_set_label(not_taken);
14579d316c75SMichael Rolnik 
14589d316c75SMichael Rolnik     ctx->bstate = DISAS_CHAIN;
14599d316c75SMichael Rolnik     return true;
14609d316c75SMichael Rolnik }
14619d316c75SMichael Rolnik 
14629d316c75SMichael Rolnik /*
14639d316c75SMichael Rolnik  *  Conditional relative branch. Tests a single bit in SREG and branches
14649d316c75SMichael Rolnik  *  relatively to PC if the bit is set. This instruction branches relatively to
14659d316c75SMichael Rolnik  *  PC in either direction (PC - 63 < = destination <= PC + 64). The parameter k
14669d316c75SMichael Rolnik  *  is the offset from PC and is represented in two's complement form.
14679d316c75SMichael Rolnik  */
14689d316c75SMichael Rolnik static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a)
14699d316c75SMichael Rolnik {
14709d316c75SMichael Rolnik     TCGLabel *not_taken = gen_new_label();
14719d316c75SMichael Rolnik 
14729d316c75SMichael Rolnik     TCGv var;
14739d316c75SMichael Rolnik 
14749d316c75SMichael Rolnik     switch (a->bit) {
14759d316c75SMichael Rolnik     case 0x00:
14769d316c75SMichael Rolnik         var = cpu_Cf;
14779d316c75SMichael Rolnik         break;
14789d316c75SMichael Rolnik     case 0x01:
14799d316c75SMichael Rolnik         var = cpu_Zf;
14809d316c75SMichael Rolnik         break;
14819d316c75SMichael Rolnik     case 0x02:
14829d316c75SMichael Rolnik         var = cpu_Nf;
14839d316c75SMichael Rolnik         break;
14849d316c75SMichael Rolnik     case 0x03:
14859d316c75SMichael Rolnik         var = cpu_Vf;
14869d316c75SMichael Rolnik         break;
14879d316c75SMichael Rolnik     case 0x04:
14889d316c75SMichael Rolnik         var = cpu_Sf;
14899d316c75SMichael Rolnik         break;
14909d316c75SMichael Rolnik     case 0x05:
14919d316c75SMichael Rolnik         var = cpu_Hf;
14929d316c75SMichael Rolnik         break;
14939d316c75SMichael Rolnik     case 0x06:
14949d316c75SMichael Rolnik         var = cpu_Tf;
14959d316c75SMichael Rolnik         break;
14969d316c75SMichael Rolnik     case 0x07:
14979d316c75SMichael Rolnik         var = cpu_If;
14989d316c75SMichael Rolnik         break;
14999d316c75SMichael Rolnik     default:
15009d316c75SMichael Rolnik         g_assert_not_reached();
15019d316c75SMichael Rolnik     }
15029d316c75SMichael Rolnik 
15039d316c75SMichael Rolnik     tcg_gen_brcondi_i32(TCG_COND_EQ, var, 0, not_taken);
15049d316c75SMichael Rolnik     gen_goto_tb(ctx, 0, ctx->npc + a->imm);
15059d316c75SMichael Rolnik     gen_set_label(not_taken);
15069d316c75SMichael Rolnik 
15079d316c75SMichael Rolnik     ctx->bstate = DISAS_CHAIN;
15089d316c75SMichael Rolnik     return true;
15099d316c75SMichael Rolnik }
1510*9732b024SMichael Rolnik 
1511*9732b024SMichael Rolnik /*
1512*9732b024SMichael Rolnik  * Data Transfer Instructions
1513*9732b024SMichael Rolnik  */
1514*9732b024SMichael Rolnik 
1515*9732b024SMichael Rolnik /*
1516*9732b024SMichael Rolnik  *  in the gen_set_addr & gen_get_addr functions
1517*9732b024SMichael Rolnik  *  H assumed to be in 0x00ff0000 format
1518*9732b024SMichael Rolnik  *  M assumed to be in 0x000000ff format
1519*9732b024SMichael Rolnik  *  L assumed to be in 0x000000ff format
1520*9732b024SMichael Rolnik  */
1521*9732b024SMichael Rolnik static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L)
1522*9732b024SMichael Rolnik {
1523*9732b024SMichael Rolnik 
1524*9732b024SMichael Rolnik     tcg_gen_andi_tl(L, addr, 0x000000ff);
1525*9732b024SMichael Rolnik 
1526*9732b024SMichael Rolnik     tcg_gen_andi_tl(M, addr, 0x0000ff00);
1527*9732b024SMichael Rolnik     tcg_gen_shri_tl(M, M, 8);
1528*9732b024SMichael Rolnik 
1529*9732b024SMichael Rolnik     tcg_gen_andi_tl(H, addr, 0x00ff0000);
1530*9732b024SMichael Rolnik }
1531*9732b024SMichael Rolnik 
1532*9732b024SMichael Rolnik static void gen_set_xaddr(TCGv addr)
1533*9732b024SMichael Rolnik {
1534*9732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]);
1535*9732b024SMichael Rolnik }
1536*9732b024SMichael Rolnik 
1537*9732b024SMichael Rolnik static void gen_set_yaddr(TCGv addr)
1538*9732b024SMichael Rolnik {
1539*9732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]);
1540*9732b024SMichael Rolnik }
1541*9732b024SMichael Rolnik 
1542*9732b024SMichael Rolnik static void gen_set_zaddr(TCGv addr)
1543*9732b024SMichael Rolnik {
1544*9732b024SMichael Rolnik     gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]);
1545*9732b024SMichael Rolnik }
1546*9732b024SMichael Rolnik 
1547*9732b024SMichael Rolnik static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L)
1548*9732b024SMichael Rolnik {
1549*9732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
1550*9732b024SMichael Rolnik 
1551*9732b024SMichael Rolnik     tcg_gen_deposit_tl(addr, M, H, 8, 8);
1552*9732b024SMichael Rolnik     tcg_gen_deposit_tl(addr, L, addr, 8, 16);
1553*9732b024SMichael Rolnik 
1554*9732b024SMichael Rolnik     return addr;
1555*9732b024SMichael Rolnik }
1556*9732b024SMichael Rolnik 
1557*9732b024SMichael Rolnik static TCGv gen_get_xaddr(void)
1558*9732b024SMichael Rolnik {
1559*9732b024SMichael Rolnik     return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]);
1560*9732b024SMichael Rolnik }
1561*9732b024SMichael Rolnik 
1562*9732b024SMichael Rolnik static TCGv gen_get_yaddr(void)
1563*9732b024SMichael Rolnik {
1564*9732b024SMichael Rolnik     return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]);
1565*9732b024SMichael Rolnik }
1566*9732b024SMichael Rolnik 
1567*9732b024SMichael Rolnik static TCGv gen_get_zaddr(void)
1568*9732b024SMichael Rolnik {
1569*9732b024SMichael Rolnik     return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]);
1570*9732b024SMichael Rolnik }
1571*9732b024SMichael Rolnik 
1572*9732b024SMichael Rolnik /*
1573*9732b024SMichael Rolnik  *  Load one byte indirect from data space to register and stores an clear
1574*9732b024SMichael Rolnik  *  the bits in data space specified by the register. The instruction can only
1575*9732b024SMichael Rolnik  *  be used towards internal SRAM.  The data location is pointed to by the Z (16
1576*9732b024SMichael Rolnik  *  bits) Pointer Register in the Register File. Memory access is limited to the
1577*9732b024SMichael Rolnik  *  current data segment of 64KB. To access another data segment in devices with
1578*9732b024SMichael Rolnik  *  more than 64KB data space, the RAMPZ in register in the I/O area has to be
1579*9732b024SMichael Rolnik  *  changed.  The Z-pointer Register is left unchanged by the operation. This
1580*9732b024SMichael Rolnik  *  instruction is especially suited for clearing status bits stored in SRAM.
1581*9732b024SMichael Rolnik  */
1582*9732b024SMichael Rolnik static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr)
1583*9732b024SMichael Rolnik {
1584*9732b024SMichael Rolnik     if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) {
1585*9732b024SMichael Rolnik         gen_helper_fullwr(cpu_env, data, addr);
1586*9732b024SMichael Rolnik     } else {
1587*9732b024SMichael Rolnik         tcg_gen_qemu_st8(data, addr, MMU_DATA_IDX); /* mem[addr] = data */
1588*9732b024SMichael Rolnik     }
1589*9732b024SMichael Rolnik }
1590*9732b024SMichael Rolnik 
1591*9732b024SMichael Rolnik static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr)
1592*9732b024SMichael Rolnik {
1593*9732b024SMichael Rolnik     if (ctx->tb->flags & TB_FLAGS_FULL_ACCESS) {
1594*9732b024SMichael Rolnik         gen_helper_fullrd(data, cpu_env, addr);
1595*9732b024SMichael Rolnik     } else {
1596*9732b024SMichael Rolnik         tcg_gen_qemu_ld8u(data, addr, MMU_DATA_IDX); /* data = mem[addr] */
1597*9732b024SMichael Rolnik     }
1598*9732b024SMichael Rolnik }
1599*9732b024SMichael Rolnik 
1600*9732b024SMichael Rolnik /*
1601*9732b024SMichael Rolnik  *  This instruction makes a copy of one register into another. The source
1602*9732b024SMichael Rolnik  *  register Rr is left unchanged, while the destination register Rd is loaded
1603*9732b024SMichael Rolnik  *  with a copy of Rr.
1604*9732b024SMichael Rolnik  */
1605*9732b024SMichael Rolnik static bool trans_MOV(DisasContext *ctx, arg_MOV *a)
1606*9732b024SMichael Rolnik {
1607*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1608*9732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rr];
1609*9732b024SMichael Rolnik 
1610*9732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, Rr);
1611*9732b024SMichael Rolnik 
1612*9732b024SMichael Rolnik     return true;
1613*9732b024SMichael Rolnik }
1614*9732b024SMichael Rolnik 
1615*9732b024SMichael Rolnik /*
1616*9732b024SMichael Rolnik  *  This instruction makes a copy of one register pair into another register
1617*9732b024SMichael Rolnik  *  pair. The source register pair Rr+1:Rr is left unchanged, while the
1618*9732b024SMichael Rolnik  *  destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr.  This
1619*9732b024SMichael Rolnik  *  instruction is not available in all devices. Refer to the device specific
1620*9732b024SMichael Rolnik  *  instruction set summary.
1621*9732b024SMichael Rolnik  */
1622*9732b024SMichael Rolnik static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a)
1623*9732b024SMichael Rolnik {
1624*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_MOVW)) {
1625*9732b024SMichael Rolnik         return true;
1626*9732b024SMichael Rolnik     }
1627*9732b024SMichael Rolnik 
1628*9732b024SMichael Rolnik     TCGv RdL = cpu_r[a->rd];
1629*9732b024SMichael Rolnik     TCGv RdH = cpu_r[a->rd + 1];
1630*9732b024SMichael Rolnik     TCGv RrL = cpu_r[a->rr];
1631*9732b024SMichael Rolnik     TCGv RrH = cpu_r[a->rr + 1];
1632*9732b024SMichael Rolnik 
1633*9732b024SMichael Rolnik     tcg_gen_mov_tl(RdH, RrH);
1634*9732b024SMichael Rolnik     tcg_gen_mov_tl(RdL, RrL);
1635*9732b024SMichael Rolnik 
1636*9732b024SMichael Rolnik     return true;
1637*9732b024SMichael Rolnik }
1638*9732b024SMichael Rolnik 
1639*9732b024SMichael Rolnik /*
1640*9732b024SMichael Rolnik  * Loads an 8 bit constant directly to register 16 to 31.
1641*9732b024SMichael Rolnik  */
1642*9732b024SMichael Rolnik static bool trans_LDI(DisasContext *ctx, arg_LDI *a)
1643*9732b024SMichael Rolnik {
1644*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1645*9732b024SMichael Rolnik     int imm = a->imm;
1646*9732b024SMichael Rolnik 
1647*9732b024SMichael Rolnik     tcg_gen_movi_tl(Rd, imm);
1648*9732b024SMichael Rolnik 
1649*9732b024SMichael Rolnik     return true;
1650*9732b024SMichael Rolnik }
1651*9732b024SMichael Rolnik 
1652*9732b024SMichael Rolnik /*
1653*9732b024SMichael Rolnik  *  Loads one byte from the data space to a register. For parts with SRAM,
1654*9732b024SMichael Rolnik  *  the data space consists of the Register File, I/O memory and internal SRAM
1655*9732b024SMichael Rolnik  *  (and external SRAM if applicable). For parts without SRAM, the data space
1656*9732b024SMichael Rolnik  *  consists of the register file only. The EEPROM has a separate address space.
1657*9732b024SMichael Rolnik  *  A 16-bit address must be supplied. Memory access is limited to the current
1658*9732b024SMichael Rolnik  *  data segment of 64KB. The LDS instruction uses the RAMPD Register to access
1659*9732b024SMichael Rolnik  *  memory above 64KB. To access another data segment in devices with more than
1660*9732b024SMichael Rolnik  *  64KB data space, the RAMPD in register in the I/O area has to be changed.
1661*9732b024SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
1662*9732b024SMichael Rolnik  *  specific instruction set summary.
1663*9732b024SMichael Rolnik  */
1664*9732b024SMichael Rolnik static bool trans_LDS(DisasContext *ctx, arg_LDS *a)
1665*9732b024SMichael Rolnik {
1666*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1667*9732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
1668*9732b024SMichael Rolnik     TCGv H = cpu_rampD;
1669*9732b024SMichael Rolnik     a->imm = next_word(ctx);
1670*9732b024SMichael Rolnik 
1671*9732b024SMichael Rolnik     tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
1672*9732b024SMichael Rolnik     tcg_gen_shli_tl(addr, addr, 16);
1673*9732b024SMichael Rolnik     tcg_gen_ori_tl(addr, addr, a->imm);
1674*9732b024SMichael Rolnik 
1675*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
1676*9732b024SMichael Rolnik 
1677*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1678*9732b024SMichael Rolnik 
1679*9732b024SMichael Rolnik     return true;
1680*9732b024SMichael Rolnik }
1681*9732b024SMichael Rolnik 
1682*9732b024SMichael Rolnik /*
1683*9732b024SMichael Rolnik  *  Loads one byte indirect from the data space to a register. For parts
1684*9732b024SMichael Rolnik  *  with SRAM, the data space consists of the Register File, I/O memory and
1685*9732b024SMichael Rolnik  *  internal SRAM (and external SRAM if applicable). For parts without SRAM, the
1686*9732b024SMichael Rolnik  *  data space consists of the Register File only. In some parts the Flash
1687*9732b024SMichael Rolnik  *  Memory has been mapped to the data space and can be read using this command.
1688*9732b024SMichael Rolnik  *  The EEPROM has a separate address space.  The data location is pointed to by
1689*9732b024SMichael Rolnik  *  the X (16 bits) Pointer Register in the Register File. Memory access is
1690*9732b024SMichael Rolnik  *  limited to the current data segment of 64KB. To access another data segment
1691*9732b024SMichael Rolnik  *  in devices with more than 64KB data space, the RAMPX in register in the I/O
1692*9732b024SMichael Rolnik  *  area has to be changed.  The X-pointer Register can either be left unchanged
1693*9732b024SMichael Rolnik  *  by the operation, or it can be post-incremented or predecremented.  These
1694*9732b024SMichael Rolnik  *  features are especially suited for accessing arrays, tables, and Stack
1695*9732b024SMichael Rolnik  *  Pointer usage of the X-pointer Register. Note that only the low byte of the
1696*9732b024SMichael Rolnik  *  X-pointer is updated in devices with no more than 256 bytes data space. For
1697*9732b024SMichael Rolnik  *  such devices, the high byte of the pointer is not used by this instruction
1698*9732b024SMichael Rolnik  *  and can be used for other purposes. The RAMPX Register in the I/O area is
1699*9732b024SMichael Rolnik  *  updated in parts with more than 64KB data space or more than 64KB Program
1700*9732b024SMichael Rolnik  *  memory, and the increment/decrement is added to the entire 24-bit address on
1701*9732b024SMichael Rolnik  *  such devices.  Not all variants of this instruction is available in all
1702*9732b024SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.  In the
1703*9732b024SMichael Rolnik  *  Reduced Core tinyAVR the LD instruction can be used to achieve the same
1704*9732b024SMichael Rolnik  *  operation as LPM since the program memory is mapped to the data memory
1705*9732b024SMichael Rolnik  *  space.
1706*9732b024SMichael Rolnik  */
1707*9732b024SMichael Rolnik static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a)
1708*9732b024SMichael Rolnik {
1709*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1710*9732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
1711*9732b024SMichael Rolnik 
1712*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
1713*9732b024SMichael Rolnik 
1714*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1715*9732b024SMichael Rolnik 
1716*9732b024SMichael Rolnik     return true;
1717*9732b024SMichael Rolnik }
1718*9732b024SMichael Rolnik 
1719*9732b024SMichael Rolnik static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a)
1720*9732b024SMichael Rolnik {
1721*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1722*9732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
1723*9732b024SMichael Rolnik 
1724*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
1725*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
1726*9732b024SMichael Rolnik 
1727*9732b024SMichael Rolnik     gen_set_xaddr(addr);
1728*9732b024SMichael Rolnik 
1729*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1730*9732b024SMichael Rolnik 
1731*9732b024SMichael Rolnik     return true;
1732*9732b024SMichael Rolnik }
1733*9732b024SMichael Rolnik 
1734*9732b024SMichael Rolnik static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a)
1735*9732b024SMichael Rolnik {
1736*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1737*9732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
1738*9732b024SMichael Rolnik 
1739*9732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
1740*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
1741*9732b024SMichael Rolnik     gen_set_xaddr(addr);
1742*9732b024SMichael Rolnik 
1743*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1744*9732b024SMichael Rolnik 
1745*9732b024SMichael Rolnik     return true;
1746*9732b024SMichael Rolnik }
1747*9732b024SMichael Rolnik 
1748*9732b024SMichael Rolnik /*
1749*9732b024SMichael Rolnik  *  Loads one byte indirect with or without displacement from the data space
1750*9732b024SMichael Rolnik  *  to a register. For parts with SRAM, the data space consists of the Register
1751*9732b024SMichael Rolnik  *  File, I/O memory and internal SRAM (and external SRAM if applicable). For
1752*9732b024SMichael Rolnik  *  parts without SRAM, the data space consists of the Register File only. In
1753*9732b024SMichael Rolnik  *  some parts the Flash Memory has been mapped to the data space and can be
1754*9732b024SMichael Rolnik  *  read using this command. The EEPROM has a separate address space.  The data
1755*9732b024SMichael Rolnik  *  location is pointed to by the Y (16 bits) Pointer Register in the Register
1756*9732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
1757*9732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
1758*9732b024SMichael Rolnik  *  RAMPY in register in the I/O area has to be changed.  The Y-pointer Register
1759*9732b024SMichael Rolnik  *  can either be left unchanged by the operation, or it can be post-incremented
1760*9732b024SMichael Rolnik  *  or predecremented.  These features are especially suited for accessing
1761*9732b024SMichael Rolnik  *  arrays, tables, and Stack Pointer usage of the Y-pointer Register. Note that
1762*9732b024SMichael Rolnik  *  only the low byte of the Y-pointer is updated in devices with no more than
1763*9732b024SMichael Rolnik  *  256 bytes data space. For such devices, the high byte of the pointer is not
1764*9732b024SMichael Rolnik  *  used by this instruction and can be used for other purposes. The RAMPY
1765*9732b024SMichael Rolnik  *  Register in the I/O area is updated in parts with more than 64KB data space
1766*9732b024SMichael Rolnik  *  or more than 64KB Program memory, and the increment/decrement/displacement
1767*9732b024SMichael Rolnik  *  is added to the entire 24-bit address on such devices.  Not all variants of
1768*9732b024SMichael Rolnik  *  this instruction is available in all devices. Refer to the device specific
1769*9732b024SMichael Rolnik  *  instruction set summary.  In the Reduced Core tinyAVR the LD instruction can
1770*9732b024SMichael Rolnik  *  be used to achieve the same operation as LPM since the program memory is
1771*9732b024SMichael Rolnik  *  mapped to the data memory space.
1772*9732b024SMichael Rolnik  */
1773*9732b024SMichael Rolnik static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a)
1774*9732b024SMichael Rolnik {
1775*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1776*9732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
1777*9732b024SMichael Rolnik 
1778*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
1779*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
1780*9732b024SMichael Rolnik 
1781*9732b024SMichael Rolnik     gen_set_yaddr(addr);
1782*9732b024SMichael Rolnik 
1783*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1784*9732b024SMichael Rolnik 
1785*9732b024SMichael Rolnik     return true;
1786*9732b024SMichael Rolnik }
1787*9732b024SMichael Rolnik 
1788*9732b024SMichael Rolnik static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a)
1789*9732b024SMichael Rolnik {
1790*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1791*9732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
1792*9732b024SMichael Rolnik 
1793*9732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
1794*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
1795*9732b024SMichael Rolnik     gen_set_yaddr(addr);
1796*9732b024SMichael Rolnik 
1797*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1798*9732b024SMichael Rolnik 
1799*9732b024SMichael Rolnik     return true;
1800*9732b024SMichael Rolnik }
1801*9732b024SMichael Rolnik 
1802*9732b024SMichael Rolnik static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a)
1803*9732b024SMichael Rolnik {
1804*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1805*9732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
1806*9732b024SMichael Rolnik 
1807*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
1808*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
1809*9732b024SMichael Rolnik 
1810*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1811*9732b024SMichael Rolnik 
1812*9732b024SMichael Rolnik     return true;
1813*9732b024SMichael Rolnik }
1814*9732b024SMichael Rolnik 
1815*9732b024SMichael Rolnik /*
1816*9732b024SMichael Rolnik  *  Loads one byte indirect with or without displacement from the data space
1817*9732b024SMichael Rolnik  *  to a register. For parts with SRAM, the data space consists of the Register
1818*9732b024SMichael Rolnik  *  File, I/O memory and internal SRAM (and external SRAM if applicable). For
1819*9732b024SMichael Rolnik  *  parts without SRAM, the data space consists of the Register File only. In
1820*9732b024SMichael Rolnik  *  some parts the Flash Memory has been mapped to the data space and can be
1821*9732b024SMichael Rolnik  *  read using this command. The EEPROM has a separate address space.  The data
1822*9732b024SMichael Rolnik  *  location is pointed to by the Z (16 bits) Pointer Register in the Register
1823*9732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
1824*9732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
1825*9732b024SMichael Rolnik  *  RAMPZ in register in the I/O area has to be changed.  The Z-pointer Register
1826*9732b024SMichael Rolnik  *  can either be left unchanged by the operation, or it can be post-incremented
1827*9732b024SMichael Rolnik  *  or predecremented.  These features are especially suited for Stack Pointer
1828*9732b024SMichael Rolnik  *  usage of the Z-pointer Register, however because the Z-pointer Register can
1829*9732b024SMichael Rolnik  *  be used for indirect subroutine calls, indirect jumps and table lookup, it
1830*9732b024SMichael Rolnik  *  is often more convenient to use the X or Y-pointer as a dedicated Stack
1831*9732b024SMichael Rolnik  *  Pointer. Note that only the low byte of the Z-pointer is updated in devices
1832*9732b024SMichael Rolnik  *  with no more than 256 bytes data space. For such devices, the high byte of
1833*9732b024SMichael Rolnik  *  the pointer is not used by this instruction and can be used for other
1834*9732b024SMichael Rolnik  *  purposes. The RAMPZ Register in the I/O area is updated in parts with more
1835*9732b024SMichael Rolnik  *  than 64KB data space or more than 64KB Program memory, and the
1836*9732b024SMichael Rolnik  *  increment/decrement/displacement is added to the entire 24-bit address on
1837*9732b024SMichael Rolnik  *  such devices.  Not all variants of this instruction is available in all
1838*9732b024SMichael Rolnik  *  devices. Refer to the device specific instruction set summary.  In the
1839*9732b024SMichael Rolnik  *  Reduced Core tinyAVR the LD instruction can be used to achieve the same
1840*9732b024SMichael Rolnik  *  operation as LPM since the program memory is mapped to the data memory
1841*9732b024SMichael Rolnik  *  space.  For using the Z-pointer for table lookup in Program memory see the
1842*9732b024SMichael Rolnik  *  LPM and ELPM instructions.
1843*9732b024SMichael Rolnik  */
1844*9732b024SMichael Rolnik static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a)
1845*9732b024SMichael Rolnik {
1846*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1847*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
1848*9732b024SMichael Rolnik 
1849*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
1850*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
1851*9732b024SMichael Rolnik 
1852*9732b024SMichael Rolnik     gen_set_zaddr(addr);
1853*9732b024SMichael Rolnik 
1854*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1855*9732b024SMichael Rolnik 
1856*9732b024SMichael Rolnik     return true;
1857*9732b024SMichael Rolnik }
1858*9732b024SMichael Rolnik 
1859*9732b024SMichael Rolnik static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a)
1860*9732b024SMichael Rolnik {
1861*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1862*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
1863*9732b024SMichael Rolnik 
1864*9732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
1865*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
1866*9732b024SMichael Rolnik 
1867*9732b024SMichael Rolnik     gen_set_zaddr(addr);
1868*9732b024SMichael Rolnik 
1869*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1870*9732b024SMichael Rolnik 
1871*9732b024SMichael Rolnik     return true;
1872*9732b024SMichael Rolnik }
1873*9732b024SMichael Rolnik 
1874*9732b024SMichael Rolnik static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a)
1875*9732b024SMichael Rolnik {
1876*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1877*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
1878*9732b024SMichael Rolnik 
1879*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
1880*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, addr);
1881*9732b024SMichael Rolnik 
1882*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1883*9732b024SMichael Rolnik 
1884*9732b024SMichael Rolnik     return true;
1885*9732b024SMichael Rolnik }
1886*9732b024SMichael Rolnik 
1887*9732b024SMichael Rolnik /*
1888*9732b024SMichael Rolnik  *  Stores one byte from a Register to the data space. For parts with SRAM,
1889*9732b024SMichael Rolnik  *  the data space consists of the Register File, I/O memory and internal SRAM
1890*9732b024SMichael Rolnik  *  (and external SRAM if applicable). For parts without SRAM, the data space
1891*9732b024SMichael Rolnik  *  consists of the Register File only. The EEPROM has a separate address space.
1892*9732b024SMichael Rolnik  *  A 16-bit address must be supplied. Memory access is limited to the current
1893*9732b024SMichael Rolnik  *  data segment of 64KB. The STS instruction uses the RAMPD Register to access
1894*9732b024SMichael Rolnik  *  memory above 64KB. To access another data segment in devices with more than
1895*9732b024SMichael Rolnik  *  64KB data space, the RAMPD in register in the I/O area has to be changed.
1896*9732b024SMichael Rolnik  *  This instruction is not available in all devices. Refer to the device
1897*9732b024SMichael Rolnik  *  specific instruction set summary.
1898*9732b024SMichael Rolnik  */
1899*9732b024SMichael Rolnik static bool trans_STS(DisasContext *ctx, arg_STS *a)
1900*9732b024SMichael Rolnik {
1901*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
1902*9732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
1903*9732b024SMichael Rolnik     TCGv H = cpu_rampD;
1904*9732b024SMichael Rolnik     a->imm = next_word(ctx);
1905*9732b024SMichael Rolnik 
1906*9732b024SMichael Rolnik     tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
1907*9732b024SMichael Rolnik     tcg_gen_shli_tl(addr, addr, 16);
1908*9732b024SMichael Rolnik     tcg_gen_ori_tl(addr, addr, a->imm);
1909*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
1910*9732b024SMichael Rolnik 
1911*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1912*9732b024SMichael Rolnik 
1913*9732b024SMichael Rolnik     return true;
1914*9732b024SMichael Rolnik }
1915*9732b024SMichael Rolnik 
1916*9732b024SMichael Rolnik /*
1917*9732b024SMichael Rolnik  * Stores one byte indirect from a register to data space. For parts with SRAM,
1918*9732b024SMichael Rolnik  * the data space consists of the Register File, I/O memory, and internal SRAM
1919*9732b024SMichael Rolnik  * (and external SRAM if applicable). For parts without SRAM, the data space
1920*9732b024SMichael Rolnik  * consists of the Register File only. The EEPROM has a separate address space.
1921*9732b024SMichael Rolnik  *
1922*9732b024SMichael Rolnik  * The data location is pointed to by the X (16 bits) Pointer Register in the
1923*9732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
1924*9732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
1925*9732b024SMichael Rolnik  * RAMPX in register in the I/O area has to be changed.
1926*9732b024SMichael Rolnik  *
1927*9732b024SMichael Rolnik  * The X-pointer Register can either be left unchanged by the operation, or it
1928*9732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
1929*9732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the
1930*9732b024SMichael Rolnik  * X-pointer Register. Note that only the low byte of the X-pointer is updated
1931*9732b024SMichael Rolnik  * in devices with no more than 256 bytes data space. For such devices, the high
1932*9732b024SMichael Rolnik  * byte of the pointer is not used by this instruction and can be used for other
1933*9732b024SMichael Rolnik  * purposes. The RAMPX Register in the I/O area is updated in parts with more
1934*9732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
1935*9732b024SMichael Rolnik  * decrement is added to the entire 24-bit address on such devices.
1936*9732b024SMichael Rolnik  */
1937*9732b024SMichael Rolnik static bool trans_STX1(DisasContext *ctx, arg_STX1 *a)
1938*9732b024SMichael Rolnik {
1939*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
1940*9732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
1941*9732b024SMichael Rolnik 
1942*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
1943*9732b024SMichael Rolnik 
1944*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1945*9732b024SMichael Rolnik 
1946*9732b024SMichael Rolnik     return true;
1947*9732b024SMichael Rolnik }
1948*9732b024SMichael Rolnik 
1949*9732b024SMichael Rolnik static bool trans_STX2(DisasContext *ctx, arg_STX2 *a)
1950*9732b024SMichael Rolnik {
1951*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
1952*9732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
1953*9732b024SMichael Rolnik 
1954*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
1955*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
1956*9732b024SMichael Rolnik     gen_set_xaddr(addr);
1957*9732b024SMichael Rolnik 
1958*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1959*9732b024SMichael Rolnik 
1960*9732b024SMichael Rolnik     return true;
1961*9732b024SMichael Rolnik }
1962*9732b024SMichael Rolnik 
1963*9732b024SMichael Rolnik static bool trans_STX3(DisasContext *ctx, arg_STX3 *a)
1964*9732b024SMichael Rolnik {
1965*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rr];
1966*9732b024SMichael Rolnik     TCGv addr = gen_get_xaddr();
1967*9732b024SMichael Rolnik 
1968*9732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
1969*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
1970*9732b024SMichael Rolnik     gen_set_xaddr(addr);
1971*9732b024SMichael Rolnik 
1972*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
1973*9732b024SMichael Rolnik 
1974*9732b024SMichael Rolnik     return true;
1975*9732b024SMichael Rolnik }
1976*9732b024SMichael Rolnik 
1977*9732b024SMichael Rolnik /*
1978*9732b024SMichael Rolnik  * Stores one byte indirect with or without displacement from a register to data
1979*9732b024SMichael Rolnik  * space. For parts with SRAM, the data space consists of the Register File, I/O
1980*9732b024SMichael Rolnik  * memory, and internal SRAM (and external SRAM if applicable). For parts
1981*9732b024SMichael Rolnik  * without SRAM, the data space consists of the Register File only. The EEPROM
1982*9732b024SMichael Rolnik  * has a separate address space.
1983*9732b024SMichael Rolnik  *
1984*9732b024SMichael Rolnik  * The data location is pointed to by the Y (16 bits) Pointer Register in the
1985*9732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
1986*9732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
1987*9732b024SMichael Rolnik  * RAMPY in register in the I/O area has to be changed.
1988*9732b024SMichael Rolnik  *
1989*9732b024SMichael Rolnik  * The Y-pointer Register can either be left unchanged by the operation, or it
1990*9732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
1991*9732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer
1992*9732b024SMichael Rolnik  * Register. Note that only the low byte of the Y-pointer is updated in devices
1993*9732b024SMichael Rolnik  * with no more than 256 bytes data space. For such devices, the high byte of
1994*9732b024SMichael Rolnik  * the pointer is not used by this instruction and can be used for other
1995*9732b024SMichael Rolnik  * purposes. The RAMPY Register in the I/O area is updated in parts with more
1996*9732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
1997*9732b024SMichael Rolnik  * decrement / displacement is added to the entire 24-bit address on such
1998*9732b024SMichael Rolnik  * devices.
1999*9732b024SMichael Rolnik  */
2000*9732b024SMichael Rolnik static bool trans_STY2(DisasContext *ctx, arg_STY2 *a)
2001*9732b024SMichael Rolnik {
2002*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2003*9732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
2004*9732b024SMichael Rolnik 
2005*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
2006*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
2007*9732b024SMichael Rolnik     gen_set_yaddr(addr);
2008*9732b024SMichael Rolnik 
2009*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2010*9732b024SMichael Rolnik 
2011*9732b024SMichael Rolnik     return true;
2012*9732b024SMichael Rolnik }
2013*9732b024SMichael Rolnik 
2014*9732b024SMichael Rolnik static bool trans_STY3(DisasContext *ctx, arg_STY3 *a)
2015*9732b024SMichael Rolnik {
2016*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2017*9732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
2018*9732b024SMichael Rolnik 
2019*9732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
2020*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
2021*9732b024SMichael Rolnik     gen_set_yaddr(addr);
2022*9732b024SMichael Rolnik 
2023*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2024*9732b024SMichael Rolnik 
2025*9732b024SMichael Rolnik     return true;
2026*9732b024SMichael Rolnik }
2027*9732b024SMichael Rolnik 
2028*9732b024SMichael Rolnik static bool trans_STDY(DisasContext *ctx, arg_STDY *a)
2029*9732b024SMichael Rolnik {
2030*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2031*9732b024SMichael Rolnik     TCGv addr = gen_get_yaddr();
2032*9732b024SMichael Rolnik 
2033*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
2034*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
2035*9732b024SMichael Rolnik 
2036*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2037*9732b024SMichael Rolnik 
2038*9732b024SMichael Rolnik     return true;
2039*9732b024SMichael Rolnik }
2040*9732b024SMichael Rolnik 
2041*9732b024SMichael Rolnik /*
2042*9732b024SMichael Rolnik  * Stores one byte indirect with or without displacement from a register to data
2043*9732b024SMichael Rolnik  * space. For parts with SRAM, the data space consists of the Register File, I/O
2044*9732b024SMichael Rolnik  * memory, and internal SRAM (and external SRAM if applicable). For parts
2045*9732b024SMichael Rolnik  * without SRAM, the data space consists of the Register File only. The EEPROM
2046*9732b024SMichael Rolnik  * has a separate address space.
2047*9732b024SMichael Rolnik  *
2048*9732b024SMichael Rolnik  * The data location is pointed to by the Y (16 bits) Pointer Register in the
2049*9732b024SMichael Rolnik  * Register File. Memory access is limited to the current data segment of 64KB.
2050*9732b024SMichael Rolnik  * To access another data segment in devices with more than 64KB data space, the
2051*9732b024SMichael Rolnik  * RAMPY in register in the I/O area has to be changed.
2052*9732b024SMichael Rolnik  *
2053*9732b024SMichael Rolnik  * The Y-pointer Register can either be left unchanged by the operation, or it
2054*9732b024SMichael Rolnik  * can be post-incremented or pre-decremented. These features are especially
2055*9732b024SMichael Rolnik  * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer
2056*9732b024SMichael Rolnik  * Register. Note that only the low byte of the Y-pointer is updated in devices
2057*9732b024SMichael Rolnik  * with no more than 256 bytes data space. For such devices, the high byte of
2058*9732b024SMichael Rolnik  * the pointer is not used by this instruction and can be used for other
2059*9732b024SMichael Rolnik  * purposes. The RAMPY Register in the I/O area is updated in parts with more
2060*9732b024SMichael Rolnik  * than 64KB data space or more than 64KB Program memory, and the increment /
2061*9732b024SMichael Rolnik  * decrement / displacement is added to the entire 24-bit address on such
2062*9732b024SMichael Rolnik  * devices.
2063*9732b024SMichael Rolnik  */
2064*9732b024SMichael Rolnik static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a)
2065*9732b024SMichael Rolnik {
2066*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2067*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
2068*9732b024SMichael Rolnik 
2069*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
2070*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
2071*9732b024SMichael Rolnik 
2072*9732b024SMichael Rolnik     gen_set_zaddr(addr);
2073*9732b024SMichael Rolnik 
2074*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2075*9732b024SMichael Rolnik 
2076*9732b024SMichael Rolnik     return true;
2077*9732b024SMichael Rolnik }
2078*9732b024SMichael Rolnik 
2079*9732b024SMichael Rolnik static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a)
2080*9732b024SMichael Rolnik {
2081*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2082*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
2083*9732b024SMichael Rolnik 
2084*9732b024SMichael Rolnik     tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
2085*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
2086*9732b024SMichael Rolnik 
2087*9732b024SMichael Rolnik     gen_set_zaddr(addr);
2088*9732b024SMichael Rolnik 
2089*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2090*9732b024SMichael Rolnik 
2091*9732b024SMichael Rolnik     return true;
2092*9732b024SMichael Rolnik }
2093*9732b024SMichael Rolnik 
2094*9732b024SMichael Rolnik static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a)
2095*9732b024SMichael Rolnik {
2096*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2097*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
2098*9732b024SMichael Rolnik 
2099*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */
2100*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
2101*9732b024SMichael Rolnik 
2102*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2103*9732b024SMichael Rolnik 
2104*9732b024SMichael Rolnik     return true;
2105*9732b024SMichael Rolnik }
2106*9732b024SMichael Rolnik 
2107*9732b024SMichael Rolnik /*
2108*9732b024SMichael Rolnik  *  Loads one byte pointed to by the Z-register into the destination
2109*9732b024SMichael Rolnik  *  register Rd. This instruction features a 100% space effective constant
2110*9732b024SMichael Rolnik  *  initialization or constant data fetch. The Program memory is organized in
2111*9732b024SMichael Rolnik  *  16-bit words while the Z-pointer is a byte address. Thus, the least
2112*9732b024SMichael Rolnik  *  significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high
2113*9732b024SMichael Rolnik  *  byte (ZLSB = 1). This instruction can address the first 64KB (32K words) of
2114*9732b024SMichael Rolnik  *  Program memory. The Zpointer Register can either be left unchanged by the
2115*9732b024SMichael Rolnik  *  operation, or it can be incremented. The incrementation does not apply to
2116*9732b024SMichael Rolnik  *  the RAMPZ Register.
2117*9732b024SMichael Rolnik  *
2118*9732b024SMichael Rolnik  *  Devices with Self-Programming capability can use the LPM instruction to read
2119*9732b024SMichael Rolnik  *  the Fuse and Lock bit values.
2120*9732b024SMichael Rolnik  */
2121*9732b024SMichael Rolnik static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a)
2122*9732b024SMichael Rolnik {
2123*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) {
2124*9732b024SMichael Rolnik         return true;
2125*9732b024SMichael Rolnik     }
2126*9732b024SMichael Rolnik 
2127*9732b024SMichael Rolnik     TCGv Rd = cpu_r[0];
2128*9732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
2129*9732b024SMichael Rolnik     TCGv H = cpu_r[31];
2130*9732b024SMichael Rolnik     TCGv L = cpu_r[30];
2131*9732b024SMichael Rolnik 
2132*9732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
2133*9732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
2134*9732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
2135*9732b024SMichael Rolnik 
2136*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2137*9732b024SMichael Rolnik 
2138*9732b024SMichael Rolnik     return true;
2139*9732b024SMichael Rolnik }
2140*9732b024SMichael Rolnik 
2141*9732b024SMichael Rolnik static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a)
2142*9732b024SMichael Rolnik {
2143*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) {
2144*9732b024SMichael Rolnik         return true;
2145*9732b024SMichael Rolnik     }
2146*9732b024SMichael Rolnik 
2147*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2148*9732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
2149*9732b024SMichael Rolnik     TCGv H = cpu_r[31];
2150*9732b024SMichael Rolnik     TCGv L = cpu_r[30];
2151*9732b024SMichael Rolnik 
2152*9732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
2153*9732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
2154*9732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
2155*9732b024SMichael Rolnik 
2156*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2157*9732b024SMichael Rolnik 
2158*9732b024SMichael Rolnik     return true;
2159*9732b024SMichael Rolnik }
2160*9732b024SMichael Rolnik 
2161*9732b024SMichael Rolnik static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a)
2162*9732b024SMichael Rolnik {
2163*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_LPMX)) {
2164*9732b024SMichael Rolnik         return true;
2165*9732b024SMichael Rolnik     }
2166*9732b024SMichael Rolnik 
2167*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2168*9732b024SMichael Rolnik     TCGv addr = tcg_temp_new_i32();
2169*9732b024SMichael Rolnik     TCGv H = cpu_r[31];
2170*9732b024SMichael Rolnik     TCGv L = cpu_r[30];
2171*9732b024SMichael Rolnik 
2172*9732b024SMichael Rolnik     tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
2173*9732b024SMichael Rolnik     tcg_gen_or_tl(addr, addr, L);
2174*9732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
2175*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
2176*9732b024SMichael Rolnik     tcg_gen_andi_tl(L, addr, 0xff);
2177*9732b024SMichael Rolnik     tcg_gen_shri_tl(addr, addr, 8);
2178*9732b024SMichael Rolnik     tcg_gen_andi_tl(H, addr, 0xff);
2179*9732b024SMichael Rolnik 
2180*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2181*9732b024SMichael Rolnik 
2182*9732b024SMichael Rolnik     return true;
2183*9732b024SMichael Rolnik }
2184*9732b024SMichael Rolnik 
2185*9732b024SMichael Rolnik /*
2186*9732b024SMichael Rolnik  *  Loads one byte pointed to by the Z-register and the RAMPZ Register in
2187*9732b024SMichael Rolnik  *  the I/O space, and places this byte in the destination register Rd. This
2188*9732b024SMichael Rolnik  *  instruction features a 100% space effective constant initialization or
2189*9732b024SMichael Rolnik  *  constant data fetch. The Program memory is organized in 16-bit words while
2190*9732b024SMichael Rolnik  *  the Z-pointer is a byte address. Thus, the least significant bit of the
2191*9732b024SMichael Rolnik  *  Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This
2192*9732b024SMichael Rolnik  *  instruction can address the entire Program memory space. The Z-pointer
2193*9732b024SMichael Rolnik  *  Register can either be left unchanged by the operation, or it can be
2194*9732b024SMichael Rolnik  *  incremented. The incrementation applies to the entire 24-bit concatenation
2195*9732b024SMichael Rolnik  *  of the RAMPZ and Z-pointer Registers.
2196*9732b024SMichael Rolnik  *
2197*9732b024SMichael Rolnik  *  Devices with Self-Programming capability can use the ELPM instruction to
2198*9732b024SMichael Rolnik  *  read the Fuse and Lock bit value.
2199*9732b024SMichael Rolnik  */
2200*9732b024SMichael Rolnik static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a)
2201*9732b024SMichael Rolnik {
2202*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) {
2203*9732b024SMichael Rolnik         return true;
2204*9732b024SMichael Rolnik     }
2205*9732b024SMichael Rolnik 
2206*9732b024SMichael Rolnik     TCGv Rd = cpu_r[0];
2207*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
2208*9732b024SMichael Rolnik 
2209*9732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
2210*9732b024SMichael Rolnik 
2211*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2212*9732b024SMichael Rolnik 
2213*9732b024SMichael Rolnik     return true;
2214*9732b024SMichael Rolnik }
2215*9732b024SMichael Rolnik 
2216*9732b024SMichael Rolnik static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a)
2217*9732b024SMichael Rolnik {
2218*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) {
2219*9732b024SMichael Rolnik         return true;
2220*9732b024SMichael Rolnik     }
2221*9732b024SMichael Rolnik 
2222*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2223*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
2224*9732b024SMichael Rolnik 
2225*9732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
2226*9732b024SMichael Rolnik 
2227*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2228*9732b024SMichael Rolnik 
2229*9732b024SMichael Rolnik     return true;
2230*9732b024SMichael Rolnik }
2231*9732b024SMichael Rolnik 
2232*9732b024SMichael Rolnik static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a)
2233*9732b024SMichael Rolnik {
2234*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_ELPMX)) {
2235*9732b024SMichael Rolnik         return true;
2236*9732b024SMichael Rolnik     }
2237*9732b024SMichael Rolnik 
2238*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2239*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
2240*9732b024SMichael Rolnik 
2241*9732b024SMichael Rolnik     tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */
2242*9732b024SMichael Rolnik     tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
2243*9732b024SMichael Rolnik     gen_set_zaddr(addr);
2244*9732b024SMichael Rolnik 
2245*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2246*9732b024SMichael Rolnik 
2247*9732b024SMichael Rolnik     return true;
2248*9732b024SMichael Rolnik }
2249*9732b024SMichael Rolnik 
2250*9732b024SMichael Rolnik /*
2251*9732b024SMichael Rolnik  *  SPM can be used to erase a page in the Program memory, to write a page
2252*9732b024SMichael Rolnik  *  in the Program memory (that is already erased), and to set Boot Loader Lock
2253*9732b024SMichael Rolnik  *  bits. In some devices, the Program memory can be written one word at a time,
2254*9732b024SMichael Rolnik  *  in other devices an entire page can be programmed simultaneously after first
2255*9732b024SMichael Rolnik  *  filling a temporary page buffer. In all cases, the Program memory must be
2256*9732b024SMichael Rolnik  *  erased one page at a time. When erasing the Program memory, the RAMPZ and
2257*9732b024SMichael Rolnik  *  Z-register are used as page address. When writing the Program memory, the
2258*9732b024SMichael Rolnik  *  RAMPZ and Z-register are used as page or word address, and the R1:R0
2259*9732b024SMichael Rolnik  *  register pair is used as data(1). When setting the Boot Loader Lock bits,
2260*9732b024SMichael Rolnik  *  the R1:R0 register pair is used as data. Refer to the device documentation
2261*9732b024SMichael Rolnik  *  for detailed description of SPM usage. This instruction can address the
2262*9732b024SMichael Rolnik  *  entire Program memory.
2263*9732b024SMichael Rolnik  *
2264*9732b024SMichael Rolnik  *  The SPM instruction is not available in all devices. Refer to the device
2265*9732b024SMichael Rolnik  *  specific instruction set summary.
2266*9732b024SMichael Rolnik  *
2267*9732b024SMichael Rolnik  *  Note: 1. R1 determines the instruction high byte, and R0 determines the
2268*9732b024SMichael Rolnik  *  instruction low byte.
2269*9732b024SMichael Rolnik  */
2270*9732b024SMichael Rolnik static bool trans_SPM(DisasContext *ctx, arg_SPM *a)
2271*9732b024SMichael Rolnik {
2272*9732b024SMichael Rolnik     /* TODO */
2273*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_SPM)) {
2274*9732b024SMichael Rolnik         return true;
2275*9732b024SMichael Rolnik     }
2276*9732b024SMichael Rolnik 
2277*9732b024SMichael Rolnik     return true;
2278*9732b024SMichael Rolnik }
2279*9732b024SMichael Rolnik 
2280*9732b024SMichael Rolnik static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a)
2281*9732b024SMichael Rolnik {
2282*9732b024SMichael Rolnik     /* TODO */
2283*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_SPMX)) {
2284*9732b024SMichael Rolnik         return true;
2285*9732b024SMichael Rolnik     }
2286*9732b024SMichael Rolnik 
2287*9732b024SMichael Rolnik     return true;
2288*9732b024SMichael Rolnik }
2289*9732b024SMichael Rolnik 
2290*9732b024SMichael Rolnik /*
2291*9732b024SMichael Rolnik  *  Loads data from the I/O Space (Ports, Timers, Configuration Registers,
2292*9732b024SMichael Rolnik  *  etc.) into register Rd in the Register File.
2293*9732b024SMichael Rolnik  */
2294*9732b024SMichael Rolnik static bool trans_IN(DisasContext *ctx, arg_IN *a)
2295*9732b024SMichael Rolnik {
2296*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2297*9732b024SMichael Rolnik     TCGv port = tcg_const_i32(a->imm);
2298*9732b024SMichael Rolnik 
2299*9732b024SMichael Rolnik     gen_helper_inb(Rd, cpu_env, port);
2300*9732b024SMichael Rolnik 
2301*9732b024SMichael Rolnik     tcg_temp_free_i32(port);
2302*9732b024SMichael Rolnik 
2303*9732b024SMichael Rolnik     return true;
2304*9732b024SMichael Rolnik }
2305*9732b024SMichael Rolnik 
2306*9732b024SMichael Rolnik /*
2307*9732b024SMichael Rolnik  *  Stores data from register Rr in the Register File to I/O Space (Ports,
2308*9732b024SMichael Rolnik  *  Timers, Configuration Registers, etc.).
2309*9732b024SMichael Rolnik  */
2310*9732b024SMichael Rolnik static bool trans_OUT(DisasContext *ctx, arg_OUT *a)
2311*9732b024SMichael Rolnik {
2312*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2313*9732b024SMichael Rolnik     TCGv port = tcg_const_i32(a->imm);
2314*9732b024SMichael Rolnik 
2315*9732b024SMichael Rolnik     gen_helper_outb(cpu_env, port, Rd);
2316*9732b024SMichael Rolnik 
2317*9732b024SMichael Rolnik     tcg_temp_free_i32(port);
2318*9732b024SMichael Rolnik 
2319*9732b024SMichael Rolnik     return true;
2320*9732b024SMichael Rolnik }
2321*9732b024SMichael Rolnik 
2322*9732b024SMichael Rolnik /*
2323*9732b024SMichael Rolnik  *  This instruction stores the contents of register Rr on the STACK. The
2324*9732b024SMichael Rolnik  *  Stack Pointer is post-decremented by 1 after the PUSH.  This instruction is
2325*9732b024SMichael Rolnik  *  not available in all devices. Refer to the device specific instruction set
2326*9732b024SMichael Rolnik  *  summary.
2327*9732b024SMichael Rolnik  */
2328*9732b024SMichael Rolnik static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a)
2329*9732b024SMichael Rolnik {
2330*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2331*9732b024SMichael Rolnik 
2332*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, cpu_sp);
2333*9732b024SMichael Rolnik     tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
2334*9732b024SMichael Rolnik 
2335*9732b024SMichael Rolnik     return true;
2336*9732b024SMichael Rolnik }
2337*9732b024SMichael Rolnik 
2338*9732b024SMichael Rolnik /*
2339*9732b024SMichael Rolnik  *  This instruction loads register Rd with a byte from the STACK. The Stack
2340*9732b024SMichael Rolnik  *  Pointer is pre-incremented by 1 before the POP.  This instruction is not
2341*9732b024SMichael Rolnik  *  available in all devices. Refer to the device specific instruction set
2342*9732b024SMichael Rolnik  *  summary.
2343*9732b024SMichael Rolnik  */
2344*9732b024SMichael Rolnik static bool trans_POP(DisasContext *ctx, arg_POP *a)
2345*9732b024SMichael Rolnik {
2346*9732b024SMichael Rolnik     /*
2347*9732b024SMichael Rolnik      * Using a temp to work around some strange behaviour:
2348*9732b024SMichael Rolnik      * tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
2349*9732b024SMichael Rolnik      * gen_data_load(ctx, Rd, cpu_sp);
2350*9732b024SMichael Rolnik      * seems to cause the add to happen twice.
2351*9732b024SMichael Rolnik      * This doesn't happen if either the add or the load is removed.
2352*9732b024SMichael Rolnik      */
2353*9732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
2354*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2355*9732b024SMichael Rolnik 
2356*9732b024SMichael Rolnik     tcg_gen_addi_tl(t1, cpu_sp, 1);
2357*9732b024SMichael Rolnik     gen_data_load(ctx, Rd, t1);
2358*9732b024SMichael Rolnik     tcg_gen_mov_tl(cpu_sp, t1);
2359*9732b024SMichael Rolnik 
2360*9732b024SMichael Rolnik     return true;
2361*9732b024SMichael Rolnik }
2362*9732b024SMichael Rolnik 
2363*9732b024SMichael Rolnik /*
2364*9732b024SMichael Rolnik  *  Exchanges one byte indirect between register and data space.  The data
2365*9732b024SMichael Rolnik  *  location is pointed to by the Z (16 bits) Pointer Register in the Register
2366*9732b024SMichael Rolnik  *  File. Memory access is limited to the current data segment of 64KB. To
2367*9732b024SMichael Rolnik  *  access another data segment in devices with more than 64KB data space, the
2368*9732b024SMichael Rolnik  *  RAMPZ in register in the I/O area has to be changed.
2369*9732b024SMichael Rolnik  *
2370*9732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
2371*9732b024SMichael Rolnik  *  is especially suited for writing/reading status bits stored in SRAM.
2372*9732b024SMichael Rolnik  */
2373*9732b024SMichael Rolnik static bool trans_XCH(DisasContext *ctx, arg_XCH *a)
2374*9732b024SMichael Rolnik {
2375*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
2376*9732b024SMichael Rolnik         return true;
2377*9732b024SMichael Rolnik     }
2378*9732b024SMichael Rolnik 
2379*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2380*9732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
2381*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
2382*9732b024SMichael Rolnik 
2383*9732b024SMichael Rolnik     gen_data_load(ctx, t0, addr);
2384*9732b024SMichael Rolnik     gen_data_store(ctx, Rd, addr);
2385*9732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, t0);
2386*9732b024SMichael Rolnik 
2387*9732b024SMichael Rolnik     tcg_temp_free_i32(t0);
2388*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2389*9732b024SMichael Rolnik 
2390*9732b024SMichael Rolnik     return true;
2391*9732b024SMichael Rolnik }
2392*9732b024SMichael Rolnik 
2393*9732b024SMichael Rolnik /*
2394*9732b024SMichael Rolnik  *  Load one byte indirect from data space to register and set bits in data
2395*9732b024SMichael Rolnik  *  space specified by the register. The instruction can only be used towards
2396*9732b024SMichael Rolnik  *  internal SRAM.  The data location is pointed to by the Z (16 bits) Pointer
2397*9732b024SMichael Rolnik  *  Register in the Register File. Memory access is limited to the current data
2398*9732b024SMichael Rolnik  *  segment of 64KB. To access another data segment in devices with more than
2399*9732b024SMichael Rolnik  *  64KB data space, the RAMPZ in register in the I/O area has to be changed.
2400*9732b024SMichael Rolnik  *
2401*9732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
2402*9732b024SMichael Rolnik  *  is especially suited for setting status bits stored in SRAM.
2403*9732b024SMichael Rolnik  */
2404*9732b024SMichael Rolnik static bool trans_LAS(DisasContext *ctx, arg_LAS *a)
2405*9732b024SMichael Rolnik {
2406*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
2407*9732b024SMichael Rolnik         return true;
2408*9732b024SMichael Rolnik     }
2409*9732b024SMichael Rolnik 
2410*9732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rd];
2411*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
2412*9732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
2413*9732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
2414*9732b024SMichael Rolnik 
2415*9732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
2416*9732b024SMichael Rolnik     tcg_gen_or_tl(t1, t0, Rr);
2417*9732b024SMichael Rolnik     tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
2418*9732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
2419*9732b024SMichael Rolnik 
2420*9732b024SMichael Rolnik     tcg_temp_free_i32(t1);
2421*9732b024SMichael Rolnik     tcg_temp_free_i32(t0);
2422*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2423*9732b024SMichael Rolnik 
2424*9732b024SMichael Rolnik     return true;
2425*9732b024SMichael Rolnik }
2426*9732b024SMichael Rolnik 
2427*9732b024SMichael Rolnik /*
2428*9732b024SMichael Rolnik  *  Load one byte indirect from data space to register and stores and clear
2429*9732b024SMichael Rolnik  *  the bits in data space specified by the register. The instruction can
2430*9732b024SMichael Rolnik  *  only be used towards internal SRAM.  The data location is pointed to by
2431*9732b024SMichael Rolnik  *  the Z (16 bits) Pointer Register in the Register File. Memory access is
2432*9732b024SMichael Rolnik  *  limited to the current data segment of 64KB. To access another data
2433*9732b024SMichael Rolnik  *  segment in devices with more than 64KB data space, the RAMPZ in register
2434*9732b024SMichael Rolnik  *  in the I/O area has to be changed.
2435*9732b024SMichael Rolnik  *
2436*9732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
2437*9732b024SMichael Rolnik  *  is especially suited for clearing status bits stored in SRAM.
2438*9732b024SMichael Rolnik  */
2439*9732b024SMichael Rolnik static bool trans_LAC(DisasContext *ctx, arg_LAC *a)
2440*9732b024SMichael Rolnik {
2441*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
2442*9732b024SMichael Rolnik         return true;
2443*9732b024SMichael Rolnik     }
2444*9732b024SMichael Rolnik 
2445*9732b024SMichael Rolnik     TCGv Rr = cpu_r[a->rd];
2446*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
2447*9732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
2448*9732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
2449*9732b024SMichael Rolnik 
2450*9732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
2451*9732b024SMichael Rolnik     tcg_gen_andc_tl(t1, t0, Rr); /* t1 = t0 & (0xff - Rr) = t0 & ~Rr */
2452*9732b024SMichael Rolnik     tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
2453*9732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
2454*9732b024SMichael Rolnik 
2455*9732b024SMichael Rolnik     tcg_temp_free_i32(t1);
2456*9732b024SMichael Rolnik     tcg_temp_free_i32(t0);
2457*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2458*9732b024SMichael Rolnik 
2459*9732b024SMichael Rolnik     return true;
2460*9732b024SMichael Rolnik }
2461*9732b024SMichael Rolnik 
2462*9732b024SMichael Rolnik 
2463*9732b024SMichael Rolnik /*
2464*9732b024SMichael Rolnik  *  Load one byte indirect from data space to register and toggles bits in
2465*9732b024SMichael Rolnik  *  the data space specified by the register.  The instruction can only be used
2466*9732b024SMichael Rolnik  *  towards SRAM.  The data location is pointed to by the Z (16 bits) Pointer
2467*9732b024SMichael Rolnik  *  Register in the Register File. Memory access is limited to the current data
2468*9732b024SMichael Rolnik  *  segment of 64KB. To access another data segment in devices with more than
2469*9732b024SMichael Rolnik  *  64KB data space, the RAMPZ in register in the I/O area has to be changed.
2470*9732b024SMichael Rolnik  *
2471*9732b024SMichael Rolnik  *  The Z-pointer Register is left unchanged by the operation. This instruction
2472*9732b024SMichael Rolnik  *  is especially suited for changing status bits stored in SRAM.
2473*9732b024SMichael Rolnik  */
2474*9732b024SMichael Rolnik static bool trans_LAT(DisasContext *ctx, arg_LAT *a)
2475*9732b024SMichael Rolnik {
2476*9732b024SMichael Rolnik     if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) {
2477*9732b024SMichael Rolnik         return true;
2478*9732b024SMichael Rolnik     }
2479*9732b024SMichael Rolnik 
2480*9732b024SMichael Rolnik     TCGv Rd = cpu_r[a->rd];
2481*9732b024SMichael Rolnik     TCGv addr = gen_get_zaddr();
2482*9732b024SMichael Rolnik     TCGv t0 = tcg_temp_new_i32();
2483*9732b024SMichael Rolnik     TCGv t1 = tcg_temp_new_i32();
2484*9732b024SMichael Rolnik 
2485*9732b024SMichael Rolnik     gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */
2486*9732b024SMichael Rolnik     tcg_gen_xor_tl(t1, t0, Rd);
2487*9732b024SMichael Rolnik     tcg_gen_mov_tl(Rd, t0); /* Rd = t0 */
2488*9732b024SMichael Rolnik     gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */
2489*9732b024SMichael Rolnik 
2490*9732b024SMichael Rolnik     tcg_temp_free_i32(t1);
2491*9732b024SMichael Rolnik     tcg_temp_free_i32(t0);
2492*9732b024SMichael Rolnik     tcg_temp_free_i32(addr);
2493*9732b024SMichael Rolnik 
2494*9732b024SMichael Rolnik     return true;
2495*9732b024SMichael Rolnik }
2496