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