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