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