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 { 8393d4d5e4SRichard Henderson DisasContextBase base; 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 94e03feba0SMichael Rolnik /* 95e03feba0SMichael Rolnik * some AVR instructions can make the following instruction to be skipped 96e03feba0SMichael Rolnik * Let's name those instructions 97e03feba0SMichael Rolnik * A - instruction that can skip the next one 98e03feba0SMichael Rolnik * B - instruction that can be skipped. this depends on execution of A 99e03feba0SMichael Rolnik * there are two scenarios 100e03feba0SMichael Rolnik * 1. A and B belong to the same translation block 101e03feba0SMichael Rolnik * 2. A is the last instruction in the translation block and B is the last 102e03feba0SMichael Rolnik * 103e03feba0SMichael Rolnik * following variables are used to simplify the skipping logic, they are 104e03feba0SMichael Rolnik * used in the following manner (sketch) 105e03feba0SMichael Rolnik * 106e03feba0SMichael Rolnik * TCGLabel *skip_label = NULL; 107bcef6d76SRichard Henderson * if (ctx->skip_cond != TCG_COND_NEVER) { 108e03feba0SMichael Rolnik * skip_label = gen_new_label(); 109e03feba0SMichael Rolnik * tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label); 110e03feba0SMichael Rolnik * } 111e03feba0SMichael Rolnik * 112e03feba0SMichael Rolnik * if (free_skip_var0) { 113e03feba0SMichael Rolnik * tcg_temp_free(skip_var0); 114e03feba0SMichael Rolnik * free_skip_var0 = false; 115e03feba0SMichael Rolnik * } 116e03feba0SMichael Rolnik * 117bcef6d76SRichard Henderson * translate(ctx); 118e03feba0SMichael Rolnik * 119e03feba0SMichael Rolnik * if (skip_label) { 120e03feba0SMichael Rolnik * gen_set_label(skip_label); 121e03feba0SMichael Rolnik * } 122e03feba0SMichael Rolnik */ 123e03feba0SMichael Rolnik TCGv skip_var0; 124e03feba0SMichael Rolnik TCGv skip_var1; 125e03feba0SMichael Rolnik TCGCond skip_cond; 126e03feba0SMichael Rolnik bool free_skip_var0; 127e03feba0SMichael Rolnik }; 128e03feba0SMichael Rolnik 129a107fdb0SMichael Rolnik void avr_cpu_tcg_init(void) 130a107fdb0SMichael Rolnik { 131a107fdb0SMichael Rolnik int i; 132a107fdb0SMichael Rolnik 133a107fdb0SMichael Rolnik #define AVR_REG_OFFS(x) offsetof(CPUAVRState, x) 134a107fdb0SMichael Rolnik cpu_pc = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(pc_w), "pc"); 135a107fdb0SMichael Rolnik cpu_Cf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregC), "Cf"); 136a107fdb0SMichael Rolnik cpu_Zf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregZ), "Zf"); 137a107fdb0SMichael Rolnik cpu_Nf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregN), "Nf"); 138a107fdb0SMichael Rolnik cpu_Vf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregV), "Vf"); 139a107fdb0SMichael Rolnik cpu_Sf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregS), "Sf"); 140a107fdb0SMichael Rolnik cpu_Hf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregH), "Hf"); 141a107fdb0SMichael Rolnik cpu_Tf = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregT), "Tf"); 142a107fdb0SMichael Rolnik cpu_If = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sregI), "If"); 143a107fdb0SMichael Rolnik cpu_rampD = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampD), "rampD"); 144a107fdb0SMichael Rolnik cpu_rampX = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampX), "rampX"); 145a107fdb0SMichael Rolnik cpu_rampY = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampY), "rampY"); 146a107fdb0SMichael Rolnik cpu_rampZ = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(rampZ), "rampZ"); 147a107fdb0SMichael Rolnik cpu_eind = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(eind), "eind"); 148a107fdb0SMichael Rolnik cpu_sp = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(sp), "sp"); 149a107fdb0SMichael Rolnik cpu_skip = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(skip), "skip"); 150a107fdb0SMichael Rolnik 151a107fdb0SMichael Rolnik for (i = 0; i < NUMBER_OF_CPU_REGISTERS; i++) { 152a107fdb0SMichael Rolnik cpu_r[i] = tcg_global_mem_new_i32(cpu_env, AVR_REG_OFFS(r[i]), 153a107fdb0SMichael Rolnik reg_names[i]); 154a107fdb0SMichael Rolnik } 155a107fdb0SMichael Rolnik #undef AVR_REG_OFFS 156a107fdb0SMichael Rolnik } 157a107fdb0SMichael Rolnik 158865f3bb9SMichael Rolnik static int to_regs_16_31_by_one(DisasContext *ctx, int indx) 159865f3bb9SMichael Rolnik { 160865f3bb9SMichael Rolnik return 16 + (indx % 16); 161865f3bb9SMichael Rolnik } 162865f3bb9SMichael Rolnik 163865f3bb9SMichael Rolnik static int to_regs_16_23_by_one(DisasContext *ctx, int indx) 164865f3bb9SMichael Rolnik { 165865f3bb9SMichael Rolnik return 16 + (indx % 8); 166865f3bb9SMichael Rolnik } 167865f3bb9SMichael Rolnik 168865f3bb9SMichael Rolnik static int to_regs_24_30_by_two(DisasContext *ctx, int indx) 169865f3bb9SMichael Rolnik { 170865f3bb9SMichael Rolnik return 24 + (indx % 4) * 2; 171865f3bb9SMichael Rolnik } 172865f3bb9SMichael Rolnik 1739732b024SMichael Rolnik static int to_regs_00_30_by_two(DisasContext *ctx, int indx) 1749732b024SMichael Rolnik { 1759732b024SMichael Rolnik return (indx % 16) * 2; 1769732b024SMichael Rolnik } 177865f3bb9SMichael Rolnik 1789d316c75SMichael Rolnik static uint16_t next_word(DisasContext *ctx) 1799d316c75SMichael Rolnik { 1809d316c75SMichael Rolnik return cpu_lduw_code(ctx->env, ctx->npc++ * 2); 1819d316c75SMichael Rolnik } 1829d316c75SMichael Rolnik 1839d316c75SMichael Rolnik static int append_16(DisasContext *ctx, int x) 1849d316c75SMichael Rolnik { 1859d316c75SMichael Rolnik return x << 16 | next_word(ctx); 1869d316c75SMichael Rolnik } 1879d316c75SMichael Rolnik 188e03feba0SMichael Rolnik static bool avr_have_feature(DisasContext *ctx, int feature) 189e03feba0SMichael Rolnik { 190e03feba0SMichael Rolnik if (!avr_feature(ctx->env, feature)) { 191e03feba0SMichael Rolnik gen_helper_unsupported(cpu_env); 19293d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 193e03feba0SMichael Rolnik return false; 194e03feba0SMichael Rolnik } 195e03feba0SMichael Rolnik return true; 196e03feba0SMichael Rolnik } 197e03feba0SMichael Rolnik 198e03feba0SMichael Rolnik static bool decode_insn(DisasContext *ctx, uint16_t insn); 199abff1abfSPaolo Bonzini #include "decode-insn.c.inc" 200865f3bb9SMichael Rolnik 201865f3bb9SMichael Rolnik /* 202865f3bb9SMichael Rolnik * Arithmetic Instructions 203865f3bb9SMichael Rolnik */ 204865f3bb9SMichael Rolnik 205865f3bb9SMichael Rolnik /* 206865f3bb9SMichael Rolnik * Utility functions for updating status registers: 207865f3bb9SMichael Rolnik * 208865f3bb9SMichael Rolnik * - gen_add_CHf() 209865f3bb9SMichael Rolnik * - gen_add_Vf() 210865f3bb9SMichael Rolnik * - gen_sub_CHf() 211865f3bb9SMichael Rolnik * - gen_sub_Vf() 212865f3bb9SMichael Rolnik * - gen_NSf() 213865f3bb9SMichael Rolnik * - gen_ZNSf() 214865f3bb9SMichael Rolnik * 215865f3bb9SMichael Rolnik */ 216865f3bb9SMichael Rolnik 217865f3bb9SMichael Rolnik static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) 218865f3bb9SMichael Rolnik { 219865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 220865f3bb9SMichael Rolnik TCGv t2 = tcg_temp_new_i32(); 221865f3bb9SMichael Rolnik TCGv t3 = tcg_temp_new_i32(); 222865f3bb9SMichael Rolnik 223865f3bb9SMichael Rolnik tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */ 224865f3bb9SMichael Rolnik tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */ 225865f3bb9SMichael Rolnik tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */ 226865f3bb9SMichael Rolnik tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */ 227865f3bb9SMichael Rolnik tcg_gen_or_tl(t1, t1, t3); 228865f3bb9SMichael Rolnik 229865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */ 230865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */ 231865f3bb9SMichael Rolnik tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); 232865f3bb9SMichael Rolnik 233865f3bb9SMichael Rolnik tcg_temp_free_i32(t3); 234865f3bb9SMichael Rolnik tcg_temp_free_i32(t2); 235865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 236865f3bb9SMichael Rolnik } 237865f3bb9SMichael Rolnik 238865f3bb9SMichael Rolnik static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) 239865f3bb9SMichael Rolnik { 240865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 241865f3bb9SMichael Rolnik TCGv t2 = tcg_temp_new_i32(); 242865f3bb9SMichael Rolnik 243865f3bb9SMichael Rolnik /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */ 244865f3bb9SMichael Rolnik /* = (Rd ^ R) & ~(Rd ^ Rr) */ 245865f3bb9SMichael Rolnik tcg_gen_xor_tl(t1, Rd, R); 246865f3bb9SMichael Rolnik tcg_gen_xor_tl(t2, Rd, Rr); 247865f3bb9SMichael Rolnik tcg_gen_andc_tl(t1, t1, t2); 248865f3bb9SMichael Rolnik 249865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ 250865f3bb9SMichael Rolnik 251865f3bb9SMichael Rolnik tcg_temp_free_i32(t2); 252865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 253865f3bb9SMichael Rolnik } 254865f3bb9SMichael Rolnik 255865f3bb9SMichael Rolnik static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr) 256865f3bb9SMichael Rolnik { 257865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 258865f3bb9SMichael Rolnik TCGv t2 = tcg_temp_new_i32(); 259865f3bb9SMichael Rolnik TCGv t3 = tcg_temp_new_i32(); 260865f3bb9SMichael Rolnik 261865f3bb9SMichael Rolnik tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */ 262865f3bb9SMichael Rolnik tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */ 263865f3bb9SMichael Rolnik tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */ 264865f3bb9SMichael Rolnik tcg_gen_and_tl(t3, t3, R); 265865f3bb9SMichael Rolnik tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */ 266865f3bb9SMichael Rolnik 267865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */ 268865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */ 269865f3bb9SMichael Rolnik tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); 270865f3bb9SMichael Rolnik 271865f3bb9SMichael Rolnik tcg_temp_free_i32(t3); 272865f3bb9SMichael Rolnik tcg_temp_free_i32(t2); 273865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 274865f3bb9SMichael Rolnik } 275865f3bb9SMichael Rolnik 276865f3bb9SMichael Rolnik static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr) 277865f3bb9SMichael Rolnik { 278865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 279865f3bb9SMichael Rolnik TCGv t2 = tcg_temp_new_i32(); 280865f3bb9SMichael Rolnik 281865f3bb9SMichael Rolnik /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */ 282865f3bb9SMichael Rolnik /* = (Rd ^ R) & (Rd ^ R) */ 283865f3bb9SMichael Rolnik tcg_gen_xor_tl(t1, Rd, R); 284865f3bb9SMichael Rolnik tcg_gen_xor_tl(t2, Rd, Rr); 285865f3bb9SMichael Rolnik tcg_gen_and_tl(t1, t1, t2); 286865f3bb9SMichael Rolnik 287865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ 288865f3bb9SMichael Rolnik 289865f3bb9SMichael Rolnik tcg_temp_free_i32(t2); 290865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 291865f3bb9SMichael Rolnik } 292865f3bb9SMichael Rolnik 293865f3bb9SMichael Rolnik static void gen_NSf(TCGv R) 294865f3bb9SMichael Rolnik { 295865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ 296865f3bb9SMichael Rolnik tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ 297865f3bb9SMichael Rolnik } 298865f3bb9SMichael Rolnik 299865f3bb9SMichael Rolnik static void gen_ZNSf(TCGv R) 300865f3bb9SMichael Rolnik { 301865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 302865f3bb9SMichael Rolnik 303865f3bb9SMichael Rolnik /* update status register */ 304865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ 305865f3bb9SMichael Rolnik tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ 306865f3bb9SMichael Rolnik } 307865f3bb9SMichael Rolnik 308865f3bb9SMichael Rolnik /* 309865f3bb9SMichael Rolnik * Adds two registers without the C Flag and places the result in the 310865f3bb9SMichael Rolnik * destination register Rd. 311865f3bb9SMichael Rolnik */ 312865f3bb9SMichael Rolnik static bool trans_ADD(DisasContext *ctx, arg_ADD *a) 313865f3bb9SMichael Rolnik { 314865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 315865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 316865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 317865f3bb9SMichael Rolnik 318865f3bb9SMichael Rolnik tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */ 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 two registers and the contents of the C Flag and places the result in 336865f3bb9SMichael Rolnik * the destination register Rd. 337865f3bb9SMichael Rolnik */ 338865f3bb9SMichael Rolnik static bool trans_ADC(DisasContext *ctx, arg_ADC *a) 339865f3bb9SMichael Rolnik { 340865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 341865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 342865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 343865f3bb9SMichael Rolnik 344865f3bb9SMichael Rolnik tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */ 345865f3bb9SMichael Rolnik tcg_gen_add_tl(R, R, cpu_Cf); 346865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 347865f3bb9SMichael Rolnik 348865f3bb9SMichael Rolnik /* update status register */ 349865f3bb9SMichael Rolnik gen_add_CHf(R, Rd, Rr); 350865f3bb9SMichael Rolnik gen_add_Vf(R, Rd, Rr); 351865f3bb9SMichael Rolnik gen_ZNSf(R); 352865f3bb9SMichael Rolnik 353865f3bb9SMichael Rolnik /* update output registers */ 354865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 355865f3bb9SMichael Rolnik 356865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 357865f3bb9SMichael Rolnik 358865f3bb9SMichael Rolnik return true; 359865f3bb9SMichael Rolnik } 360865f3bb9SMichael Rolnik 361865f3bb9SMichael Rolnik /* 362865f3bb9SMichael Rolnik * Adds an immediate value (0 - 63) to a register pair and places the result 363865f3bb9SMichael Rolnik * in the register pair. This instruction operates on the upper four register 364865f3bb9SMichael Rolnik * pairs, and is well suited for operations on the pointer registers. This 365865f3bb9SMichael Rolnik * instruction is not available in all devices. Refer to the device specific 366865f3bb9SMichael Rolnik * instruction set summary. 367865f3bb9SMichael Rolnik */ 368865f3bb9SMichael Rolnik static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a) 369865f3bb9SMichael Rolnik { 370865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { 371865f3bb9SMichael Rolnik return true; 372865f3bb9SMichael Rolnik } 373865f3bb9SMichael Rolnik 374865f3bb9SMichael Rolnik TCGv RdL = cpu_r[a->rd]; 375865f3bb9SMichael Rolnik TCGv RdH = cpu_r[a->rd + 1]; 376865f3bb9SMichael Rolnik int Imm = (a->imm); 377865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 378865f3bb9SMichael Rolnik TCGv Rd = tcg_temp_new_i32(); 379865f3bb9SMichael Rolnik 380865f3bb9SMichael Rolnik tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ 381865f3bb9SMichael Rolnik tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */ 382865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ 383865f3bb9SMichael Rolnik 384865f3bb9SMichael Rolnik /* update status register */ 385865f3bb9SMichael Rolnik tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ 386865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); 387865f3bb9SMichael Rolnik tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */ 388865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); 389865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 390865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ 391865f3bb9SMichael Rolnik tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */ 392865f3bb9SMichael Rolnik 393865f3bb9SMichael Rolnik /* update output registers */ 394865f3bb9SMichael Rolnik tcg_gen_andi_tl(RdL, R, 0xff); 395865f3bb9SMichael Rolnik tcg_gen_shri_tl(RdH, R, 8); 396865f3bb9SMichael Rolnik 397865f3bb9SMichael Rolnik tcg_temp_free_i32(Rd); 398865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 399865f3bb9SMichael Rolnik 400865f3bb9SMichael Rolnik return true; 401865f3bb9SMichael Rolnik } 402865f3bb9SMichael Rolnik 403865f3bb9SMichael Rolnik /* 404865f3bb9SMichael Rolnik * Subtracts two registers and places the result in the destination 405865f3bb9SMichael Rolnik * register Rd. 406865f3bb9SMichael Rolnik */ 407865f3bb9SMichael Rolnik static bool trans_SUB(DisasContext *ctx, arg_SUB *a) 408865f3bb9SMichael Rolnik { 409865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 410865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 411865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 412865f3bb9SMichael Rolnik 413865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ 414865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 415865f3bb9SMichael Rolnik 416865f3bb9SMichael Rolnik /* update status register */ 417865f3bb9SMichael Rolnik tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ 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 427865f3bb9SMichael Rolnik return true; 428865f3bb9SMichael Rolnik } 429865f3bb9SMichael Rolnik 430865f3bb9SMichael Rolnik /* 431865f3bb9SMichael Rolnik * Subtracts a register and a constant and places the result in the 432865f3bb9SMichael Rolnik * destination register Rd. This instruction is working on Register R16 to R31 433865f3bb9SMichael Rolnik * and is very well suited for operations on the X, Y, and Z-pointers. 434865f3bb9SMichael Rolnik */ 435865f3bb9SMichael Rolnik static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a) 436865f3bb9SMichael Rolnik { 437865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 438865f3bb9SMichael Rolnik TCGv Rr = tcg_const_i32(a->imm); 439865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 440865f3bb9SMichael Rolnik 441865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */ 442865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 443865f3bb9SMichael Rolnik 444865f3bb9SMichael Rolnik /* update status register */ 445865f3bb9SMichael Rolnik gen_sub_CHf(R, Rd, Rr); 446865f3bb9SMichael Rolnik gen_sub_Vf(R, Rd, Rr); 447865f3bb9SMichael Rolnik gen_ZNSf(R); 448865f3bb9SMichael Rolnik 449865f3bb9SMichael Rolnik /* update output registers */ 450865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 451865f3bb9SMichael Rolnik 452865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 453865f3bb9SMichael Rolnik tcg_temp_free_i32(Rr); 454865f3bb9SMichael Rolnik 455865f3bb9SMichael Rolnik return true; 456865f3bb9SMichael Rolnik } 457865f3bb9SMichael Rolnik 458865f3bb9SMichael Rolnik /* 459865f3bb9SMichael Rolnik * Subtracts two registers and subtracts with the C Flag and places the 460865f3bb9SMichael Rolnik * result in the destination register Rd. 461865f3bb9SMichael Rolnik */ 462865f3bb9SMichael Rolnik static bool trans_SBC(DisasContext *ctx, arg_SBC *a) 463865f3bb9SMichael Rolnik { 464865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 465865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 466865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 467865f3bb9SMichael Rolnik TCGv zero = tcg_const_i32(0); 468865f3bb9SMichael Rolnik 469865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ 470865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, R, cpu_Cf); 471865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 472865f3bb9SMichael Rolnik 473865f3bb9SMichael Rolnik /* update status register */ 474865f3bb9SMichael Rolnik gen_sub_CHf(R, Rd, Rr); 475865f3bb9SMichael Rolnik gen_sub_Vf(R, Rd, Rr); 476865f3bb9SMichael Rolnik gen_NSf(R); 477865f3bb9SMichael Rolnik 478865f3bb9SMichael Rolnik /* 479865f3bb9SMichael Rolnik * Previous value remains unchanged when the result is zero; 480865f3bb9SMichael Rolnik * cleared otherwise. 481865f3bb9SMichael Rolnik */ 482865f3bb9SMichael Rolnik tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); 483865f3bb9SMichael Rolnik 484865f3bb9SMichael Rolnik /* update output registers */ 485865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 486865f3bb9SMichael Rolnik 487865f3bb9SMichael Rolnik tcg_temp_free_i32(zero); 488865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 489865f3bb9SMichael Rolnik 490865f3bb9SMichael Rolnik return true; 491865f3bb9SMichael Rolnik } 492865f3bb9SMichael Rolnik 493865f3bb9SMichael Rolnik /* 494865f3bb9SMichael Rolnik * SBCI -- Subtract Immediate with Carry 495865f3bb9SMichael Rolnik */ 496865f3bb9SMichael Rolnik static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a) 497865f3bb9SMichael Rolnik { 498865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 499865f3bb9SMichael Rolnik TCGv Rr = tcg_const_i32(a->imm); 500865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 501865f3bb9SMichael Rolnik TCGv zero = tcg_const_i32(0); 502865f3bb9SMichael Rolnik 503865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ 504865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, R, cpu_Cf); 505865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 506865f3bb9SMichael Rolnik 507865f3bb9SMichael Rolnik /* update status register */ 508865f3bb9SMichael Rolnik gen_sub_CHf(R, Rd, Rr); 509865f3bb9SMichael Rolnik gen_sub_Vf(R, Rd, Rr); 510865f3bb9SMichael Rolnik gen_NSf(R); 511865f3bb9SMichael Rolnik 512865f3bb9SMichael Rolnik /* 513865f3bb9SMichael Rolnik * Previous value remains unchanged when the result is zero; 514865f3bb9SMichael Rolnik * cleared otherwise. 515865f3bb9SMichael Rolnik */ 516865f3bb9SMichael Rolnik tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); 517865f3bb9SMichael Rolnik 518865f3bb9SMichael Rolnik /* update output registers */ 519865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 520865f3bb9SMichael Rolnik 521865f3bb9SMichael Rolnik tcg_temp_free_i32(zero); 522865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 523865f3bb9SMichael Rolnik tcg_temp_free_i32(Rr); 524865f3bb9SMichael Rolnik 525865f3bb9SMichael Rolnik return true; 526865f3bb9SMichael Rolnik } 527865f3bb9SMichael Rolnik 528865f3bb9SMichael Rolnik /* 529865f3bb9SMichael Rolnik * Subtracts an immediate value (0-63) from a register pair and places the 530865f3bb9SMichael Rolnik * result in the register pair. This instruction operates on the upper four 531865f3bb9SMichael Rolnik * register pairs, and is well suited for operations on the Pointer Registers. 532865f3bb9SMichael Rolnik * This instruction is not available in all devices. Refer to the device 533865f3bb9SMichael Rolnik * specific instruction set summary. 534865f3bb9SMichael Rolnik */ 535865f3bb9SMichael Rolnik static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a) 536865f3bb9SMichael Rolnik { 537865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { 538865f3bb9SMichael Rolnik return true; 539865f3bb9SMichael Rolnik } 540865f3bb9SMichael Rolnik 541865f3bb9SMichael Rolnik TCGv RdL = cpu_r[a->rd]; 542865f3bb9SMichael Rolnik TCGv RdH = cpu_r[a->rd + 1]; 543865f3bb9SMichael Rolnik int Imm = (a->imm); 544865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 545865f3bb9SMichael Rolnik TCGv Rd = tcg_temp_new_i32(); 546865f3bb9SMichael Rolnik 547865f3bb9SMichael Rolnik tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ 548865f3bb9SMichael Rolnik tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */ 549865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ 550865f3bb9SMichael Rolnik 551865f3bb9SMichael Rolnik /* update status register */ 552865f3bb9SMichael Rolnik tcg_gen_andc_tl(cpu_Cf, R, Rd); 553865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */ 554865f3bb9SMichael Rolnik tcg_gen_andc_tl(cpu_Vf, Rd, R); 555865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */ 556865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 557865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ 558865f3bb9SMichael Rolnik tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ 559865f3bb9SMichael Rolnik 560865f3bb9SMichael Rolnik /* update output registers */ 561865f3bb9SMichael Rolnik tcg_gen_andi_tl(RdL, R, 0xff); 562865f3bb9SMichael Rolnik tcg_gen_shri_tl(RdH, R, 8); 563865f3bb9SMichael Rolnik 564865f3bb9SMichael Rolnik tcg_temp_free_i32(Rd); 565865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 566865f3bb9SMichael Rolnik 567865f3bb9SMichael Rolnik return true; 568865f3bb9SMichael Rolnik } 569865f3bb9SMichael Rolnik 570865f3bb9SMichael Rolnik /* 571865f3bb9SMichael Rolnik * Performs the logical AND between the contents of register Rd and register 572865f3bb9SMichael Rolnik * Rr and places the result in the destination register Rd. 573865f3bb9SMichael Rolnik */ 574865f3bb9SMichael Rolnik static bool trans_AND(DisasContext *ctx, arg_AND *a) 575865f3bb9SMichael Rolnik { 576865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 577865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 578865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 579865f3bb9SMichael Rolnik 580865f3bb9SMichael Rolnik tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */ 581865f3bb9SMichael Rolnik 582865f3bb9SMichael Rolnik /* update status register */ 583865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ 584865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 585865f3bb9SMichael Rolnik gen_ZNSf(R); 586865f3bb9SMichael Rolnik 587865f3bb9SMichael Rolnik /* update output registers */ 588865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 589865f3bb9SMichael Rolnik 590865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 591865f3bb9SMichael Rolnik 592865f3bb9SMichael Rolnik return true; 593865f3bb9SMichael Rolnik } 594865f3bb9SMichael Rolnik 595865f3bb9SMichael Rolnik /* 596865f3bb9SMichael Rolnik * Performs the logical AND between the contents of register Rd and a constant 597865f3bb9SMichael Rolnik * and places the result in the destination register Rd. 598865f3bb9SMichael Rolnik */ 599865f3bb9SMichael Rolnik static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a) 600865f3bb9SMichael Rolnik { 601865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 602865f3bb9SMichael Rolnik int Imm = (a->imm); 603865f3bb9SMichael Rolnik 604865f3bb9SMichael Rolnik tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */ 605865f3bb9SMichael Rolnik 606865f3bb9SMichael Rolnik /* update status register */ 607865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ 608865f3bb9SMichael Rolnik gen_ZNSf(Rd); 609865f3bb9SMichael Rolnik 610865f3bb9SMichael Rolnik return true; 611865f3bb9SMichael Rolnik } 612865f3bb9SMichael Rolnik 613865f3bb9SMichael Rolnik /* 614865f3bb9SMichael Rolnik * Performs the logical OR between the contents of register Rd and register 615865f3bb9SMichael Rolnik * Rr and places the result in the destination register Rd. 616865f3bb9SMichael Rolnik */ 617865f3bb9SMichael Rolnik static bool trans_OR(DisasContext *ctx, arg_OR *a) 618865f3bb9SMichael Rolnik { 619865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 620865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 621865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 622865f3bb9SMichael Rolnik 623865f3bb9SMichael Rolnik tcg_gen_or_tl(R, Rd, Rr); 624865f3bb9SMichael Rolnik 625865f3bb9SMichael Rolnik /* update status register */ 626865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0); 627865f3bb9SMichael Rolnik gen_ZNSf(R); 628865f3bb9SMichael Rolnik 629865f3bb9SMichael Rolnik /* update output registers */ 630865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 631865f3bb9SMichael Rolnik 632865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 633865f3bb9SMichael Rolnik 634865f3bb9SMichael Rolnik return true; 635865f3bb9SMichael Rolnik } 636865f3bb9SMichael Rolnik 637865f3bb9SMichael Rolnik /* 638865f3bb9SMichael Rolnik * Performs the logical OR between the contents of register Rd and a 639865f3bb9SMichael Rolnik * constant and places the result in the destination register Rd. 640865f3bb9SMichael Rolnik */ 641865f3bb9SMichael Rolnik static bool trans_ORI(DisasContext *ctx, arg_ORI *a) 642865f3bb9SMichael Rolnik { 643865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 644865f3bb9SMichael Rolnik int Imm = (a->imm); 645865f3bb9SMichael Rolnik 646865f3bb9SMichael Rolnik tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */ 647865f3bb9SMichael Rolnik 648865f3bb9SMichael Rolnik /* update status register */ 649865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ 650865f3bb9SMichael Rolnik gen_ZNSf(Rd); 651865f3bb9SMichael Rolnik 652865f3bb9SMichael Rolnik return true; 653865f3bb9SMichael Rolnik } 654865f3bb9SMichael Rolnik 655865f3bb9SMichael Rolnik /* 656865f3bb9SMichael Rolnik * Performs the logical EOR between the contents of register Rd and 657865f3bb9SMichael Rolnik * register Rr and places the result in the destination register Rd. 658865f3bb9SMichael Rolnik */ 659865f3bb9SMichael Rolnik static bool trans_EOR(DisasContext *ctx, arg_EOR *a) 660865f3bb9SMichael Rolnik { 661865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 662865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 663865f3bb9SMichael Rolnik 664865f3bb9SMichael Rolnik tcg_gen_xor_tl(Rd, Rd, Rr); 665865f3bb9SMichael Rolnik 666865f3bb9SMichael Rolnik /* update status register */ 667865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0); 668865f3bb9SMichael Rolnik gen_ZNSf(Rd); 669865f3bb9SMichael Rolnik 670865f3bb9SMichael Rolnik return true; 671865f3bb9SMichael Rolnik } 672865f3bb9SMichael Rolnik 673865f3bb9SMichael Rolnik /* 674865f3bb9SMichael Rolnik * Clears the specified bits in register Rd. Performs the logical AND 675865f3bb9SMichael Rolnik * between the contents of register Rd and the complement of the constant mask 676865f3bb9SMichael Rolnik * K. The result will be placed in register Rd. 677865f3bb9SMichael Rolnik */ 678865f3bb9SMichael Rolnik static bool trans_COM(DisasContext *ctx, arg_COM *a) 679865f3bb9SMichael Rolnik { 680865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 681865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 682865f3bb9SMichael Rolnik 683865f3bb9SMichael Rolnik tcg_gen_xori_tl(Rd, Rd, 0xff); 684865f3bb9SMichael Rolnik 685865f3bb9SMichael Rolnik /* update status register */ 686865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */ 687865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ 688865f3bb9SMichael Rolnik gen_ZNSf(Rd); 689865f3bb9SMichael Rolnik 690865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 691865f3bb9SMichael Rolnik 692865f3bb9SMichael Rolnik return true; 693865f3bb9SMichael Rolnik } 694865f3bb9SMichael Rolnik 695865f3bb9SMichael Rolnik /* 696865f3bb9SMichael Rolnik * Replaces the contents of register Rd with its two's complement; the 697865f3bb9SMichael Rolnik * value $80 is left unchanged. 698865f3bb9SMichael Rolnik */ 699865f3bb9SMichael Rolnik static bool trans_NEG(DisasContext *ctx, arg_NEG *a) 700865f3bb9SMichael Rolnik { 701865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 702865f3bb9SMichael Rolnik TCGv t0 = tcg_const_i32(0); 703865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 704865f3bb9SMichael Rolnik 705865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */ 706865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 707865f3bb9SMichael Rolnik 708865f3bb9SMichael Rolnik /* update status register */ 709865f3bb9SMichael Rolnik gen_sub_CHf(R, t0, Rd); 710865f3bb9SMichael Rolnik gen_sub_Vf(R, t0, Rd); 711865f3bb9SMichael Rolnik gen_ZNSf(R); 712865f3bb9SMichael Rolnik 713865f3bb9SMichael Rolnik /* update output registers */ 714865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 715865f3bb9SMichael Rolnik 716865f3bb9SMichael Rolnik tcg_temp_free_i32(t0); 717865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 718865f3bb9SMichael Rolnik 719865f3bb9SMichael Rolnik return true; 720865f3bb9SMichael Rolnik } 721865f3bb9SMichael Rolnik 722865f3bb9SMichael Rolnik /* 723865f3bb9SMichael Rolnik * Adds one -1- to the contents of register Rd and places the result in the 724865f3bb9SMichael Rolnik * destination register Rd. The C Flag in SREG is not affected by the 725865f3bb9SMichael Rolnik * operation, thus allowing the INC instruction to be used on a loop counter in 726865f3bb9SMichael Rolnik * multiple-precision computations. When operating on unsigned numbers, only 727865f3bb9SMichael Rolnik * BREQ and BRNE branches can be expected to perform consistently. When 728865f3bb9SMichael Rolnik * operating on two's complement values, all signed branches are available. 729865f3bb9SMichael Rolnik */ 730865f3bb9SMichael Rolnik static bool trans_INC(DisasContext *ctx, arg_INC *a) 731865f3bb9SMichael Rolnik { 732865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 733865f3bb9SMichael Rolnik 734865f3bb9SMichael Rolnik tcg_gen_addi_tl(Rd, Rd, 1); 735865f3bb9SMichael Rolnik tcg_gen_andi_tl(Rd, Rd, 0xff); 736865f3bb9SMichael Rolnik 737865f3bb9SMichael Rolnik /* update status register */ 738865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */ 739865f3bb9SMichael Rolnik gen_ZNSf(Rd); 740865f3bb9SMichael Rolnik 741865f3bb9SMichael Rolnik return true; 742865f3bb9SMichael Rolnik } 743865f3bb9SMichael Rolnik 744865f3bb9SMichael Rolnik /* 745865f3bb9SMichael Rolnik * Subtracts one -1- from the contents of register Rd and places the result 746865f3bb9SMichael Rolnik * in the destination register Rd. The C Flag in SREG is not affected by the 747865f3bb9SMichael Rolnik * operation, thus allowing the DEC instruction to be used on a loop counter in 748865f3bb9SMichael Rolnik * multiple-precision computations. When operating on unsigned values, only 749865f3bb9SMichael Rolnik * BREQ and BRNE branches can be expected to perform consistently. When 750865f3bb9SMichael Rolnik * operating on two's complement values, all signed branches are available. 751865f3bb9SMichael Rolnik */ 752865f3bb9SMichael Rolnik static bool trans_DEC(DisasContext *ctx, arg_DEC *a) 753865f3bb9SMichael Rolnik { 754865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 755865f3bb9SMichael Rolnik 756865f3bb9SMichael Rolnik tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */ 757865f3bb9SMichael Rolnik tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */ 758865f3bb9SMichael Rolnik 759865f3bb9SMichael Rolnik /* update status register */ 760865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */ 761865f3bb9SMichael Rolnik gen_ZNSf(Rd); 762865f3bb9SMichael Rolnik 763865f3bb9SMichael Rolnik return true; 764865f3bb9SMichael Rolnik } 765865f3bb9SMichael Rolnik 766865f3bb9SMichael Rolnik /* 767865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication. 768865f3bb9SMichael Rolnik */ 769865f3bb9SMichael Rolnik static bool trans_MUL(DisasContext *ctx, arg_MUL *a) 770865f3bb9SMichael Rolnik { 771865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 772865f3bb9SMichael Rolnik return true; 773865f3bb9SMichael Rolnik } 774865f3bb9SMichael Rolnik 775865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 776865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 777865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 778865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 779865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 780865f3bb9SMichael Rolnik 781865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ 782865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 783865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 784865f3bb9SMichael Rolnik 785865f3bb9SMichael Rolnik /* update status register */ 786865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 787865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 788865f3bb9SMichael Rolnik 789865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 790865f3bb9SMichael Rolnik 791865f3bb9SMichael Rolnik return true; 792865f3bb9SMichael Rolnik } 793865f3bb9SMichael Rolnik 794865f3bb9SMichael Rolnik /* 795865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication. 796865f3bb9SMichael Rolnik */ 797865f3bb9SMichael Rolnik static bool trans_MULS(DisasContext *ctx, arg_MULS *a) 798865f3bb9SMichael Rolnik { 799865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 800865f3bb9SMichael Rolnik return true; 801865f3bb9SMichael Rolnik } 802865f3bb9SMichael Rolnik 803865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 804865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 805865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 806865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 807865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 808865f3bb9SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 809865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 810865f3bb9SMichael Rolnik 811865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ 812865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ 813865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ 814865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ 815865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 816865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 817865f3bb9SMichael Rolnik 818865f3bb9SMichael Rolnik /* update status register */ 819865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 820865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 821865f3bb9SMichael Rolnik 822865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 823865f3bb9SMichael Rolnik tcg_temp_free_i32(t0); 824865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 825865f3bb9SMichael Rolnik 826865f3bb9SMichael Rolnik return true; 827865f3bb9SMichael Rolnik } 828865f3bb9SMichael Rolnik 829865f3bb9SMichael Rolnik /* 830865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a 831865f3bb9SMichael Rolnik * signed and an unsigned number. 832865f3bb9SMichael Rolnik */ 833865f3bb9SMichael Rolnik static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a) 834865f3bb9SMichael Rolnik { 835865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 836865f3bb9SMichael Rolnik return true; 837865f3bb9SMichael Rolnik } 838865f3bb9SMichael Rolnik 839865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 840865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 841865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 842865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 843865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 844865f3bb9SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 845865f3bb9SMichael Rolnik 846865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ 847865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ 848865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */ 849865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 850865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 851865f3bb9SMichael Rolnik 852865f3bb9SMichael Rolnik /* update status register */ 853865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 854865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 855865f3bb9SMichael Rolnik 856865f3bb9SMichael Rolnik tcg_temp_free_i32(t0); 857865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 858865f3bb9SMichael Rolnik 859865f3bb9SMichael Rolnik return true; 860865f3bb9SMichael Rolnik } 861865f3bb9SMichael Rolnik 862865f3bb9SMichael Rolnik /* 863865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit unsigned 864865f3bb9SMichael Rolnik * multiplication and shifts the result one bit left. 865865f3bb9SMichael Rolnik */ 866865f3bb9SMichael Rolnik static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a) 867865f3bb9SMichael Rolnik { 868865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 869865f3bb9SMichael Rolnik return true; 870865f3bb9SMichael Rolnik } 871865f3bb9SMichael Rolnik 872865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 873865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 874865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 875865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 876865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 877865f3bb9SMichael Rolnik 878865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ 879865f3bb9SMichael Rolnik 880865f3bb9SMichael Rolnik /* update status register */ 881865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 882865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 883865f3bb9SMichael Rolnik 884865f3bb9SMichael Rolnik /* update output registers */ 885865f3bb9SMichael Rolnik tcg_gen_shli_tl(R, R, 1); 886865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 887865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 888865f3bb9SMichael Rolnik tcg_gen_andi_tl(R1, R1, 0xff); 889865f3bb9SMichael Rolnik 890865f3bb9SMichael Rolnik 891865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 892865f3bb9SMichael Rolnik 893865f3bb9SMichael Rolnik return true; 894865f3bb9SMichael Rolnik } 895865f3bb9SMichael Rolnik 896865f3bb9SMichael Rolnik /* 897865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication 898865f3bb9SMichael Rolnik * and shifts the result one bit left. 899865f3bb9SMichael Rolnik */ 900865f3bb9SMichael Rolnik static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a) 901865f3bb9SMichael Rolnik { 902865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 903865f3bb9SMichael Rolnik return true; 904865f3bb9SMichael Rolnik } 905865f3bb9SMichael Rolnik 906865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 907865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 908865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 909865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 910865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 911865f3bb9SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 912865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 913865f3bb9SMichael Rolnik 914865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ 915865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ 916865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ 917865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ 918865f3bb9SMichael Rolnik 919865f3bb9SMichael Rolnik /* update status register */ 920865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 921865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 922865f3bb9SMichael Rolnik 923865f3bb9SMichael Rolnik /* update output registers */ 924865f3bb9SMichael Rolnik tcg_gen_shli_tl(R, R, 1); 925865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 926865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 927865f3bb9SMichael Rolnik tcg_gen_andi_tl(R1, R1, 0xff); 928865f3bb9SMichael Rolnik 929865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 930865f3bb9SMichael Rolnik tcg_temp_free_i32(t0); 931865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 932865f3bb9SMichael Rolnik 933865f3bb9SMichael Rolnik return true; 934865f3bb9SMichael Rolnik } 935865f3bb9SMichael Rolnik 936865f3bb9SMichael Rolnik /* 937865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication 938865f3bb9SMichael Rolnik * and shifts the result one bit left. 939865f3bb9SMichael Rolnik */ 940865f3bb9SMichael Rolnik static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a) 941865f3bb9SMichael Rolnik { 942865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 943865f3bb9SMichael Rolnik return true; 944865f3bb9SMichael Rolnik } 945865f3bb9SMichael Rolnik 946865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 947865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 948865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 949865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 950865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 951865f3bb9SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 952865f3bb9SMichael Rolnik 953865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ 954865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ 955865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ 956865f3bb9SMichael Rolnik 957865f3bb9SMichael Rolnik /* update status register */ 958865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 959865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 960865f3bb9SMichael Rolnik 961865f3bb9SMichael Rolnik /* update output registers */ 962865f3bb9SMichael Rolnik tcg_gen_shli_tl(R, R, 1); 963865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 964865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 965865f3bb9SMichael Rolnik tcg_gen_andi_tl(R1, R1, 0xff); 966865f3bb9SMichael Rolnik 967865f3bb9SMichael Rolnik tcg_temp_free_i32(t0); 968865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 969865f3bb9SMichael Rolnik 970865f3bb9SMichael Rolnik return true; 971865f3bb9SMichael Rolnik } 972865f3bb9SMichael Rolnik 973865f3bb9SMichael Rolnik /* 974865f3bb9SMichael Rolnik * The module is an instruction set extension to the AVR CPU, performing 975865f3bb9SMichael Rolnik * DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in 976865f3bb9SMichael Rolnik * the CPU register file, registers R0-R7, where LSB of data is placed in LSB 977865f3bb9SMichael Rolnik * of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including 978865f3bb9SMichael Rolnik * parity bits) is placed in registers R8- R15, organized in the register file 979865f3bb9SMichael Rolnik * with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES 980865f3bb9SMichael Rolnik * instruction performs one round in the DES algorithm. Sixteen rounds must be 981865f3bb9SMichael Rolnik * executed in increasing order to form the correct DES ciphertext or 982865f3bb9SMichael Rolnik * plaintext. Intermediate results are stored in the register file (R0-R15) 983865f3bb9SMichael Rolnik * after each DES instruction. The instruction's operand (K) determines which 984865f3bb9SMichael Rolnik * round is executed, and the half carry flag (H) determines whether encryption 985865f3bb9SMichael Rolnik * or decryption is performed. The DES algorithm is described in 986865f3bb9SMichael Rolnik * "Specifications for the Data Encryption Standard" (Federal Information 987865f3bb9SMichael Rolnik * Processing Standards Publication 46). Intermediate results in this 988865f3bb9SMichael Rolnik * implementation differ from the standard because the initial permutation and 989865f3bb9SMichael Rolnik * the inverse initial permutation are performed each iteration. This does not 990865f3bb9SMichael Rolnik * affect the result in the final ciphertext or plaintext, but reduces 991865f3bb9SMichael Rolnik * execution time. 992865f3bb9SMichael Rolnik */ 993865f3bb9SMichael Rolnik static bool trans_DES(DisasContext *ctx, arg_DES *a) 994865f3bb9SMichael Rolnik { 995865f3bb9SMichael Rolnik /* TODO */ 996865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_DES)) { 997865f3bb9SMichael Rolnik return true; 998865f3bb9SMichael Rolnik } 999865f3bb9SMichael Rolnik 1000865f3bb9SMichael Rolnik qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); 1001865f3bb9SMichael Rolnik 1002865f3bb9SMichael Rolnik return true; 1003865f3bb9SMichael Rolnik } 10049d316c75SMichael Rolnik 10059d316c75SMichael Rolnik /* 10069d316c75SMichael Rolnik * Branch Instructions 10079d316c75SMichael Rolnik */ 10089d316c75SMichael Rolnik static void gen_jmp_ez(DisasContext *ctx) 10099d316c75SMichael Rolnik { 10109d316c75SMichael Rolnik tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); 10119d316c75SMichael Rolnik tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_eind); 101293d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_LOOKUP; 10139d316c75SMichael Rolnik } 10149d316c75SMichael Rolnik 10159d316c75SMichael Rolnik static void gen_jmp_z(DisasContext *ctx) 10169d316c75SMichael Rolnik { 10179d316c75SMichael Rolnik tcg_gen_deposit_tl(cpu_pc, cpu_r[30], cpu_r[31], 8, 8); 101893d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_LOOKUP; 10199d316c75SMichael Rolnik } 10209d316c75SMichael Rolnik 10219d316c75SMichael Rolnik static void gen_push_ret(DisasContext *ctx, int ret) 10229d316c75SMichael Rolnik { 10239d316c75SMichael Rolnik if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { 10249d316c75SMichael Rolnik 10259d316c75SMichael Rolnik TCGv t0 = tcg_const_i32((ret & 0x0000ff)); 10269d316c75SMichael Rolnik 10279d316c75SMichael Rolnik tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB); 10289d316c75SMichael Rolnik tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); 10299d316c75SMichael Rolnik 10309d316c75SMichael Rolnik tcg_temp_free_i32(t0); 10319d316c75SMichael Rolnik } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { 10329d316c75SMichael Rolnik 10339d316c75SMichael Rolnik TCGv t0 = tcg_const_i32((ret & 0x00ffff)); 10349d316c75SMichael Rolnik 10359d316c75SMichael Rolnik tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); 10369d316c75SMichael Rolnik tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW); 10379d316c75SMichael Rolnik tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); 10389d316c75SMichael Rolnik 10399d316c75SMichael Rolnik tcg_temp_free_i32(t0); 10409d316c75SMichael Rolnik 10419d316c75SMichael Rolnik } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { 10429d316c75SMichael Rolnik 10439d316c75SMichael Rolnik TCGv lo = tcg_const_i32((ret & 0x0000ff)); 10449d316c75SMichael Rolnik TCGv hi = tcg_const_i32((ret & 0xffff00) >> 8); 10459d316c75SMichael Rolnik 10469d316c75SMichael Rolnik tcg_gen_qemu_st_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); 10479d316c75SMichael Rolnik tcg_gen_subi_tl(cpu_sp, cpu_sp, 2); 10489d316c75SMichael Rolnik tcg_gen_qemu_st_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); 10499d316c75SMichael Rolnik tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); 10509d316c75SMichael Rolnik 10519d316c75SMichael Rolnik tcg_temp_free_i32(lo); 10529d316c75SMichael Rolnik tcg_temp_free_i32(hi); 10539d316c75SMichael Rolnik } 10549d316c75SMichael Rolnik } 10559d316c75SMichael Rolnik 10569d316c75SMichael Rolnik static void gen_pop_ret(DisasContext *ctx, TCGv ret) 10579d316c75SMichael Rolnik { 10589d316c75SMichael Rolnik if (avr_feature(ctx->env, AVR_FEATURE_1_BYTE_PC)) { 10599d316c75SMichael Rolnik tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); 10609d316c75SMichael Rolnik tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_UB); 10619d316c75SMichael Rolnik } else if (avr_feature(ctx->env, AVR_FEATURE_2_BYTE_PC)) { 10629d316c75SMichael Rolnik tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); 10639d316c75SMichael Rolnik tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW); 10649d316c75SMichael Rolnik tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); 10659d316c75SMichael Rolnik } else if (avr_feature(ctx->env, AVR_FEATURE_3_BYTE_PC)) { 10669d316c75SMichael Rolnik TCGv lo = tcg_temp_new_i32(); 10679d316c75SMichael Rolnik TCGv hi = tcg_temp_new_i32(); 10689d316c75SMichael Rolnik 10699d316c75SMichael Rolnik tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); 10709d316c75SMichael Rolnik tcg_gen_qemu_ld_tl(hi, cpu_sp, MMU_DATA_IDX, MO_BEUW); 10719d316c75SMichael Rolnik 10729d316c75SMichael Rolnik tcg_gen_addi_tl(cpu_sp, cpu_sp, 2); 10739d316c75SMichael Rolnik tcg_gen_qemu_ld_tl(lo, cpu_sp, MMU_DATA_IDX, MO_UB); 10749d316c75SMichael Rolnik 10759d316c75SMichael Rolnik tcg_gen_deposit_tl(ret, lo, hi, 8, 16); 10769d316c75SMichael Rolnik 10779d316c75SMichael Rolnik tcg_temp_free_i32(lo); 10789d316c75SMichael Rolnik tcg_temp_free_i32(hi); 10799d316c75SMichael Rolnik } 10809d316c75SMichael Rolnik } 10819d316c75SMichael Rolnik 10829d316c75SMichael Rolnik static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) 10839d316c75SMichael Rolnik { 108493d4d5e4SRichard Henderson const TranslationBlock *tb = ctx->base.tb; 10859d316c75SMichael Rolnik 108693d4d5e4SRichard Henderson if (!ctx->base.singlestep_enabled) { 10879d316c75SMichael Rolnik tcg_gen_goto_tb(n); 10889d316c75SMichael Rolnik tcg_gen_movi_i32(cpu_pc, dest); 10899d316c75SMichael Rolnik tcg_gen_exit_tb(tb, n); 10909d316c75SMichael Rolnik } else { 10919d316c75SMichael Rolnik tcg_gen_movi_i32(cpu_pc, dest); 10929d316c75SMichael Rolnik gen_helper_debug(cpu_env); 10939d316c75SMichael Rolnik tcg_gen_exit_tb(NULL, 0); 10949d316c75SMichael Rolnik } 109593d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 10969d316c75SMichael Rolnik } 10979d316c75SMichael Rolnik 10989d316c75SMichael Rolnik /* 10999d316c75SMichael Rolnik * Relative jump to an address within PC - 2K +1 and PC + 2K (words). For 11009d316c75SMichael Rolnik * AVR microcontrollers with Program memory not exceeding 4K words (8KB) this 11019d316c75SMichael Rolnik * instruction can address the entire memory from every address location. See 11029d316c75SMichael Rolnik * also JMP. 11039d316c75SMichael Rolnik */ 11049d316c75SMichael Rolnik static bool trans_RJMP(DisasContext *ctx, arg_RJMP *a) 11059d316c75SMichael Rolnik { 11069d316c75SMichael Rolnik int dst = ctx->npc + a->imm; 11079d316c75SMichael Rolnik 11089d316c75SMichael Rolnik gen_goto_tb(ctx, 0, dst); 11099d316c75SMichael Rolnik 11109d316c75SMichael Rolnik return true; 11119d316c75SMichael Rolnik } 11129d316c75SMichael Rolnik 11139d316c75SMichael Rolnik /* 11149d316c75SMichael Rolnik * Indirect jump to the address pointed to by the Z (16 bits) Pointer 11159d316c75SMichael Rolnik * Register in the Register File. The Z-pointer Register is 16 bits wide and 11169d316c75SMichael Rolnik * allows jump within the lowest 64K words (128KB) section of Program memory. 11179d316c75SMichael Rolnik * This instruction is not available in all devices. Refer to the device 11189d316c75SMichael Rolnik * specific instruction set summary. 11199d316c75SMichael Rolnik */ 11209d316c75SMichael Rolnik static bool trans_IJMP(DisasContext *ctx, arg_IJMP *a) 11219d316c75SMichael Rolnik { 11229d316c75SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { 11239d316c75SMichael Rolnik return true; 11249d316c75SMichael Rolnik } 11259d316c75SMichael Rolnik 11269d316c75SMichael Rolnik gen_jmp_z(ctx); 11279d316c75SMichael Rolnik 11289d316c75SMichael Rolnik return true; 11299d316c75SMichael Rolnik } 11309d316c75SMichael Rolnik 11319d316c75SMichael Rolnik /* 11329d316c75SMichael Rolnik * Indirect jump to the address pointed to by the Z (16 bits) Pointer 11339d316c75SMichael Rolnik * Register in the Register File and the EIND Register in the I/O space. This 11349d316c75SMichael Rolnik * instruction allows for indirect jumps to the entire 4M (words) Program 11359d316c75SMichael Rolnik * memory space. See also IJMP. This instruction is not available in all 11369d316c75SMichael Rolnik * devices. Refer to the device specific instruction set summary. 11379d316c75SMichael Rolnik */ 11389d316c75SMichael Rolnik static bool trans_EIJMP(DisasContext *ctx, arg_EIJMP *a) 11399d316c75SMichael Rolnik { 11409d316c75SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { 11419d316c75SMichael Rolnik return true; 11429d316c75SMichael Rolnik } 11439d316c75SMichael Rolnik 11449d316c75SMichael Rolnik gen_jmp_ez(ctx); 11459d316c75SMichael Rolnik return true; 11469d316c75SMichael Rolnik } 11479d316c75SMichael Rolnik 11489d316c75SMichael Rolnik /* 11499d316c75SMichael Rolnik * Jump to an address within the entire 4M (words) Program memory. See also 11509d316c75SMichael Rolnik * RJMP. This instruction is not available in all devices. Refer to the device 11519d316c75SMichael Rolnik * specific instruction set summary.0 11529d316c75SMichael Rolnik */ 11539d316c75SMichael Rolnik static bool trans_JMP(DisasContext *ctx, arg_JMP *a) 11549d316c75SMichael Rolnik { 11559d316c75SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { 11569d316c75SMichael Rolnik return true; 11579d316c75SMichael Rolnik } 11589d316c75SMichael Rolnik 11599d316c75SMichael Rolnik gen_goto_tb(ctx, 0, a->imm); 11609d316c75SMichael Rolnik 11619d316c75SMichael Rolnik return true; 11629d316c75SMichael Rolnik } 11639d316c75SMichael Rolnik 11649d316c75SMichael Rolnik /* 11659d316c75SMichael Rolnik * Relative call to an address within PC - 2K + 1 and PC + 2K (words). The 11669d316c75SMichael Rolnik * return address (the instruction after the RCALL) is stored onto the Stack. 11679d316c75SMichael Rolnik * See also CALL. For AVR microcontrollers with Program memory not exceeding 4K 11689d316c75SMichael Rolnik * words (8KB) this instruction can address the entire memory from every 11699d316c75SMichael Rolnik * address location. The Stack Pointer uses a post-decrement scheme during 11709d316c75SMichael Rolnik * RCALL. 11719d316c75SMichael Rolnik */ 11729d316c75SMichael Rolnik static bool trans_RCALL(DisasContext *ctx, arg_RCALL *a) 11739d316c75SMichael Rolnik { 11749d316c75SMichael Rolnik int ret = ctx->npc; 11759d316c75SMichael Rolnik int dst = ctx->npc + a->imm; 11769d316c75SMichael Rolnik 11779d316c75SMichael Rolnik gen_push_ret(ctx, ret); 11789d316c75SMichael Rolnik gen_goto_tb(ctx, 0, dst); 11799d316c75SMichael Rolnik 11809d316c75SMichael Rolnik return true; 11819d316c75SMichael Rolnik } 11829d316c75SMichael Rolnik 11839d316c75SMichael Rolnik /* 11849d316c75SMichael Rolnik * Calls to a subroutine within the entire 4M (words) Program memory. The 11859d316c75SMichael Rolnik * return address (to the instruction after the CALL) will be stored onto the 11869d316c75SMichael Rolnik * Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme during 11879d316c75SMichael Rolnik * CALL. This instruction is not available in all devices. Refer to the device 11889d316c75SMichael Rolnik * specific instruction set summary. 11899d316c75SMichael Rolnik */ 11909d316c75SMichael Rolnik static bool trans_ICALL(DisasContext *ctx, arg_ICALL *a) 11919d316c75SMichael Rolnik { 11929d316c75SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_IJMP_ICALL)) { 11939d316c75SMichael Rolnik return true; 11949d316c75SMichael Rolnik } 11959d316c75SMichael Rolnik 11969d316c75SMichael Rolnik int ret = ctx->npc; 11979d316c75SMichael Rolnik 11989d316c75SMichael Rolnik gen_push_ret(ctx, ret); 11999d316c75SMichael Rolnik gen_jmp_z(ctx); 12009d316c75SMichael Rolnik 12019d316c75SMichael Rolnik return true; 12029d316c75SMichael Rolnik } 12039d316c75SMichael Rolnik 12049d316c75SMichael Rolnik /* 12059d316c75SMichael Rolnik * Indirect call of a subroutine pointed to by the Z (16 bits) Pointer 12069d316c75SMichael Rolnik * Register in the Register File and the EIND Register in the I/O space. This 12079d316c75SMichael Rolnik * instruction allows for indirect calls to the entire 4M (words) Program 12089d316c75SMichael Rolnik * memory space. See also ICALL. The Stack Pointer uses a post-decrement scheme 12099d316c75SMichael Rolnik * during EICALL. This instruction is not available in all devices. Refer to 12109d316c75SMichael Rolnik * the device specific instruction set summary. 12119d316c75SMichael Rolnik */ 12129d316c75SMichael Rolnik static bool trans_EICALL(DisasContext *ctx, arg_EICALL *a) 12139d316c75SMichael Rolnik { 12149d316c75SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_EIJMP_EICALL)) { 12159d316c75SMichael Rolnik return true; 12169d316c75SMichael Rolnik } 12179d316c75SMichael Rolnik 12189d316c75SMichael Rolnik int ret = ctx->npc; 12199d316c75SMichael Rolnik 12209d316c75SMichael Rolnik gen_push_ret(ctx, ret); 12219d316c75SMichael Rolnik gen_jmp_ez(ctx); 12229d316c75SMichael Rolnik return true; 12239d316c75SMichael Rolnik } 12249d316c75SMichael Rolnik 12259d316c75SMichael Rolnik /* 12269d316c75SMichael Rolnik * Calls to a subroutine within the entire Program memory. The return 12279d316c75SMichael Rolnik * address (to the instruction after the CALL) will be stored onto the Stack. 12289d316c75SMichael Rolnik * (See also RCALL). The Stack Pointer uses a post-decrement scheme during 12299d316c75SMichael Rolnik * CALL. This instruction is not available in all devices. Refer to the device 12309d316c75SMichael Rolnik * specific instruction set summary. 12319d316c75SMichael Rolnik */ 12329d316c75SMichael Rolnik static bool trans_CALL(DisasContext *ctx, arg_CALL *a) 12339d316c75SMichael Rolnik { 12349d316c75SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_JMP_CALL)) { 12359d316c75SMichael Rolnik return true; 12369d316c75SMichael Rolnik } 12379d316c75SMichael Rolnik 12389d316c75SMichael Rolnik int Imm = a->imm; 12399d316c75SMichael Rolnik int ret = ctx->npc; 12409d316c75SMichael Rolnik 12419d316c75SMichael Rolnik gen_push_ret(ctx, ret); 12429d316c75SMichael Rolnik gen_goto_tb(ctx, 0, Imm); 12439d316c75SMichael Rolnik 12449d316c75SMichael Rolnik return true; 12459d316c75SMichael Rolnik } 12469d316c75SMichael Rolnik 12479d316c75SMichael Rolnik /* 12489d316c75SMichael Rolnik * Returns from subroutine. The return address is loaded from the STACK. 12499d316c75SMichael Rolnik * The Stack Pointer uses a preincrement scheme during RET. 12509d316c75SMichael Rolnik */ 12519d316c75SMichael Rolnik static bool trans_RET(DisasContext *ctx, arg_RET *a) 12529d316c75SMichael Rolnik { 12539d316c75SMichael Rolnik gen_pop_ret(ctx, cpu_pc); 12549d316c75SMichael Rolnik 125593d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_LOOKUP; 12569d316c75SMichael Rolnik return true; 12579d316c75SMichael Rolnik } 12589d316c75SMichael Rolnik 12599d316c75SMichael Rolnik /* 12609d316c75SMichael Rolnik * Returns from interrupt. The return address is loaded from the STACK and 12619d316c75SMichael Rolnik * the Global Interrupt Flag is set. Note that the Status Register is not 12629d316c75SMichael Rolnik * automatically stored when entering an interrupt routine, and it is not 12639d316c75SMichael Rolnik * restored when returning from an interrupt routine. This must be handled by 12649d316c75SMichael Rolnik * the application program. The Stack Pointer uses a pre-increment scheme 12659d316c75SMichael Rolnik * during RETI. 12669d316c75SMichael Rolnik */ 12679d316c75SMichael Rolnik static bool trans_RETI(DisasContext *ctx, arg_RETI *a) 12689d316c75SMichael Rolnik { 12699d316c75SMichael Rolnik gen_pop_ret(ctx, cpu_pc); 12709d316c75SMichael Rolnik tcg_gen_movi_tl(cpu_If, 1); 12719d316c75SMichael Rolnik 12729d316c75SMichael Rolnik /* Need to return to main loop to re-evaluate interrupts. */ 127393d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_EXIT; 12749d316c75SMichael Rolnik return true; 12759d316c75SMichael Rolnik } 12769d316c75SMichael Rolnik 12779d316c75SMichael Rolnik /* 12789d316c75SMichael Rolnik * This instruction performs a compare between two registers Rd and Rr, and 12799d316c75SMichael Rolnik * skips the next instruction if Rd = Rr. 12809d316c75SMichael Rolnik */ 12819d316c75SMichael Rolnik static bool trans_CPSE(DisasContext *ctx, arg_CPSE *a) 12829d316c75SMichael Rolnik { 12839d316c75SMichael Rolnik ctx->skip_cond = TCG_COND_EQ; 12849d316c75SMichael Rolnik ctx->skip_var0 = cpu_r[a->rd]; 12859d316c75SMichael Rolnik ctx->skip_var1 = cpu_r[a->rr]; 12869d316c75SMichael Rolnik return true; 12879d316c75SMichael Rolnik } 12889d316c75SMichael Rolnik 12899d316c75SMichael Rolnik /* 12909d316c75SMichael Rolnik * This instruction performs a compare between two registers Rd and Rr. 12919d316c75SMichael Rolnik * None of the registers are changed. All conditional branches can be used 12929d316c75SMichael Rolnik * after this instruction. 12939d316c75SMichael Rolnik */ 12949d316c75SMichael Rolnik static bool trans_CP(DisasContext *ctx, arg_CP *a) 12959d316c75SMichael Rolnik { 12969d316c75SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 12979d316c75SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 12989d316c75SMichael Rolnik TCGv R = tcg_temp_new_i32(); 12999d316c75SMichael Rolnik 13009d316c75SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ 13019d316c75SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 13029d316c75SMichael Rolnik 13039d316c75SMichael Rolnik /* update status register */ 13049d316c75SMichael Rolnik gen_sub_CHf(R, Rd, Rr); 13059d316c75SMichael Rolnik gen_sub_Vf(R, Rd, Rr); 13069d316c75SMichael Rolnik gen_ZNSf(R); 13079d316c75SMichael Rolnik 13089d316c75SMichael Rolnik tcg_temp_free_i32(R); 13099d316c75SMichael Rolnik 13109d316c75SMichael Rolnik return true; 13119d316c75SMichael Rolnik } 13129d316c75SMichael Rolnik 13139d316c75SMichael Rolnik /* 13149d316c75SMichael Rolnik * This instruction performs a compare between two registers Rd and Rr and 13159d316c75SMichael Rolnik * also takes into account the previous carry. None of the registers are 13169d316c75SMichael Rolnik * changed. All conditional branches can be used after this instruction. 13179d316c75SMichael Rolnik */ 13189d316c75SMichael Rolnik static bool trans_CPC(DisasContext *ctx, arg_CPC *a) 13199d316c75SMichael Rolnik { 13209d316c75SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 13219d316c75SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 13229d316c75SMichael Rolnik TCGv R = tcg_temp_new_i32(); 13239d316c75SMichael Rolnik TCGv zero = tcg_const_i32(0); 13249d316c75SMichael Rolnik 13259d316c75SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ 13269d316c75SMichael Rolnik tcg_gen_sub_tl(R, R, cpu_Cf); 13279d316c75SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 13289d316c75SMichael Rolnik /* update status register */ 13299d316c75SMichael Rolnik gen_sub_CHf(R, Rd, Rr); 13309d316c75SMichael Rolnik gen_sub_Vf(R, Rd, Rr); 13319d316c75SMichael Rolnik gen_NSf(R); 13329d316c75SMichael Rolnik 13339d316c75SMichael Rolnik /* 13349d316c75SMichael Rolnik * Previous value remains unchanged when the result is zero; 13359d316c75SMichael Rolnik * cleared otherwise. 13369d316c75SMichael Rolnik */ 13379d316c75SMichael Rolnik tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); 13389d316c75SMichael Rolnik 13399d316c75SMichael Rolnik tcg_temp_free_i32(zero); 13409d316c75SMichael Rolnik tcg_temp_free_i32(R); 13419d316c75SMichael Rolnik 13429d316c75SMichael Rolnik return true; 13439d316c75SMichael Rolnik } 13449d316c75SMichael Rolnik 13459d316c75SMichael Rolnik /* 13469d316c75SMichael Rolnik * This instruction performs a compare between register Rd and a constant. 13479d316c75SMichael Rolnik * The register is not changed. All conditional branches can be used after this 13489d316c75SMichael Rolnik * instruction. 13499d316c75SMichael Rolnik */ 13509d316c75SMichael Rolnik static bool trans_CPI(DisasContext *ctx, arg_CPI *a) 13519d316c75SMichael Rolnik { 13529d316c75SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 13539d316c75SMichael Rolnik int Imm = a->imm; 13549d316c75SMichael Rolnik TCGv Rr = tcg_const_i32(Imm); 13559d316c75SMichael Rolnik TCGv R = tcg_temp_new_i32(); 13569d316c75SMichael Rolnik 13579d316c75SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ 13589d316c75SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 13599d316c75SMichael Rolnik 13609d316c75SMichael Rolnik /* update status register */ 13619d316c75SMichael Rolnik gen_sub_CHf(R, Rd, Rr); 13629d316c75SMichael Rolnik gen_sub_Vf(R, Rd, Rr); 13639d316c75SMichael Rolnik gen_ZNSf(R); 13649d316c75SMichael Rolnik 13659d316c75SMichael Rolnik tcg_temp_free_i32(R); 13669d316c75SMichael Rolnik tcg_temp_free_i32(Rr); 13679d316c75SMichael Rolnik 13689d316c75SMichael Rolnik return true; 13699d316c75SMichael Rolnik } 13709d316c75SMichael Rolnik 13719d316c75SMichael Rolnik /* 13729d316c75SMichael Rolnik * This instruction tests a single bit in a register and skips the next 13739d316c75SMichael Rolnik * instruction if the bit is cleared. 13749d316c75SMichael Rolnik */ 13759d316c75SMichael Rolnik static bool trans_SBRC(DisasContext *ctx, arg_SBRC *a) 13769d316c75SMichael Rolnik { 13779d316c75SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 13789d316c75SMichael Rolnik 13799d316c75SMichael Rolnik ctx->skip_cond = TCG_COND_EQ; 13809d316c75SMichael Rolnik ctx->skip_var0 = tcg_temp_new(); 13819d316c75SMichael Rolnik ctx->free_skip_var0 = true; 13829d316c75SMichael Rolnik 13839d316c75SMichael Rolnik tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); 13849d316c75SMichael Rolnik return true; 13859d316c75SMichael Rolnik } 13869d316c75SMichael Rolnik 13879d316c75SMichael Rolnik /* 13889d316c75SMichael Rolnik * This instruction tests a single bit in a register and skips the next 13899d316c75SMichael Rolnik * instruction if the bit is set. 13909d316c75SMichael Rolnik */ 13919d316c75SMichael Rolnik static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a) 13929d316c75SMichael Rolnik { 13939d316c75SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 13949d316c75SMichael Rolnik 13959d316c75SMichael Rolnik ctx->skip_cond = TCG_COND_NE; 13969d316c75SMichael Rolnik ctx->skip_var0 = tcg_temp_new(); 13979d316c75SMichael Rolnik ctx->free_skip_var0 = true; 13989d316c75SMichael Rolnik 13999d316c75SMichael Rolnik tcg_gen_andi_tl(ctx->skip_var0, Rr, 1 << a->bit); 14009d316c75SMichael Rolnik return true; 14019d316c75SMichael Rolnik } 14029d316c75SMichael Rolnik 14039d316c75SMichael Rolnik /* 14049d316c75SMichael Rolnik * This instruction tests a single bit in an I/O Register and skips the 14059d316c75SMichael Rolnik * next instruction if the bit is cleared. This instruction operates on the 14069d316c75SMichael Rolnik * lower 32 I/O Registers -- addresses 0-31. 14079d316c75SMichael Rolnik */ 14089d316c75SMichael Rolnik static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) 14099d316c75SMichael Rolnik { 14109d316c75SMichael Rolnik TCGv temp = tcg_const_i32(a->reg); 14119d316c75SMichael Rolnik 14129d316c75SMichael Rolnik gen_helper_inb(temp, cpu_env, temp); 14139d316c75SMichael Rolnik tcg_gen_andi_tl(temp, temp, 1 << a->bit); 14149d316c75SMichael Rolnik ctx->skip_cond = TCG_COND_EQ; 14159d316c75SMichael Rolnik ctx->skip_var0 = temp; 14169d316c75SMichael Rolnik ctx->free_skip_var0 = true; 14179d316c75SMichael Rolnik 14189d316c75SMichael Rolnik return true; 14199d316c75SMichael Rolnik } 14209d316c75SMichael Rolnik 14219d316c75SMichael Rolnik /* 14229d316c75SMichael Rolnik * This instruction tests a single bit in an I/O Register and skips the 14239d316c75SMichael Rolnik * next instruction if the bit is set. This instruction operates on the lower 14249d316c75SMichael Rolnik * 32 I/O Registers -- addresses 0-31. 14259d316c75SMichael Rolnik */ 14269d316c75SMichael Rolnik static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) 14279d316c75SMichael Rolnik { 14289d316c75SMichael Rolnik TCGv temp = tcg_const_i32(a->reg); 14299d316c75SMichael Rolnik 14309d316c75SMichael Rolnik gen_helper_inb(temp, cpu_env, temp); 14319d316c75SMichael Rolnik tcg_gen_andi_tl(temp, temp, 1 << a->bit); 14329d316c75SMichael Rolnik ctx->skip_cond = TCG_COND_NE; 14339d316c75SMichael Rolnik ctx->skip_var0 = temp; 14349d316c75SMichael Rolnik ctx->free_skip_var0 = true; 14359d316c75SMichael Rolnik 14369d316c75SMichael Rolnik return true; 14379d316c75SMichael Rolnik } 14389d316c75SMichael Rolnik 14399d316c75SMichael Rolnik /* 14409d316c75SMichael Rolnik * Conditional relative branch. Tests a single bit in SREG and branches 14419d316c75SMichael Rolnik * relatively to PC if the bit is cleared. This instruction branches relatively 14429d316c75SMichael Rolnik * to PC in either direction (PC - 63 < = destination <= PC + 64). The 14439d316c75SMichael Rolnik * parameter k is the offset from PC and is represented in two's complement 14449d316c75SMichael Rolnik * form. 14459d316c75SMichael Rolnik */ 14469d316c75SMichael Rolnik static bool trans_BRBC(DisasContext *ctx, arg_BRBC *a) 14479d316c75SMichael Rolnik { 14489d316c75SMichael Rolnik TCGLabel *not_taken = gen_new_label(); 14499d316c75SMichael Rolnik 14509d316c75SMichael Rolnik TCGv var; 14519d316c75SMichael Rolnik 14529d316c75SMichael Rolnik switch (a->bit) { 14539d316c75SMichael Rolnik case 0x00: 14549d316c75SMichael Rolnik var = cpu_Cf; 14559d316c75SMichael Rolnik break; 14569d316c75SMichael Rolnik case 0x01: 14579d316c75SMichael Rolnik var = cpu_Zf; 14589d316c75SMichael Rolnik break; 14599d316c75SMichael Rolnik case 0x02: 14609d316c75SMichael Rolnik var = cpu_Nf; 14619d316c75SMichael Rolnik break; 14629d316c75SMichael Rolnik case 0x03: 14639d316c75SMichael Rolnik var = cpu_Vf; 14649d316c75SMichael Rolnik break; 14659d316c75SMichael Rolnik case 0x04: 14669d316c75SMichael Rolnik var = cpu_Sf; 14679d316c75SMichael Rolnik break; 14689d316c75SMichael Rolnik case 0x05: 14699d316c75SMichael Rolnik var = cpu_Hf; 14709d316c75SMichael Rolnik break; 14719d316c75SMichael Rolnik case 0x06: 14729d316c75SMichael Rolnik var = cpu_Tf; 14739d316c75SMichael Rolnik break; 14749d316c75SMichael Rolnik case 0x07: 14759d316c75SMichael Rolnik var = cpu_If; 14769d316c75SMichael Rolnik break; 14779d316c75SMichael Rolnik default: 14789d316c75SMichael Rolnik g_assert_not_reached(); 14799d316c75SMichael Rolnik } 14809d316c75SMichael Rolnik 14819d316c75SMichael Rolnik tcg_gen_brcondi_i32(TCG_COND_NE, var, 0, not_taken); 14829d316c75SMichael Rolnik gen_goto_tb(ctx, 0, ctx->npc + a->imm); 14839d316c75SMichael Rolnik gen_set_label(not_taken); 14849d316c75SMichael Rolnik 148593d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_CHAIN; 14869d316c75SMichael Rolnik return true; 14879d316c75SMichael Rolnik } 14889d316c75SMichael Rolnik 14899d316c75SMichael Rolnik /* 14909d316c75SMichael Rolnik * Conditional relative branch. Tests a single bit in SREG and branches 14919d316c75SMichael Rolnik * relatively to PC if the bit is set. This instruction branches relatively to 14929d316c75SMichael Rolnik * PC in either direction (PC - 63 < = destination <= PC + 64). The parameter k 14939d316c75SMichael Rolnik * is the offset from PC and is represented in two's complement form. 14949d316c75SMichael Rolnik */ 14959d316c75SMichael Rolnik static bool trans_BRBS(DisasContext *ctx, arg_BRBS *a) 14969d316c75SMichael Rolnik { 14979d316c75SMichael Rolnik TCGLabel *not_taken = gen_new_label(); 14989d316c75SMichael Rolnik 14999d316c75SMichael Rolnik TCGv var; 15009d316c75SMichael Rolnik 15019d316c75SMichael Rolnik switch (a->bit) { 15029d316c75SMichael Rolnik case 0x00: 15039d316c75SMichael Rolnik var = cpu_Cf; 15049d316c75SMichael Rolnik break; 15059d316c75SMichael Rolnik case 0x01: 15069d316c75SMichael Rolnik var = cpu_Zf; 15079d316c75SMichael Rolnik break; 15089d316c75SMichael Rolnik case 0x02: 15099d316c75SMichael Rolnik var = cpu_Nf; 15109d316c75SMichael Rolnik break; 15119d316c75SMichael Rolnik case 0x03: 15129d316c75SMichael Rolnik var = cpu_Vf; 15139d316c75SMichael Rolnik break; 15149d316c75SMichael Rolnik case 0x04: 15159d316c75SMichael Rolnik var = cpu_Sf; 15169d316c75SMichael Rolnik break; 15179d316c75SMichael Rolnik case 0x05: 15189d316c75SMichael Rolnik var = cpu_Hf; 15199d316c75SMichael Rolnik break; 15209d316c75SMichael Rolnik case 0x06: 15219d316c75SMichael Rolnik var = cpu_Tf; 15229d316c75SMichael Rolnik break; 15239d316c75SMichael Rolnik case 0x07: 15249d316c75SMichael Rolnik var = cpu_If; 15259d316c75SMichael Rolnik break; 15269d316c75SMichael Rolnik default: 15279d316c75SMichael Rolnik g_assert_not_reached(); 15289d316c75SMichael Rolnik } 15299d316c75SMichael Rolnik 15309d316c75SMichael Rolnik tcg_gen_brcondi_i32(TCG_COND_EQ, var, 0, not_taken); 15319d316c75SMichael Rolnik gen_goto_tb(ctx, 0, ctx->npc + a->imm); 15329d316c75SMichael Rolnik gen_set_label(not_taken); 15339d316c75SMichael Rolnik 153493d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_CHAIN; 15359d316c75SMichael Rolnik return true; 15369d316c75SMichael Rolnik } 15379732b024SMichael Rolnik 15389732b024SMichael Rolnik /* 15399732b024SMichael Rolnik * Data Transfer Instructions 15409732b024SMichael Rolnik */ 15419732b024SMichael Rolnik 15429732b024SMichael Rolnik /* 15439732b024SMichael Rolnik * in the gen_set_addr & gen_get_addr functions 15449732b024SMichael Rolnik * H assumed to be in 0x00ff0000 format 15459732b024SMichael Rolnik * M assumed to be in 0x000000ff format 15469732b024SMichael Rolnik * L assumed to be in 0x000000ff format 15479732b024SMichael Rolnik */ 15489732b024SMichael Rolnik static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L) 15499732b024SMichael Rolnik { 15509732b024SMichael Rolnik 15519732b024SMichael Rolnik tcg_gen_andi_tl(L, addr, 0x000000ff); 15529732b024SMichael Rolnik 15539732b024SMichael Rolnik tcg_gen_andi_tl(M, addr, 0x0000ff00); 15549732b024SMichael Rolnik tcg_gen_shri_tl(M, M, 8); 15559732b024SMichael Rolnik 15569732b024SMichael Rolnik tcg_gen_andi_tl(H, addr, 0x00ff0000); 15579732b024SMichael Rolnik } 15589732b024SMichael Rolnik 15599732b024SMichael Rolnik static void gen_set_xaddr(TCGv addr) 15609732b024SMichael Rolnik { 15619732b024SMichael Rolnik gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]); 15629732b024SMichael Rolnik } 15639732b024SMichael Rolnik 15649732b024SMichael Rolnik static void gen_set_yaddr(TCGv addr) 15659732b024SMichael Rolnik { 15669732b024SMichael Rolnik gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]); 15679732b024SMichael Rolnik } 15689732b024SMichael Rolnik 15699732b024SMichael Rolnik static void gen_set_zaddr(TCGv addr) 15709732b024SMichael Rolnik { 15719732b024SMichael Rolnik gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]); 15729732b024SMichael Rolnik } 15739732b024SMichael Rolnik 15749732b024SMichael Rolnik static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L) 15759732b024SMichael Rolnik { 15769732b024SMichael Rolnik TCGv addr = tcg_temp_new_i32(); 15779732b024SMichael Rolnik 15789732b024SMichael Rolnik tcg_gen_deposit_tl(addr, M, H, 8, 8); 15799732b024SMichael Rolnik tcg_gen_deposit_tl(addr, L, addr, 8, 16); 15809732b024SMichael Rolnik 15819732b024SMichael Rolnik return addr; 15829732b024SMichael Rolnik } 15839732b024SMichael Rolnik 15849732b024SMichael Rolnik static TCGv gen_get_xaddr(void) 15859732b024SMichael Rolnik { 15869732b024SMichael Rolnik return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]); 15879732b024SMichael Rolnik } 15889732b024SMichael Rolnik 15899732b024SMichael Rolnik static TCGv gen_get_yaddr(void) 15909732b024SMichael Rolnik { 15919732b024SMichael Rolnik return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]); 15929732b024SMichael Rolnik } 15939732b024SMichael Rolnik 15949732b024SMichael Rolnik static TCGv gen_get_zaddr(void) 15959732b024SMichael Rolnik { 15969732b024SMichael Rolnik return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]); 15979732b024SMichael Rolnik } 15989732b024SMichael Rolnik 15999732b024SMichael Rolnik /* 16009732b024SMichael Rolnik * Load one byte indirect from data space to register and stores an clear 16019732b024SMichael Rolnik * the bits in data space specified by the register. The instruction can only 16029732b024SMichael Rolnik * be used towards internal SRAM. The data location is pointed to by the Z (16 16039732b024SMichael Rolnik * bits) Pointer Register in the Register File. Memory access is limited to the 16049732b024SMichael Rolnik * current data segment of 64KB. To access another data segment in devices with 16059732b024SMichael Rolnik * more than 64KB data space, the RAMPZ in register in the I/O area has to be 16069732b024SMichael Rolnik * changed. The Z-pointer Register is left unchanged by the operation. This 16079732b024SMichael Rolnik * instruction is especially suited for clearing status bits stored in SRAM. 16089732b024SMichael Rolnik */ 16099732b024SMichael Rolnik static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) 16109732b024SMichael Rolnik { 161193d4d5e4SRichard Henderson if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) { 16129732b024SMichael Rolnik gen_helper_fullwr(cpu_env, data, addr); 16139732b024SMichael Rolnik } else { 16149732b024SMichael Rolnik tcg_gen_qemu_st8(data, addr, MMU_DATA_IDX); /* mem[addr] = data */ 16159732b024SMichael Rolnik } 16169732b024SMichael Rolnik } 16179732b024SMichael Rolnik 16189732b024SMichael Rolnik static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) 16199732b024SMichael Rolnik { 162093d4d5e4SRichard Henderson if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) { 16219732b024SMichael Rolnik gen_helper_fullrd(data, cpu_env, addr); 16229732b024SMichael Rolnik } else { 16239732b024SMichael Rolnik tcg_gen_qemu_ld8u(data, addr, MMU_DATA_IDX); /* data = mem[addr] */ 16249732b024SMichael Rolnik } 16259732b024SMichael Rolnik } 16269732b024SMichael Rolnik 16279732b024SMichael Rolnik /* 16289732b024SMichael Rolnik * This instruction makes a copy of one register into another. The source 16299732b024SMichael Rolnik * register Rr is left unchanged, while the destination register Rd is loaded 16309732b024SMichael Rolnik * with a copy of Rr. 16319732b024SMichael Rolnik */ 16329732b024SMichael Rolnik static bool trans_MOV(DisasContext *ctx, arg_MOV *a) 16339732b024SMichael Rolnik { 16349732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 16359732b024SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 16369732b024SMichael Rolnik 16379732b024SMichael Rolnik tcg_gen_mov_tl(Rd, Rr); 16389732b024SMichael Rolnik 16399732b024SMichael Rolnik return true; 16409732b024SMichael Rolnik } 16419732b024SMichael Rolnik 16429732b024SMichael Rolnik /* 16439732b024SMichael Rolnik * This instruction makes a copy of one register pair into another register 16449732b024SMichael Rolnik * pair. The source register pair Rr+1:Rr is left unchanged, while the 16459732b024SMichael Rolnik * destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr. This 16469732b024SMichael Rolnik * instruction is not available in all devices. Refer to the device specific 16479732b024SMichael Rolnik * instruction set summary. 16489732b024SMichael Rolnik */ 16499732b024SMichael Rolnik static bool trans_MOVW(DisasContext *ctx, arg_MOVW *a) 16509732b024SMichael Rolnik { 16519732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MOVW)) { 16529732b024SMichael Rolnik return true; 16539732b024SMichael Rolnik } 16549732b024SMichael Rolnik 16559732b024SMichael Rolnik TCGv RdL = cpu_r[a->rd]; 16569732b024SMichael Rolnik TCGv RdH = cpu_r[a->rd + 1]; 16579732b024SMichael Rolnik TCGv RrL = cpu_r[a->rr]; 16589732b024SMichael Rolnik TCGv RrH = cpu_r[a->rr + 1]; 16599732b024SMichael Rolnik 16609732b024SMichael Rolnik tcg_gen_mov_tl(RdH, RrH); 16619732b024SMichael Rolnik tcg_gen_mov_tl(RdL, RrL); 16629732b024SMichael Rolnik 16639732b024SMichael Rolnik return true; 16649732b024SMichael Rolnik } 16659732b024SMichael Rolnik 16669732b024SMichael Rolnik /* 16679732b024SMichael Rolnik * Loads an 8 bit constant directly to register 16 to 31. 16689732b024SMichael Rolnik */ 16699732b024SMichael Rolnik static bool trans_LDI(DisasContext *ctx, arg_LDI *a) 16709732b024SMichael Rolnik { 16719732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 16729732b024SMichael Rolnik int imm = a->imm; 16739732b024SMichael Rolnik 16749732b024SMichael Rolnik tcg_gen_movi_tl(Rd, imm); 16759732b024SMichael Rolnik 16769732b024SMichael Rolnik return true; 16779732b024SMichael Rolnik } 16789732b024SMichael Rolnik 16799732b024SMichael Rolnik /* 16809732b024SMichael Rolnik * Loads one byte from the data space to a register. For parts with SRAM, 16819732b024SMichael Rolnik * the data space consists of the Register File, I/O memory and internal SRAM 16829732b024SMichael Rolnik * (and external SRAM if applicable). For parts without SRAM, the data space 16839732b024SMichael Rolnik * consists of the register file only. The EEPROM has a separate address space. 16849732b024SMichael Rolnik * A 16-bit address must be supplied. Memory access is limited to the current 16859732b024SMichael Rolnik * data segment of 64KB. The LDS instruction uses the RAMPD Register to access 16869732b024SMichael Rolnik * memory above 64KB. To access another data segment in devices with more than 16879732b024SMichael Rolnik * 64KB data space, the RAMPD in register in the I/O area has to be changed. 16889732b024SMichael Rolnik * This instruction is not available in all devices. Refer to the device 16899732b024SMichael Rolnik * specific instruction set summary. 16909732b024SMichael Rolnik */ 16919732b024SMichael Rolnik static bool trans_LDS(DisasContext *ctx, arg_LDS *a) 16929732b024SMichael Rolnik { 16939732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 16949732b024SMichael Rolnik TCGv addr = tcg_temp_new_i32(); 16959732b024SMichael Rolnik TCGv H = cpu_rampD; 16969732b024SMichael Rolnik a->imm = next_word(ctx); 16979732b024SMichael Rolnik 16989732b024SMichael Rolnik tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ 16999732b024SMichael Rolnik tcg_gen_shli_tl(addr, addr, 16); 17009732b024SMichael Rolnik tcg_gen_ori_tl(addr, addr, a->imm); 17019732b024SMichael Rolnik 17029732b024SMichael Rolnik gen_data_load(ctx, Rd, addr); 17039732b024SMichael Rolnik 17049732b024SMichael Rolnik tcg_temp_free_i32(addr); 17059732b024SMichael Rolnik 17069732b024SMichael Rolnik return true; 17079732b024SMichael Rolnik } 17089732b024SMichael Rolnik 17099732b024SMichael Rolnik /* 17109732b024SMichael Rolnik * Loads one byte indirect from the data space to a register. For parts 17119732b024SMichael Rolnik * with SRAM, the data space consists of the Register File, I/O memory and 17129732b024SMichael Rolnik * internal SRAM (and external SRAM if applicable). For parts without SRAM, the 17139732b024SMichael Rolnik * data space consists of the Register File only. In some parts the Flash 17149732b024SMichael Rolnik * Memory has been mapped to the data space and can be read using this command. 17159732b024SMichael Rolnik * The EEPROM has a separate address space. The data location is pointed to by 17169732b024SMichael Rolnik * the X (16 bits) Pointer Register in the Register File. Memory access is 17179732b024SMichael Rolnik * limited to the current data segment of 64KB. To access another data segment 17189732b024SMichael Rolnik * in devices with more than 64KB data space, the RAMPX in register in the I/O 17199732b024SMichael Rolnik * area has to be changed. The X-pointer Register can either be left unchanged 17209732b024SMichael Rolnik * by the operation, or it can be post-incremented or predecremented. These 17219732b024SMichael Rolnik * features are especially suited for accessing arrays, tables, and Stack 17229732b024SMichael Rolnik * Pointer usage of the X-pointer Register. Note that only the low byte of the 17239732b024SMichael Rolnik * X-pointer is updated in devices with no more than 256 bytes data space. For 17249732b024SMichael Rolnik * such devices, the high byte of the pointer is not used by this instruction 17259732b024SMichael Rolnik * and can be used for other purposes. The RAMPX Register in the I/O area is 17269732b024SMichael Rolnik * updated in parts with more than 64KB data space or more than 64KB Program 17279732b024SMichael Rolnik * memory, and the increment/decrement is added to the entire 24-bit address on 17289732b024SMichael Rolnik * such devices. Not all variants of this instruction is available in all 17299732b024SMichael Rolnik * devices. Refer to the device specific instruction set summary. In the 17309732b024SMichael Rolnik * Reduced Core tinyAVR the LD instruction can be used to achieve the same 17319732b024SMichael Rolnik * operation as LPM since the program memory is mapped to the data memory 17329732b024SMichael Rolnik * space. 17339732b024SMichael Rolnik */ 17349732b024SMichael Rolnik static bool trans_LDX1(DisasContext *ctx, arg_LDX1 *a) 17359732b024SMichael Rolnik { 17369732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 17379732b024SMichael Rolnik TCGv addr = gen_get_xaddr(); 17389732b024SMichael Rolnik 17399732b024SMichael Rolnik gen_data_load(ctx, Rd, addr); 17409732b024SMichael Rolnik 17419732b024SMichael Rolnik tcg_temp_free_i32(addr); 17429732b024SMichael Rolnik 17439732b024SMichael Rolnik return true; 17449732b024SMichael Rolnik } 17459732b024SMichael Rolnik 17469732b024SMichael Rolnik static bool trans_LDX2(DisasContext *ctx, arg_LDX2 *a) 17479732b024SMichael Rolnik { 17489732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 17499732b024SMichael Rolnik TCGv addr = gen_get_xaddr(); 17509732b024SMichael Rolnik 17519732b024SMichael Rolnik gen_data_load(ctx, Rd, addr); 17529732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ 17539732b024SMichael Rolnik 17549732b024SMichael Rolnik gen_set_xaddr(addr); 17559732b024SMichael Rolnik 17569732b024SMichael Rolnik tcg_temp_free_i32(addr); 17579732b024SMichael Rolnik 17589732b024SMichael Rolnik return true; 17599732b024SMichael Rolnik } 17609732b024SMichael Rolnik 17619732b024SMichael Rolnik static bool trans_LDX3(DisasContext *ctx, arg_LDX3 *a) 17629732b024SMichael Rolnik { 17639732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 17649732b024SMichael Rolnik TCGv addr = gen_get_xaddr(); 17659732b024SMichael Rolnik 17669732b024SMichael Rolnik tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ 17679732b024SMichael Rolnik gen_data_load(ctx, Rd, addr); 17689732b024SMichael Rolnik gen_set_xaddr(addr); 17699732b024SMichael Rolnik 17709732b024SMichael Rolnik tcg_temp_free_i32(addr); 17719732b024SMichael Rolnik 17729732b024SMichael Rolnik return true; 17739732b024SMichael Rolnik } 17749732b024SMichael Rolnik 17759732b024SMichael Rolnik /* 17769732b024SMichael Rolnik * Loads one byte indirect with or without displacement from the data space 17779732b024SMichael Rolnik * to a register. For parts with SRAM, the data space consists of the Register 17789732b024SMichael Rolnik * File, I/O memory and internal SRAM (and external SRAM if applicable). For 17799732b024SMichael Rolnik * parts without SRAM, the data space consists of the Register File only. In 17809732b024SMichael Rolnik * some parts the Flash Memory has been mapped to the data space and can be 17819732b024SMichael Rolnik * read using this command. The EEPROM has a separate address space. The data 17829732b024SMichael Rolnik * location is pointed to by the Y (16 bits) Pointer Register in the Register 17839732b024SMichael Rolnik * File. Memory access is limited to the current data segment of 64KB. To 17849732b024SMichael Rolnik * access another data segment in devices with more than 64KB data space, the 17859732b024SMichael Rolnik * RAMPY in register in the I/O area has to be changed. The Y-pointer Register 17869732b024SMichael Rolnik * can either be left unchanged by the operation, or it can be post-incremented 17879732b024SMichael Rolnik * or predecremented. These features are especially suited for accessing 17889732b024SMichael Rolnik * arrays, tables, and Stack Pointer usage of the Y-pointer Register. Note that 17899732b024SMichael Rolnik * only the low byte of the Y-pointer is updated in devices with no more than 17909732b024SMichael Rolnik * 256 bytes data space. For such devices, the high byte of the pointer is not 17919732b024SMichael Rolnik * used by this instruction and can be used for other purposes. The RAMPY 17929732b024SMichael Rolnik * Register in the I/O area is updated in parts with more than 64KB data space 17939732b024SMichael Rolnik * or more than 64KB Program memory, and the increment/decrement/displacement 17949732b024SMichael Rolnik * is added to the entire 24-bit address on such devices. Not all variants of 17959732b024SMichael Rolnik * this instruction is available in all devices. Refer to the device specific 17969732b024SMichael Rolnik * instruction set summary. In the Reduced Core tinyAVR the LD instruction can 17979732b024SMichael Rolnik * be used to achieve the same operation as LPM since the program memory is 17989732b024SMichael Rolnik * mapped to the data memory space. 17999732b024SMichael Rolnik */ 18009732b024SMichael Rolnik static bool trans_LDY2(DisasContext *ctx, arg_LDY2 *a) 18019732b024SMichael Rolnik { 18029732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 18039732b024SMichael Rolnik TCGv addr = gen_get_yaddr(); 18049732b024SMichael Rolnik 18059732b024SMichael Rolnik gen_data_load(ctx, Rd, addr); 18069732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ 18079732b024SMichael Rolnik 18089732b024SMichael Rolnik gen_set_yaddr(addr); 18099732b024SMichael Rolnik 18109732b024SMichael Rolnik tcg_temp_free_i32(addr); 18119732b024SMichael Rolnik 18129732b024SMichael Rolnik return true; 18139732b024SMichael Rolnik } 18149732b024SMichael Rolnik 18159732b024SMichael Rolnik static bool trans_LDY3(DisasContext *ctx, arg_LDY3 *a) 18169732b024SMichael Rolnik { 18179732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 18189732b024SMichael Rolnik TCGv addr = gen_get_yaddr(); 18199732b024SMichael Rolnik 18209732b024SMichael Rolnik tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ 18219732b024SMichael Rolnik gen_data_load(ctx, Rd, addr); 18229732b024SMichael Rolnik gen_set_yaddr(addr); 18239732b024SMichael Rolnik 18249732b024SMichael Rolnik tcg_temp_free_i32(addr); 18259732b024SMichael Rolnik 18269732b024SMichael Rolnik return true; 18279732b024SMichael Rolnik } 18289732b024SMichael Rolnik 18299732b024SMichael Rolnik static bool trans_LDDY(DisasContext *ctx, arg_LDDY *a) 18309732b024SMichael Rolnik { 18319732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 18329732b024SMichael Rolnik TCGv addr = gen_get_yaddr(); 18339732b024SMichael Rolnik 18349732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ 18359732b024SMichael Rolnik gen_data_load(ctx, Rd, addr); 18369732b024SMichael Rolnik 18379732b024SMichael Rolnik tcg_temp_free_i32(addr); 18389732b024SMichael Rolnik 18399732b024SMichael Rolnik return true; 18409732b024SMichael Rolnik } 18419732b024SMichael Rolnik 18429732b024SMichael Rolnik /* 18439732b024SMichael Rolnik * Loads one byte indirect with or without displacement from the data space 18449732b024SMichael Rolnik * to a register. For parts with SRAM, the data space consists of the Register 18459732b024SMichael Rolnik * File, I/O memory and internal SRAM (and external SRAM if applicable). For 18469732b024SMichael Rolnik * parts without SRAM, the data space consists of the Register File only. In 18479732b024SMichael Rolnik * some parts the Flash Memory has been mapped to the data space and can be 18489732b024SMichael Rolnik * read using this command. The EEPROM has a separate address space. The data 18499732b024SMichael Rolnik * location is pointed to by the Z (16 bits) Pointer Register in the Register 18509732b024SMichael Rolnik * File. Memory access is limited to the current data segment of 64KB. To 18519732b024SMichael Rolnik * access another data segment in devices with more than 64KB data space, the 18529732b024SMichael Rolnik * RAMPZ in register in the I/O area has to be changed. The Z-pointer Register 18539732b024SMichael Rolnik * can either be left unchanged by the operation, or it can be post-incremented 18549732b024SMichael Rolnik * or predecremented. These features are especially suited for Stack Pointer 18559732b024SMichael Rolnik * usage of the Z-pointer Register, however because the Z-pointer Register can 18569732b024SMichael Rolnik * be used for indirect subroutine calls, indirect jumps and table lookup, it 18579732b024SMichael Rolnik * is often more convenient to use the X or Y-pointer as a dedicated Stack 18589732b024SMichael Rolnik * Pointer. Note that only the low byte of the Z-pointer is updated in devices 18599732b024SMichael Rolnik * with no more than 256 bytes data space. For such devices, the high byte of 18609732b024SMichael Rolnik * the pointer is not used by this instruction and can be used for other 18619732b024SMichael Rolnik * purposes. The RAMPZ Register in the I/O area is updated in parts with more 18629732b024SMichael Rolnik * than 64KB data space or more than 64KB Program memory, and the 18639732b024SMichael Rolnik * increment/decrement/displacement is added to the entire 24-bit address on 18649732b024SMichael Rolnik * such devices. Not all variants of this instruction is available in all 18659732b024SMichael Rolnik * devices. Refer to the device specific instruction set summary. In the 18669732b024SMichael Rolnik * Reduced Core tinyAVR the LD instruction can be used to achieve the same 18679732b024SMichael Rolnik * operation as LPM since the program memory is mapped to the data memory 18689732b024SMichael Rolnik * space. For using the Z-pointer for table lookup in Program memory see the 18699732b024SMichael Rolnik * LPM and ELPM instructions. 18709732b024SMichael Rolnik */ 18719732b024SMichael Rolnik static bool trans_LDZ2(DisasContext *ctx, arg_LDZ2 *a) 18729732b024SMichael Rolnik { 18739732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 18749732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 18759732b024SMichael Rolnik 18769732b024SMichael Rolnik gen_data_load(ctx, Rd, addr); 18779732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ 18789732b024SMichael Rolnik 18799732b024SMichael Rolnik gen_set_zaddr(addr); 18809732b024SMichael Rolnik 18819732b024SMichael Rolnik tcg_temp_free_i32(addr); 18829732b024SMichael Rolnik 18839732b024SMichael Rolnik return true; 18849732b024SMichael Rolnik } 18859732b024SMichael Rolnik 18869732b024SMichael Rolnik static bool trans_LDZ3(DisasContext *ctx, arg_LDZ3 *a) 18879732b024SMichael Rolnik { 18889732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 18899732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 18909732b024SMichael Rolnik 18919732b024SMichael Rolnik tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ 18929732b024SMichael Rolnik gen_data_load(ctx, Rd, addr); 18939732b024SMichael Rolnik 18949732b024SMichael Rolnik gen_set_zaddr(addr); 18959732b024SMichael Rolnik 18969732b024SMichael Rolnik tcg_temp_free_i32(addr); 18979732b024SMichael Rolnik 18989732b024SMichael Rolnik return true; 18999732b024SMichael Rolnik } 19009732b024SMichael Rolnik 19019732b024SMichael Rolnik static bool trans_LDDZ(DisasContext *ctx, arg_LDDZ *a) 19029732b024SMichael Rolnik { 19039732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 19049732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 19059732b024SMichael Rolnik 19069732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ 19079732b024SMichael Rolnik gen_data_load(ctx, Rd, addr); 19089732b024SMichael Rolnik 19099732b024SMichael Rolnik tcg_temp_free_i32(addr); 19109732b024SMichael Rolnik 19119732b024SMichael Rolnik return true; 19129732b024SMichael Rolnik } 19139732b024SMichael Rolnik 19149732b024SMichael Rolnik /* 19159732b024SMichael Rolnik * Stores one byte from a Register to the data space. For parts with SRAM, 19169732b024SMichael Rolnik * the data space consists of the Register File, I/O memory and internal SRAM 19179732b024SMichael Rolnik * (and external SRAM if applicable). For parts without SRAM, the data space 19189732b024SMichael Rolnik * consists of the Register File only. The EEPROM has a separate address space. 19199732b024SMichael Rolnik * A 16-bit address must be supplied. Memory access is limited to the current 19209732b024SMichael Rolnik * data segment of 64KB. The STS instruction uses the RAMPD Register to access 19219732b024SMichael Rolnik * memory above 64KB. To access another data segment in devices with more than 19229732b024SMichael Rolnik * 64KB data space, the RAMPD in register in the I/O area has to be changed. 19239732b024SMichael Rolnik * This instruction is not available in all devices. Refer to the device 19249732b024SMichael Rolnik * specific instruction set summary. 19259732b024SMichael Rolnik */ 19269732b024SMichael Rolnik static bool trans_STS(DisasContext *ctx, arg_STS *a) 19279732b024SMichael Rolnik { 19289732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 19299732b024SMichael Rolnik TCGv addr = tcg_temp_new_i32(); 19309732b024SMichael Rolnik TCGv H = cpu_rampD; 19319732b024SMichael Rolnik a->imm = next_word(ctx); 19329732b024SMichael Rolnik 19339732b024SMichael Rolnik tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ 19349732b024SMichael Rolnik tcg_gen_shli_tl(addr, addr, 16); 19359732b024SMichael Rolnik tcg_gen_ori_tl(addr, addr, a->imm); 19369732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 19379732b024SMichael Rolnik 19389732b024SMichael Rolnik tcg_temp_free_i32(addr); 19399732b024SMichael Rolnik 19409732b024SMichael Rolnik return true; 19419732b024SMichael Rolnik } 19429732b024SMichael Rolnik 19439732b024SMichael Rolnik /* 19449732b024SMichael Rolnik * Stores one byte indirect from a register to data space. For parts with SRAM, 19459732b024SMichael Rolnik * the data space consists of the Register File, I/O memory, and internal SRAM 19469732b024SMichael Rolnik * (and external SRAM if applicable). For parts without SRAM, the data space 19479732b024SMichael Rolnik * consists of the Register File only. The EEPROM has a separate address space. 19489732b024SMichael Rolnik * 19499732b024SMichael Rolnik * The data location is pointed to by the X (16 bits) Pointer Register in the 19509732b024SMichael Rolnik * Register File. Memory access is limited to the current data segment of 64KB. 19519732b024SMichael Rolnik * To access another data segment in devices with more than 64KB data space, the 19529732b024SMichael Rolnik * RAMPX in register in the I/O area has to be changed. 19539732b024SMichael Rolnik * 19549732b024SMichael Rolnik * The X-pointer Register can either be left unchanged by the operation, or it 19559732b024SMichael Rolnik * can be post-incremented or pre-decremented. These features are especially 19569732b024SMichael Rolnik * suited for accessing arrays, tables, and Stack Pointer usage of the 19579732b024SMichael Rolnik * X-pointer Register. Note that only the low byte of the X-pointer is updated 19589732b024SMichael Rolnik * in devices with no more than 256 bytes data space. For such devices, the high 19599732b024SMichael Rolnik * byte of the pointer is not used by this instruction and can be used for other 19609732b024SMichael Rolnik * purposes. The RAMPX Register in the I/O area is updated in parts with more 19619732b024SMichael Rolnik * than 64KB data space or more than 64KB Program memory, and the increment / 19629732b024SMichael Rolnik * decrement is added to the entire 24-bit address on such devices. 19639732b024SMichael Rolnik */ 19649732b024SMichael Rolnik static bool trans_STX1(DisasContext *ctx, arg_STX1 *a) 19659732b024SMichael Rolnik { 19669732b024SMichael Rolnik TCGv Rd = cpu_r[a->rr]; 19679732b024SMichael Rolnik TCGv addr = gen_get_xaddr(); 19689732b024SMichael Rolnik 19699732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 19709732b024SMichael Rolnik 19719732b024SMichael Rolnik tcg_temp_free_i32(addr); 19729732b024SMichael Rolnik 19739732b024SMichael Rolnik return true; 19749732b024SMichael Rolnik } 19759732b024SMichael Rolnik 19769732b024SMichael Rolnik static bool trans_STX2(DisasContext *ctx, arg_STX2 *a) 19779732b024SMichael Rolnik { 19789732b024SMichael Rolnik TCGv Rd = cpu_r[a->rr]; 19799732b024SMichael Rolnik TCGv addr = gen_get_xaddr(); 19809732b024SMichael Rolnik 19819732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 19829732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ 19839732b024SMichael Rolnik gen_set_xaddr(addr); 19849732b024SMichael Rolnik 19859732b024SMichael Rolnik tcg_temp_free_i32(addr); 19869732b024SMichael Rolnik 19879732b024SMichael Rolnik return true; 19889732b024SMichael Rolnik } 19899732b024SMichael Rolnik 19909732b024SMichael Rolnik static bool trans_STX3(DisasContext *ctx, arg_STX3 *a) 19919732b024SMichael Rolnik { 19929732b024SMichael Rolnik TCGv Rd = cpu_r[a->rr]; 19939732b024SMichael Rolnik TCGv addr = gen_get_xaddr(); 19949732b024SMichael Rolnik 19959732b024SMichael Rolnik tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ 19969732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 19979732b024SMichael Rolnik gen_set_xaddr(addr); 19989732b024SMichael Rolnik 19999732b024SMichael Rolnik tcg_temp_free_i32(addr); 20009732b024SMichael Rolnik 20019732b024SMichael Rolnik return true; 20029732b024SMichael Rolnik } 20039732b024SMichael Rolnik 20049732b024SMichael Rolnik /* 20059732b024SMichael Rolnik * Stores one byte indirect with or without displacement from a register to data 20069732b024SMichael Rolnik * space. For parts with SRAM, the data space consists of the Register File, I/O 20079732b024SMichael Rolnik * memory, and internal SRAM (and external SRAM if applicable). For parts 20089732b024SMichael Rolnik * without SRAM, the data space consists of the Register File only. The EEPROM 20099732b024SMichael Rolnik * has a separate address space. 20109732b024SMichael Rolnik * 20119732b024SMichael Rolnik * The data location is pointed to by the Y (16 bits) Pointer Register in the 20129732b024SMichael Rolnik * Register File. Memory access is limited to the current data segment of 64KB. 20139732b024SMichael Rolnik * To access another data segment in devices with more than 64KB data space, the 20149732b024SMichael Rolnik * RAMPY in register in the I/O area has to be changed. 20159732b024SMichael Rolnik * 20169732b024SMichael Rolnik * The Y-pointer Register can either be left unchanged by the operation, or it 20179732b024SMichael Rolnik * can be post-incremented or pre-decremented. These features are especially 20189732b024SMichael Rolnik * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer 20199732b024SMichael Rolnik * Register. Note that only the low byte of the Y-pointer is updated in devices 20209732b024SMichael Rolnik * with no more than 256 bytes data space. For such devices, the high byte of 20219732b024SMichael Rolnik * the pointer is not used by this instruction and can be used for other 20229732b024SMichael Rolnik * purposes. The RAMPY Register in the I/O area is updated in parts with more 20239732b024SMichael Rolnik * than 64KB data space or more than 64KB Program memory, and the increment / 20249732b024SMichael Rolnik * decrement / displacement is added to the entire 24-bit address on such 20259732b024SMichael Rolnik * devices. 20269732b024SMichael Rolnik */ 20279732b024SMichael Rolnik static bool trans_STY2(DisasContext *ctx, arg_STY2 *a) 20289732b024SMichael Rolnik { 20299732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 20309732b024SMichael Rolnik TCGv addr = gen_get_yaddr(); 20319732b024SMichael Rolnik 20329732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 20339732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ 20349732b024SMichael Rolnik gen_set_yaddr(addr); 20359732b024SMichael Rolnik 20369732b024SMichael Rolnik tcg_temp_free_i32(addr); 20379732b024SMichael Rolnik 20389732b024SMichael Rolnik return true; 20399732b024SMichael Rolnik } 20409732b024SMichael Rolnik 20419732b024SMichael Rolnik static bool trans_STY3(DisasContext *ctx, arg_STY3 *a) 20429732b024SMichael Rolnik { 20439732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 20449732b024SMichael Rolnik TCGv addr = gen_get_yaddr(); 20459732b024SMichael Rolnik 20469732b024SMichael Rolnik tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ 20479732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 20489732b024SMichael Rolnik gen_set_yaddr(addr); 20499732b024SMichael Rolnik 20509732b024SMichael Rolnik tcg_temp_free_i32(addr); 20519732b024SMichael Rolnik 20529732b024SMichael Rolnik return true; 20539732b024SMichael Rolnik } 20549732b024SMichael Rolnik 20559732b024SMichael Rolnik static bool trans_STDY(DisasContext *ctx, arg_STDY *a) 20569732b024SMichael Rolnik { 20579732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 20589732b024SMichael Rolnik TCGv addr = gen_get_yaddr(); 20599732b024SMichael Rolnik 20609732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ 20619732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 20629732b024SMichael Rolnik 20639732b024SMichael Rolnik tcg_temp_free_i32(addr); 20649732b024SMichael Rolnik 20659732b024SMichael Rolnik return true; 20669732b024SMichael Rolnik } 20679732b024SMichael Rolnik 20689732b024SMichael Rolnik /* 20699732b024SMichael Rolnik * Stores one byte indirect with or without displacement from a register to data 20709732b024SMichael Rolnik * space. For parts with SRAM, the data space consists of the Register File, I/O 20719732b024SMichael Rolnik * memory, and internal SRAM (and external SRAM if applicable). For parts 20729732b024SMichael Rolnik * without SRAM, the data space consists of the Register File only. The EEPROM 20739732b024SMichael Rolnik * has a separate address space. 20749732b024SMichael Rolnik * 20759732b024SMichael Rolnik * The data location is pointed to by the Y (16 bits) Pointer Register in the 20769732b024SMichael Rolnik * Register File. Memory access is limited to the current data segment of 64KB. 20779732b024SMichael Rolnik * To access another data segment in devices with more than 64KB data space, the 20789732b024SMichael Rolnik * RAMPY in register in the I/O area has to be changed. 20799732b024SMichael Rolnik * 20809732b024SMichael Rolnik * The Y-pointer Register can either be left unchanged by the operation, or it 20819732b024SMichael Rolnik * can be post-incremented or pre-decremented. These features are especially 20829732b024SMichael Rolnik * suited for accessing arrays, tables, and Stack Pointer usage of the Y-pointer 20839732b024SMichael Rolnik * Register. Note that only the low byte of the Y-pointer is updated in devices 20849732b024SMichael Rolnik * with no more than 256 bytes data space. For such devices, the high byte of 20859732b024SMichael Rolnik * the pointer is not used by this instruction and can be used for other 20869732b024SMichael Rolnik * purposes. The RAMPY Register in the I/O area is updated in parts with more 20879732b024SMichael Rolnik * than 64KB data space or more than 64KB Program memory, and the increment / 20889732b024SMichael Rolnik * decrement / displacement is added to the entire 24-bit address on such 20899732b024SMichael Rolnik * devices. 20909732b024SMichael Rolnik */ 20919732b024SMichael Rolnik static bool trans_STZ2(DisasContext *ctx, arg_STZ2 *a) 20929732b024SMichael Rolnik { 20939732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 20949732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 20959732b024SMichael Rolnik 20969732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 20979732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ 20989732b024SMichael Rolnik 20999732b024SMichael Rolnik gen_set_zaddr(addr); 21009732b024SMichael Rolnik 21019732b024SMichael Rolnik tcg_temp_free_i32(addr); 21029732b024SMichael Rolnik 21039732b024SMichael Rolnik return true; 21049732b024SMichael Rolnik } 21059732b024SMichael Rolnik 21069732b024SMichael Rolnik static bool trans_STZ3(DisasContext *ctx, arg_STZ3 *a) 21079732b024SMichael Rolnik { 21089732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 21099732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 21109732b024SMichael Rolnik 21119732b024SMichael Rolnik tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */ 21129732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 21139732b024SMichael Rolnik 21149732b024SMichael Rolnik gen_set_zaddr(addr); 21159732b024SMichael Rolnik 21169732b024SMichael Rolnik tcg_temp_free_i32(addr); 21179732b024SMichael Rolnik 21189732b024SMichael Rolnik return true; 21199732b024SMichael Rolnik } 21209732b024SMichael Rolnik 21219732b024SMichael Rolnik static bool trans_STDZ(DisasContext *ctx, arg_STDZ *a) 21229732b024SMichael Rolnik { 21239732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 21249732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 21259732b024SMichael Rolnik 21269732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, a->imm); /* addr = addr + q */ 21279732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 21289732b024SMichael Rolnik 21299732b024SMichael Rolnik tcg_temp_free_i32(addr); 21309732b024SMichael Rolnik 21319732b024SMichael Rolnik return true; 21329732b024SMichael Rolnik } 21339732b024SMichael Rolnik 21349732b024SMichael Rolnik /* 21359732b024SMichael Rolnik * Loads one byte pointed to by the Z-register into the destination 21369732b024SMichael Rolnik * register Rd. This instruction features a 100% space effective constant 21379732b024SMichael Rolnik * initialization or constant data fetch. The Program memory is organized in 21389732b024SMichael Rolnik * 16-bit words while the Z-pointer is a byte address. Thus, the least 21399732b024SMichael Rolnik * significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high 21409732b024SMichael Rolnik * byte (ZLSB = 1). This instruction can address the first 64KB (32K words) of 21419732b024SMichael Rolnik * Program memory. The Zpointer Register can either be left unchanged by the 21429732b024SMichael Rolnik * operation, or it can be incremented. The incrementation does not apply to 21439732b024SMichael Rolnik * the RAMPZ Register. 21449732b024SMichael Rolnik * 21459732b024SMichael Rolnik * Devices with Self-Programming capability can use the LPM instruction to read 21469732b024SMichael Rolnik * the Fuse and Lock bit values. 21479732b024SMichael Rolnik */ 21489732b024SMichael Rolnik static bool trans_LPM1(DisasContext *ctx, arg_LPM1 *a) 21499732b024SMichael Rolnik { 21509732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { 21519732b024SMichael Rolnik return true; 21529732b024SMichael Rolnik } 21539732b024SMichael Rolnik 21549732b024SMichael Rolnik TCGv Rd = cpu_r[0]; 21559732b024SMichael Rolnik TCGv addr = tcg_temp_new_i32(); 21569732b024SMichael Rolnik TCGv H = cpu_r[31]; 21579732b024SMichael Rolnik TCGv L = cpu_r[30]; 21589732b024SMichael Rolnik 21599732b024SMichael Rolnik tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ 21609732b024SMichael Rolnik tcg_gen_or_tl(addr, addr, L); 21619732b024SMichael Rolnik tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ 21629732b024SMichael Rolnik 21639732b024SMichael Rolnik tcg_temp_free_i32(addr); 21649732b024SMichael Rolnik 21659732b024SMichael Rolnik return true; 21669732b024SMichael Rolnik } 21679732b024SMichael Rolnik 21689732b024SMichael Rolnik static bool trans_LPM2(DisasContext *ctx, arg_LPM2 *a) 21699732b024SMichael Rolnik { 21709732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_LPM)) { 21719732b024SMichael Rolnik return true; 21729732b024SMichael Rolnik } 21739732b024SMichael Rolnik 21749732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 21759732b024SMichael Rolnik TCGv addr = tcg_temp_new_i32(); 21769732b024SMichael Rolnik TCGv H = cpu_r[31]; 21779732b024SMichael Rolnik TCGv L = cpu_r[30]; 21789732b024SMichael Rolnik 21799732b024SMichael Rolnik tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ 21809732b024SMichael Rolnik tcg_gen_or_tl(addr, addr, L); 21819732b024SMichael Rolnik tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ 21829732b024SMichael Rolnik 21839732b024SMichael Rolnik tcg_temp_free_i32(addr); 21849732b024SMichael Rolnik 21859732b024SMichael Rolnik return true; 21869732b024SMichael Rolnik } 21879732b024SMichael Rolnik 21889732b024SMichael Rolnik static bool trans_LPMX(DisasContext *ctx, arg_LPMX *a) 21899732b024SMichael Rolnik { 21909732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_LPMX)) { 21919732b024SMichael Rolnik return true; 21929732b024SMichael Rolnik } 21939732b024SMichael Rolnik 21949732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 21959732b024SMichael Rolnik TCGv addr = tcg_temp_new_i32(); 21969732b024SMichael Rolnik TCGv H = cpu_r[31]; 21979732b024SMichael Rolnik TCGv L = cpu_r[30]; 21989732b024SMichael Rolnik 21999732b024SMichael Rolnik tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */ 22009732b024SMichael Rolnik tcg_gen_or_tl(addr, addr, L); 22019732b024SMichael Rolnik tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ 22029732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ 22039732b024SMichael Rolnik tcg_gen_andi_tl(L, addr, 0xff); 22049732b024SMichael Rolnik tcg_gen_shri_tl(addr, addr, 8); 22059732b024SMichael Rolnik tcg_gen_andi_tl(H, addr, 0xff); 22069732b024SMichael Rolnik 22079732b024SMichael Rolnik tcg_temp_free_i32(addr); 22089732b024SMichael Rolnik 22099732b024SMichael Rolnik return true; 22109732b024SMichael Rolnik } 22119732b024SMichael Rolnik 22129732b024SMichael Rolnik /* 22139732b024SMichael Rolnik * Loads one byte pointed to by the Z-register and the RAMPZ Register in 22149732b024SMichael Rolnik * the I/O space, and places this byte in the destination register Rd. This 22159732b024SMichael Rolnik * instruction features a 100% space effective constant initialization or 22169732b024SMichael Rolnik * constant data fetch. The Program memory is organized in 16-bit words while 22179732b024SMichael Rolnik * the Z-pointer is a byte address. Thus, the least significant bit of the 22189732b024SMichael Rolnik * Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This 22199732b024SMichael Rolnik * instruction can address the entire Program memory space. The Z-pointer 22209732b024SMichael Rolnik * Register can either be left unchanged by the operation, or it can be 22219732b024SMichael Rolnik * incremented. The incrementation applies to the entire 24-bit concatenation 22229732b024SMichael Rolnik * of the RAMPZ and Z-pointer Registers. 22239732b024SMichael Rolnik * 22249732b024SMichael Rolnik * Devices with Self-Programming capability can use the ELPM instruction to 22259732b024SMichael Rolnik * read the Fuse and Lock bit value. 22269732b024SMichael Rolnik */ 22279732b024SMichael Rolnik static bool trans_ELPM1(DisasContext *ctx, arg_ELPM1 *a) 22289732b024SMichael Rolnik { 22299732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { 22309732b024SMichael Rolnik return true; 22319732b024SMichael Rolnik } 22329732b024SMichael Rolnik 22339732b024SMichael Rolnik TCGv Rd = cpu_r[0]; 22349732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 22359732b024SMichael Rolnik 22369732b024SMichael Rolnik tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ 22379732b024SMichael Rolnik 22389732b024SMichael Rolnik tcg_temp_free_i32(addr); 22399732b024SMichael Rolnik 22409732b024SMichael Rolnik return true; 22419732b024SMichael Rolnik } 22429732b024SMichael Rolnik 22439732b024SMichael Rolnik static bool trans_ELPM2(DisasContext *ctx, arg_ELPM2 *a) 22449732b024SMichael Rolnik { 22459732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_ELPM)) { 22469732b024SMichael Rolnik return true; 22479732b024SMichael Rolnik } 22489732b024SMichael Rolnik 22499732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 22509732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 22519732b024SMichael Rolnik 22529732b024SMichael Rolnik tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ 22539732b024SMichael Rolnik 22549732b024SMichael Rolnik tcg_temp_free_i32(addr); 22559732b024SMichael Rolnik 22569732b024SMichael Rolnik return true; 22579732b024SMichael Rolnik } 22589732b024SMichael Rolnik 22599732b024SMichael Rolnik static bool trans_ELPMX(DisasContext *ctx, arg_ELPMX *a) 22609732b024SMichael Rolnik { 22619732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_ELPMX)) { 22629732b024SMichael Rolnik return true; 22639732b024SMichael Rolnik } 22649732b024SMichael Rolnik 22659732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 22669732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 22679732b024SMichael Rolnik 22689732b024SMichael Rolnik tcg_gen_qemu_ld8u(Rd, addr, MMU_CODE_IDX); /* Rd = mem[addr] */ 22699732b024SMichael Rolnik tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */ 22709732b024SMichael Rolnik gen_set_zaddr(addr); 22719732b024SMichael Rolnik 22729732b024SMichael Rolnik tcg_temp_free_i32(addr); 22739732b024SMichael Rolnik 22749732b024SMichael Rolnik return true; 22759732b024SMichael Rolnik } 22769732b024SMichael Rolnik 22779732b024SMichael Rolnik /* 22789732b024SMichael Rolnik * SPM can be used to erase a page in the Program memory, to write a page 22799732b024SMichael Rolnik * in the Program memory (that is already erased), and to set Boot Loader Lock 22809732b024SMichael Rolnik * bits. In some devices, the Program memory can be written one word at a time, 22819732b024SMichael Rolnik * in other devices an entire page can be programmed simultaneously after first 22829732b024SMichael Rolnik * filling a temporary page buffer. In all cases, the Program memory must be 22839732b024SMichael Rolnik * erased one page at a time. When erasing the Program memory, the RAMPZ and 22849732b024SMichael Rolnik * Z-register are used as page address. When writing the Program memory, the 22859732b024SMichael Rolnik * RAMPZ and Z-register are used as page or word address, and the R1:R0 22869732b024SMichael Rolnik * register pair is used as data(1). When setting the Boot Loader Lock bits, 22879732b024SMichael Rolnik * the R1:R0 register pair is used as data. Refer to the device documentation 22889732b024SMichael Rolnik * for detailed description of SPM usage. This instruction can address the 22899732b024SMichael Rolnik * entire Program memory. 22909732b024SMichael Rolnik * 22919732b024SMichael Rolnik * The SPM instruction is not available in all devices. Refer to the device 22929732b024SMichael Rolnik * specific instruction set summary. 22939732b024SMichael Rolnik * 22949732b024SMichael Rolnik * Note: 1. R1 determines the instruction high byte, and R0 determines the 22959732b024SMichael Rolnik * instruction low byte. 22969732b024SMichael Rolnik */ 22979732b024SMichael Rolnik static bool trans_SPM(DisasContext *ctx, arg_SPM *a) 22989732b024SMichael Rolnik { 22999732b024SMichael Rolnik /* TODO */ 23009732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_SPM)) { 23019732b024SMichael Rolnik return true; 23029732b024SMichael Rolnik } 23039732b024SMichael Rolnik 23049732b024SMichael Rolnik return true; 23059732b024SMichael Rolnik } 23069732b024SMichael Rolnik 23079732b024SMichael Rolnik static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a) 23089732b024SMichael Rolnik { 23099732b024SMichael Rolnik /* TODO */ 23109732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_SPMX)) { 23119732b024SMichael Rolnik return true; 23129732b024SMichael Rolnik } 23139732b024SMichael Rolnik 23149732b024SMichael Rolnik return true; 23159732b024SMichael Rolnik } 23169732b024SMichael Rolnik 23179732b024SMichael Rolnik /* 23189732b024SMichael Rolnik * Loads data from the I/O Space (Ports, Timers, Configuration Registers, 23199732b024SMichael Rolnik * etc.) into register Rd in the Register File. 23209732b024SMichael Rolnik */ 23219732b024SMichael Rolnik static bool trans_IN(DisasContext *ctx, arg_IN *a) 23229732b024SMichael Rolnik { 23239732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 23249732b024SMichael Rolnik TCGv port = tcg_const_i32(a->imm); 23259732b024SMichael Rolnik 23269732b024SMichael Rolnik gen_helper_inb(Rd, cpu_env, port); 23279732b024SMichael Rolnik 23289732b024SMichael Rolnik tcg_temp_free_i32(port); 23299732b024SMichael Rolnik 23309732b024SMichael Rolnik return true; 23319732b024SMichael Rolnik } 23329732b024SMichael Rolnik 23339732b024SMichael Rolnik /* 23349732b024SMichael Rolnik * Stores data from register Rr in the Register File to I/O Space (Ports, 23359732b024SMichael Rolnik * Timers, Configuration Registers, etc.). 23369732b024SMichael Rolnik */ 23379732b024SMichael Rolnik static bool trans_OUT(DisasContext *ctx, arg_OUT *a) 23389732b024SMichael Rolnik { 23399732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 23409732b024SMichael Rolnik TCGv port = tcg_const_i32(a->imm); 23419732b024SMichael Rolnik 23429732b024SMichael Rolnik gen_helper_outb(cpu_env, port, Rd); 23439732b024SMichael Rolnik 23449732b024SMichael Rolnik tcg_temp_free_i32(port); 23459732b024SMichael Rolnik 23469732b024SMichael Rolnik return true; 23479732b024SMichael Rolnik } 23489732b024SMichael Rolnik 23499732b024SMichael Rolnik /* 23509732b024SMichael Rolnik * This instruction stores the contents of register Rr on the STACK. The 23519732b024SMichael Rolnik * Stack Pointer is post-decremented by 1 after the PUSH. This instruction is 23529732b024SMichael Rolnik * not available in all devices. Refer to the device specific instruction set 23539732b024SMichael Rolnik * summary. 23549732b024SMichael Rolnik */ 23559732b024SMichael Rolnik static bool trans_PUSH(DisasContext *ctx, arg_PUSH *a) 23569732b024SMichael Rolnik { 23579732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 23589732b024SMichael Rolnik 23599732b024SMichael Rolnik gen_data_store(ctx, Rd, cpu_sp); 23609732b024SMichael Rolnik tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); 23619732b024SMichael Rolnik 23629732b024SMichael Rolnik return true; 23639732b024SMichael Rolnik } 23649732b024SMichael Rolnik 23659732b024SMichael Rolnik /* 23669732b024SMichael Rolnik * This instruction loads register Rd with a byte from the STACK. The Stack 23679732b024SMichael Rolnik * Pointer is pre-incremented by 1 before the POP. This instruction is not 23689732b024SMichael Rolnik * available in all devices. Refer to the device specific instruction set 23699732b024SMichael Rolnik * summary. 23709732b024SMichael Rolnik */ 23719732b024SMichael Rolnik static bool trans_POP(DisasContext *ctx, arg_POP *a) 23729732b024SMichael Rolnik { 23739732b024SMichael Rolnik /* 23749732b024SMichael Rolnik * Using a temp to work around some strange behaviour: 23759732b024SMichael Rolnik * tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); 23769732b024SMichael Rolnik * gen_data_load(ctx, Rd, cpu_sp); 23779732b024SMichael Rolnik * seems to cause the add to happen twice. 23789732b024SMichael Rolnik * This doesn't happen if either the add or the load is removed. 23799732b024SMichael Rolnik */ 23809732b024SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 23819732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 23829732b024SMichael Rolnik 23839732b024SMichael Rolnik tcg_gen_addi_tl(t1, cpu_sp, 1); 23849732b024SMichael Rolnik gen_data_load(ctx, Rd, t1); 23859732b024SMichael Rolnik tcg_gen_mov_tl(cpu_sp, t1); 23869732b024SMichael Rolnik 23879732b024SMichael Rolnik return true; 23889732b024SMichael Rolnik } 23899732b024SMichael Rolnik 23909732b024SMichael Rolnik /* 23919732b024SMichael Rolnik * Exchanges one byte indirect between register and data space. The data 23929732b024SMichael Rolnik * location is pointed to by the Z (16 bits) Pointer Register in the Register 23939732b024SMichael Rolnik * File. Memory access is limited to the current data segment of 64KB. To 23949732b024SMichael Rolnik * access another data segment in devices with more than 64KB data space, the 23959732b024SMichael Rolnik * RAMPZ in register in the I/O area has to be changed. 23969732b024SMichael Rolnik * 23979732b024SMichael Rolnik * The Z-pointer Register is left unchanged by the operation. This instruction 23989732b024SMichael Rolnik * is especially suited for writing/reading status bits stored in SRAM. 23999732b024SMichael Rolnik */ 24009732b024SMichael Rolnik static bool trans_XCH(DisasContext *ctx, arg_XCH *a) 24019732b024SMichael Rolnik { 24029732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { 24039732b024SMichael Rolnik return true; 24049732b024SMichael Rolnik } 24059732b024SMichael Rolnik 24069732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 24079732b024SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 24089732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 24099732b024SMichael Rolnik 24109732b024SMichael Rolnik gen_data_load(ctx, t0, addr); 24119732b024SMichael Rolnik gen_data_store(ctx, Rd, addr); 24129732b024SMichael Rolnik tcg_gen_mov_tl(Rd, t0); 24139732b024SMichael Rolnik 24149732b024SMichael Rolnik tcg_temp_free_i32(t0); 24159732b024SMichael Rolnik tcg_temp_free_i32(addr); 24169732b024SMichael Rolnik 24179732b024SMichael Rolnik return true; 24189732b024SMichael Rolnik } 24199732b024SMichael Rolnik 24209732b024SMichael Rolnik /* 24219732b024SMichael Rolnik * Load one byte indirect from data space to register and set bits in data 24229732b024SMichael Rolnik * space specified by the register. The instruction can only be used towards 24239732b024SMichael Rolnik * internal SRAM. The data location is pointed to by the Z (16 bits) Pointer 24249732b024SMichael Rolnik * Register in the Register File. Memory access is limited to the current data 24259732b024SMichael Rolnik * segment of 64KB. To access another data segment in devices with more than 24269732b024SMichael Rolnik * 64KB data space, the RAMPZ in register in the I/O area has to be changed. 24279732b024SMichael Rolnik * 24289732b024SMichael Rolnik * The Z-pointer Register is left unchanged by the operation. This instruction 24299732b024SMichael Rolnik * is especially suited for setting status bits stored in SRAM. 24309732b024SMichael Rolnik */ 24319732b024SMichael Rolnik static bool trans_LAS(DisasContext *ctx, arg_LAS *a) 24329732b024SMichael Rolnik { 24339732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { 24349732b024SMichael Rolnik return true; 24359732b024SMichael Rolnik } 24369732b024SMichael Rolnik 24379732b024SMichael Rolnik TCGv Rr = cpu_r[a->rd]; 24389732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 24399732b024SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 24409732b024SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 24419732b024SMichael Rolnik 24429732b024SMichael Rolnik gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ 24439732b024SMichael Rolnik tcg_gen_or_tl(t1, t0, Rr); 24449732b024SMichael Rolnik tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */ 24459732b024SMichael Rolnik gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ 24469732b024SMichael Rolnik 24479732b024SMichael Rolnik tcg_temp_free_i32(t1); 24489732b024SMichael Rolnik tcg_temp_free_i32(t0); 24499732b024SMichael Rolnik tcg_temp_free_i32(addr); 24509732b024SMichael Rolnik 24519732b024SMichael Rolnik return true; 24529732b024SMichael Rolnik } 24539732b024SMichael Rolnik 24549732b024SMichael Rolnik /* 24559732b024SMichael Rolnik * Load one byte indirect from data space to register and stores and clear 24569732b024SMichael Rolnik * the bits in data space specified by the register. The instruction can 24579732b024SMichael Rolnik * only be used towards internal SRAM. The data location is pointed to by 24589732b024SMichael Rolnik * the Z (16 bits) Pointer Register in the Register File. Memory access is 24599732b024SMichael Rolnik * limited to the current data segment of 64KB. To access another data 24609732b024SMichael Rolnik * segment in devices with more than 64KB data space, the RAMPZ in register 24619732b024SMichael Rolnik * in the I/O area has to be changed. 24629732b024SMichael Rolnik * 24639732b024SMichael Rolnik * The Z-pointer Register is left unchanged by the operation. This instruction 24649732b024SMichael Rolnik * is especially suited for clearing status bits stored in SRAM. 24659732b024SMichael Rolnik */ 24669732b024SMichael Rolnik static bool trans_LAC(DisasContext *ctx, arg_LAC *a) 24679732b024SMichael Rolnik { 24689732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { 24699732b024SMichael Rolnik return true; 24709732b024SMichael Rolnik } 24719732b024SMichael Rolnik 24729732b024SMichael Rolnik TCGv Rr = cpu_r[a->rd]; 24739732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 24749732b024SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 24759732b024SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 24769732b024SMichael Rolnik 24779732b024SMichael Rolnik gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ 24789732b024SMichael Rolnik tcg_gen_andc_tl(t1, t0, Rr); /* t1 = t0 & (0xff - Rr) = t0 & ~Rr */ 24799732b024SMichael Rolnik tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */ 24809732b024SMichael Rolnik gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ 24819732b024SMichael Rolnik 24829732b024SMichael Rolnik tcg_temp_free_i32(t1); 24839732b024SMichael Rolnik tcg_temp_free_i32(t0); 24849732b024SMichael Rolnik tcg_temp_free_i32(addr); 24859732b024SMichael Rolnik 24869732b024SMichael Rolnik return true; 24879732b024SMichael Rolnik } 24889732b024SMichael Rolnik 24899732b024SMichael Rolnik 24909732b024SMichael Rolnik /* 24919732b024SMichael Rolnik * Load one byte indirect from data space to register and toggles bits in 24929732b024SMichael Rolnik * the data space specified by the register. The instruction can only be used 24939732b024SMichael Rolnik * towards SRAM. The data location is pointed to by the Z (16 bits) Pointer 24949732b024SMichael Rolnik * Register in the Register File. Memory access is limited to the current data 24959732b024SMichael Rolnik * segment of 64KB. To access another data segment in devices with more than 24969732b024SMichael Rolnik * 64KB data space, the RAMPZ in register in the I/O area has to be changed. 24979732b024SMichael Rolnik * 24989732b024SMichael Rolnik * The Z-pointer Register is left unchanged by the operation. This instruction 24999732b024SMichael Rolnik * is especially suited for changing status bits stored in SRAM. 25009732b024SMichael Rolnik */ 25019732b024SMichael Rolnik static bool trans_LAT(DisasContext *ctx, arg_LAT *a) 25029732b024SMichael Rolnik { 25039732b024SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_RMW)) { 25049732b024SMichael Rolnik return true; 25059732b024SMichael Rolnik } 25069732b024SMichael Rolnik 25079732b024SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 25089732b024SMichael Rolnik TCGv addr = gen_get_zaddr(); 25099732b024SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 25109732b024SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 25119732b024SMichael Rolnik 25129732b024SMichael Rolnik gen_data_load(ctx, t0, addr); /* t0 = mem[addr] */ 25139732b024SMichael Rolnik tcg_gen_xor_tl(t1, t0, Rd); 25149732b024SMichael Rolnik tcg_gen_mov_tl(Rd, t0); /* Rd = t0 */ 25159732b024SMichael Rolnik gen_data_store(ctx, t1, addr); /* mem[addr] = t1 */ 25169732b024SMichael Rolnik 25179732b024SMichael Rolnik tcg_temp_free_i32(t1); 25189732b024SMichael Rolnik tcg_temp_free_i32(t0); 25199732b024SMichael Rolnik tcg_temp_free_i32(addr); 25209732b024SMichael Rolnik 25219732b024SMichael Rolnik return true; 25229732b024SMichael Rolnik } 25235718cef0SMichael Rolnik 25245718cef0SMichael Rolnik /* 25255718cef0SMichael Rolnik * Bit and Bit-test Instructions 25265718cef0SMichael Rolnik */ 25275718cef0SMichael Rolnik static void gen_rshift_ZNVSf(TCGv R) 25285718cef0SMichael Rolnik { 25295718cef0SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 25305718cef0SMichael Rolnik tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ 25315718cef0SMichael Rolnik tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf); 25325718cef0SMichael Rolnik tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ 25335718cef0SMichael Rolnik } 25345718cef0SMichael Rolnik 25355718cef0SMichael Rolnik /* 25365718cef0SMichael Rolnik * Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is 25375718cef0SMichael Rolnik * loaded into the C Flag of the SREG. This operation effectively divides an 25385718cef0SMichael Rolnik * unsigned value by two. The C Flag can be used to round the result. 25395718cef0SMichael Rolnik */ 25405718cef0SMichael Rolnik static bool trans_LSR(DisasContext *ctx, arg_LSR *a) 25415718cef0SMichael Rolnik { 25425718cef0SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 25435718cef0SMichael Rolnik 25445718cef0SMichael Rolnik tcg_gen_andi_tl(cpu_Cf, Rd, 1); 25455718cef0SMichael Rolnik tcg_gen_shri_tl(Rd, Rd, 1); 25465718cef0SMichael Rolnik 25475718cef0SMichael Rolnik /* update status register */ 25485718cef0SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, Rd, 0); /* Zf = Rd == 0 */ 25495718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Nf, 0); 25505718cef0SMichael Rolnik tcg_gen_mov_tl(cpu_Vf, cpu_Cf); 25515718cef0SMichael Rolnik tcg_gen_mov_tl(cpu_Sf, cpu_Vf); 25525718cef0SMichael Rolnik 25535718cef0SMichael Rolnik return true; 25545718cef0SMichael Rolnik } 25555718cef0SMichael Rolnik 25565718cef0SMichael Rolnik /* 25575718cef0SMichael Rolnik * Shifts all bits in Rd one place to the right. The C Flag is shifted into 25585718cef0SMichael Rolnik * bit 7 of Rd. Bit 0 is shifted into the C Flag. This operation, combined 25595718cef0SMichael Rolnik * with ASR, effectively divides multi-byte signed values by two. Combined with 25605718cef0SMichael Rolnik * LSR it effectively divides multi-byte unsigned values by two. The Carry Flag 25615718cef0SMichael Rolnik * can be used to round the result. 25625718cef0SMichael Rolnik */ 25635718cef0SMichael Rolnik static bool trans_ROR(DisasContext *ctx, arg_ROR *a) 25645718cef0SMichael Rolnik { 25655718cef0SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 25665718cef0SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 25675718cef0SMichael Rolnik 25685718cef0SMichael Rolnik tcg_gen_shli_tl(t0, cpu_Cf, 7); 25695718cef0SMichael Rolnik 25705718cef0SMichael Rolnik /* update status register */ 25715718cef0SMichael Rolnik tcg_gen_andi_tl(cpu_Cf, Rd, 1); 25725718cef0SMichael Rolnik 25735718cef0SMichael Rolnik /* update output register */ 25745718cef0SMichael Rolnik tcg_gen_shri_tl(Rd, Rd, 1); 25755718cef0SMichael Rolnik tcg_gen_or_tl(Rd, Rd, t0); 25765718cef0SMichael Rolnik 25775718cef0SMichael Rolnik /* update status register */ 25785718cef0SMichael Rolnik gen_rshift_ZNVSf(Rd); 25795718cef0SMichael Rolnik 25805718cef0SMichael Rolnik tcg_temp_free_i32(t0); 25815718cef0SMichael Rolnik 25825718cef0SMichael Rolnik return true; 25835718cef0SMichael Rolnik } 25845718cef0SMichael Rolnik 25855718cef0SMichael Rolnik /* 25865718cef0SMichael Rolnik * Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0 25875718cef0SMichael Rolnik * is loaded into the C Flag of the SREG. This operation effectively divides a 25885718cef0SMichael Rolnik * signed value by two without changing its sign. The Carry Flag can be used to 25895718cef0SMichael Rolnik * round the result. 25905718cef0SMichael Rolnik */ 25915718cef0SMichael Rolnik static bool trans_ASR(DisasContext *ctx, arg_ASR *a) 25925718cef0SMichael Rolnik { 25935718cef0SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 25945718cef0SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 25955718cef0SMichael Rolnik 25965718cef0SMichael Rolnik /* update status register */ 25975718cef0SMichael Rolnik tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */ 25985718cef0SMichael Rolnik 25995718cef0SMichael Rolnik /* update output register */ 26005718cef0SMichael Rolnik tcg_gen_andi_tl(t0, Rd, 0x80); /* Rd = (Rd & 0x80) | (Rd >> 1) */ 26015718cef0SMichael Rolnik tcg_gen_shri_tl(Rd, Rd, 1); 26025718cef0SMichael Rolnik tcg_gen_or_tl(Rd, Rd, t0); 26035718cef0SMichael Rolnik 26045718cef0SMichael Rolnik /* update status register */ 26055718cef0SMichael Rolnik gen_rshift_ZNVSf(Rd); 26065718cef0SMichael Rolnik 26075718cef0SMichael Rolnik tcg_temp_free_i32(t0); 26085718cef0SMichael Rolnik 26095718cef0SMichael Rolnik return true; 26105718cef0SMichael Rolnik } 26115718cef0SMichael Rolnik 26125718cef0SMichael Rolnik /* 26135718cef0SMichael Rolnik * Swaps high and low nibbles in a register. 26145718cef0SMichael Rolnik */ 26155718cef0SMichael Rolnik static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) 26165718cef0SMichael Rolnik { 26175718cef0SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 26185718cef0SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 26195718cef0SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 26205718cef0SMichael Rolnik 26215718cef0SMichael Rolnik tcg_gen_andi_tl(t0, Rd, 0x0f); 26225718cef0SMichael Rolnik tcg_gen_shli_tl(t0, t0, 4); 26235718cef0SMichael Rolnik tcg_gen_andi_tl(t1, Rd, 0xf0); 26245718cef0SMichael Rolnik tcg_gen_shri_tl(t1, t1, 4); 26255718cef0SMichael Rolnik tcg_gen_or_tl(Rd, t0, t1); 26265718cef0SMichael Rolnik 26275718cef0SMichael Rolnik tcg_temp_free_i32(t1); 26285718cef0SMichael Rolnik tcg_temp_free_i32(t0); 26295718cef0SMichael Rolnik 26305718cef0SMichael Rolnik return true; 26315718cef0SMichael Rolnik } 26325718cef0SMichael Rolnik 26335718cef0SMichael Rolnik /* 26345718cef0SMichael Rolnik * Sets a specified bit in an I/O Register. This instruction operates on 26355718cef0SMichael Rolnik * the lower 32 I/O Registers -- addresses 0-31. 26365718cef0SMichael Rolnik */ 26375718cef0SMichael Rolnik static bool trans_SBI(DisasContext *ctx, arg_SBI *a) 26385718cef0SMichael Rolnik { 26395718cef0SMichael Rolnik TCGv data = tcg_temp_new_i32(); 26405718cef0SMichael Rolnik TCGv port = tcg_const_i32(a->reg); 26415718cef0SMichael Rolnik 26425718cef0SMichael Rolnik gen_helper_inb(data, cpu_env, port); 26435718cef0SMichael Rolnik tcg_gen_ori_tl(data, data, 1 << a->bit); 26445718cef0SMichael Rolnik gen_helper_outb(cpu_env, port, data); 26455718cef0SMichael Rolnik 26465718cef0SMichael Rolnik tcg_temp_free_i32(port); 26475718cef0SMichael Rolnik tcg_temp_free_i32(data); 26485718cef0SMichael Rolnik 26495718cef0SMichael Rolnik return true; 26505718cef0SMichael Rolnik } 26515718cef0SMichael Rolnik 26525718cef0SMichael Rolnik /* 26535718cef0SMichael Rolnik * Clears a specified bit in an I/O Register. This instruction operates on 26545718cef0SMichael Rolnik * the lower 32 I/O Registers -- addresses 0-31. 26555718cef0SMichael Rolnik */ 26565718cef0SMichael Rolnik static bool trans_CBI(DisasContext *ctx, arg_CBI *a) 26575718cef0SMichael Rolnik { 26585718cef0SMichael Rolnik TCGv data = tcg_temp_new_i32(); 26595718cef0SMichael Rolnik TCGv port = tcg_const_i32(a->reg); 26605718cef0SMichael Rolnik 26615718cef0SMichael Rolnik gen_helper_inb(data, cpu_env, port); 26625718cef0SMichael Rolnik tcg_gen_andi_tl(data, data, ~(1 << a->bit)); 26635718cef0SMichael Rolnik gen_helper_outb(cpu_env, port, data); 26645718cef0SMichael Rolnik 26655718cef0SMichael Rolnik tcg_temp_free_i32(data); 26665718cef0SMichael Rolnik tcg_temp_free_i32(port); 26675718cef0SMichael Rolnik 26685718cef0SMichael Rolnik return true; 26695718cef0SMichael Rolnik } 26705718cef0SMichael Rolnik 26715718cef0SMichael Rolnik /* 26725718cef0SMichael Rolnik * Stores bit b from Rd to the T Flag in SREG (Status Register). 26735718cef0SMichael Rolnik */ 26745718cef0SMichael Rolnik static bool trans_BST(DisasContext *ctx, arg_BST *a) 26755718cef0SMichael Rolnik { 26765718cef0SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 26775718cef0SMichael Rolnik 26785718cef0SMichael Rolnik tcg_gen_andi_tl(cpu_Tf, Rd, 1 << a->bit); 26795718cef0SMichael Rolnik tcg_gen_shri_tl(cpu_Tf, cpu_Tf, a->bit); 26805718cef0SMichael Rolnik 26815718cef0SMichael Rolnik return true; 26825718cef0SMichael Rolnik } 26835718cef0SMichael Rolnik 26845718cef0SMichael Rolnik /* 26855718cef0SMichael Rolnik * Copies the T Flag in the SREG (Status Register) to bit b in register Rd. 26865718cef0SMichael Rolnik */ 26875718cef0SMichael Rolnik static bool trans_BLD(DisasContext *ctx, arg_BLD *a) 26885718cef0SMichael Rolnik { 26895718cef0SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 26905718cef0SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 26915718cef0SMichael Rolnik 26925718cef0SMichael Rolnik tcg_gen_andi_tl(Rd, Rd, ~(1u << a->bit)); /* clear bit */ 26935718cef0SMichael Rolnik tcg_gen_shli_tl(t1, cpu_Tf, a->bit); /* create mask */ 26945718cef0SMichael Rolnik tcg_gen_or_tl(Rd, Rd, t1); 26955718cef0SMichael Rolnik 26965718cef0SMichael Rolnik tcg_temp_free_i32(t1); 26975718cef0SMichael Rolnik 26985718cef0SMichael Rolnik return true; 26995718cef0SMichael Rolnik } 27005718cef0SMichael Rolnik 27015718cef0SMichael Rolnik /* 27025718cef0SMichael Rolnik * Sets a single Flag or bit in SREG. 27035718cef0SMichael Rolnik */ 27045718cef0SMichael Rolnik static bool trans_BSET(DisasContext *ctx, arg_BSET *a) 27055718cef0SMichael Rolnik { 27065718cef0SMichael Rolnik switch (a->bit) { 27075718cef0SMichael Rolnik case 0x00: 27085718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Cf, 0x01); 27095718cef0SMichael Rolnik break; 27105718cef0SMichael Rolnik case 0x01: 27115718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Zf, 0x01); 27125718cef0SMichael Rolnik break; 27135718cef0SMichael Rolnik case 0x02: 27145718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Nf, 0x01); 27155718cef0SMichael Rolnik break; 27165718cef0SMichael Rolnik case 0x03: 27175718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0x01); 27185718cef0SMichael Rolnik break; 27195718cef0SMichael Rolnik case 0x04: 27205718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Sf, 0x01); 27215718cef0SMichael Rolnik break; 27225718cef0SMichael Rolnik case 0x05: 27235718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Hf, 0x01); 27245718cef0SMichael Rolnik break; 27255718cef0SMichael Rolnik case 0x06: 27265718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Tf, 0x01); 27275718cef0SMichael Rolnik break; 27285718cef0SMichael Rolnik case 0x07: 27295718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_If, 0x01); 27305718cef0SMichael Rolnik break; 27315718cef0SMichael Rolnik } 27325718cef0SMichael Rolnik 27335718cef0SMichael Rolnik return true; 27345718cef0SMichael Rolnik } 27355718cef0SMichael Rolnik 27365718cef0SMichael Rolnik /* 27375718cef0SMichael Rolnik * Clears a single Flag in SREG. 27385718cef0SMichael Rolnik */ 27395718cef0SMichael Rolnik static bool trans_BCLR(DisasContext *ctx, arg_BCLR *a) 27405718cef0SMichael Rolnik { 27415718cef0SMichael Rolnik switch (a->bit) { 27425718cef0SMichael Rolnik case 0x00: 27435718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Cf, 0x00); 27445718cef0SMichael Rolnik break; 27455718cef0SMichael Rolnik case 0x01: 27465718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Zf, 0x00); 27475718cef0SMichael Rolnik break; 27485718cef0SMichael Rolnik case 0x02: 27495718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Nf, 0x00); 27505718cef0SMichael Rolnik break; 27515718cef0SMichael Rolnik case 0x03: 27525718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0x00); 27535718cef0SMichael Rolnik break; 27545718cef0SMichael Rolnik case 0x04: 27555718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Sf, 0x00); 27565718cef0SMichael Rolnik break; 27575718cef0SMichael Rolnik case 0x05: 27585718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Hf, 0x00); 27595718cef0SMichael Rolnik break; 27605718cef0SMichael Rolnik case 0x06: 27615718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_Tf, 0x00); 27625718cef0SMichael Rolnik break; 27635718cef0SMichael Rolnik case 0x07: 27645718cef0SMichael Rolnik tcg_gen_movi_tl(cpu_If, 0x00); 27655718cef0SMichael Rolnik break; 27665718cef0SMichael Rolnik } 27675718cef0SMichael Rolnik 27685718cef0SMichael Rolnik return true; 27695718cef0SMichael Rolnik } 277046188cabSMichael Rolnik 277146188cabSMichael Rolnik /* 277246188cabSMichael Rolnik * MCU Control Instructions 277346188cabSMichael Rolnik */ 277446188cabSMichael Rolnik 277546188cabSMichael Rolnik /* 277646188cabSMichael Rolnik * The BREAK instruction is used by the On-chip Debug system, and is 277746188cabSMichael Rolnik * normally not used in the application software. When the BREAK instruction is 277846188cabSMichael Rolnik * executed, the AVR CPU is set in the Stopped Mode. This gives the On-chip 277946188cabSMichael Rolnik * Debugger access to internal resources. If any Lock bits are set, or either 278046188cabSMichael Rolnik * the JTAGEN or OCDEN Fuses are unprogrammed, the CPU will treat the BREAK 278146188cabSMichael Rolnik * instruction as a NOP and will not enter the Stopped mode. This instruction 278246188cabSMichael Rolnik * is not available in all devices. Refer to the device specific instruction 278346188cabSMichael Rolnik * set summary. 278446188cabSMichael Rolnik */ 278546188cabSMichael Rolnik static bool trans_BREAK(DisasContext *ctx, arg_BREAK *a) 278646188cabSMichael Rolnik { 278746188cabSMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_BREAK)) { 278846188cabSMichael Rolnik return true; 278946188cabSMichael Rolnik } 279046188cabSMichael Rolnik 279146188cabSMichael Rolnik #ifdef BREAKPOINT_ON_BREAK 279246188cabSMichael Rolnik tcg_gen_movi_tl(cpu_pc, ctx->npc - 1); 279346188cabSMichael Rolnik gen_helper_debug(cpu_env); 279493d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_EXIT; 279546188cabSMichael Rolnik #else 279646188cabSMichael Rolnik /* NOP */ 279746188cabSMichael Rolnik #endif 279846188cabSMichael Rolnik 279946188cabSMichael Rolnik return true; 280046188cabSMichael Rolnik } 280146188cabSMichael Rolnik 280246188cabSMichael Rolnik /* 280346188cabSMichael Rolnik * This instruction performs a single cycle No Operation. 280446188cabSMichael Rolnik */ 280546188cabSMichael Rolnik static bool trans_NOP(DisasContext *ctx, arg_NOP *a) 280646188cabSMichael Rolnik { 280746188cabSMichael Rolnik 280846188cabSMichael Rolnik /* NOP */ 280946188cabSMichael Rolnik 281046188cabSMichael Rolnik return true; 281146188cabSMichael Rolnik } 281246188cabSMichael Rolnik 281346188cabSMichael Rolnik /* 281446188cabSMichael Rolnik * This instruction sets the circuit in sleep mode defined by the MCU 281546188cabSMichael Rolnik * Control Register. 281646188cabSMichael Rolnik */ 281746188cabSMichael Rolnik static bool trans_SLEEP(DisasContext *ctx, arg_SLEEP *a) 281846188cabSMichael Rolnik { 281946188cabSMichael Rolnik gen_helper_sleep(cpu_env); 282093d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 282146188cabSMichael Rolnik return true; 282246188cabSMichael Rolnik } 282346188cabSMichael Rolnik 282446188cabSMichael Rolnik /* 282546188cabSMichael Rolnik * This instruction resets the Watchdog Timer. This instruction must be 282646188cabSMichael Rolnik * executed within a limited time given by the WD prescaler. See the Watchdog 282746188cabSMichael Rolnik * Timer hardware specification. 282846188cabSMichael Rolnik */ 282946188cabSMichael Rolnik static bool trans_WDR(DisasContext *ctx, arg_WDR *a) 283046188cabSMichael Rolnik { 283146188cabSMichael Rolnik gen_helper_wdr(cpu_env); 283246188cabSMichael Rolnik 283346188cabSMichael Rolnik return true; 283446188cabSMichael Rolnik } 28359baade8dSMichael Rolnik 28369baade8dSMichael Rolnik /* 28379baade8dSMichael Rolnik * Core translation mechanism functions: 28389baade8dSMichael Rolnik * 28399baade8dSMichael Rolnik * - translate() 28409baade8dSMichael Rolnik * - canonicalize_skip() 28419baade8dSMichael Rolnik * - gen_intermediate_code() 28429baade8dSMichael Rolnik * - restore_state_to_opc() 28439baade8dSMichael Rolnik * 28449baade8dSMichael Rolnik */ 28459baade8dSMichael Rolnik static void translate(DisasContext *ctx) 28469baade8dSMichael Rolnik { 28479baade8dSMichael Rolnik uint32_t opcode = next_word(ctx); 28489baade8dSMichael Rolnik 28499baade8dSMichael Rolnik if (!decode_insn(ctx, opcode)) { 28509baade8dSMichael Rolnik gen_helper_unsupported(cpu_env); 285193d4d5e4SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 28529baade8dSMichael Rolnik } 28539baade8dSMichael Rolnik } 28549baade8dSMichael Rolnik 28559baade8dSMichael Rolnik /* Standardize the cpu_skip condition to NE. */ 28569baade8dSMichael Rolnik static bool canonicalize_skip(DisasContext *ctx) 28579baade8dSMichael Rolnik { 28589baade8dSMichael Rolnik switch (ctx->skip_cond) { 28599baade8dSMichael Rolnik case TCG_COND_NEVER: 28609baade8dSMichael Rolnik /* Normal case: cpu_skip is known to be false. */ 28619baade8dSMichael Rolnik return false; 28629baade8dSMichael Rolnik 28639baade8dSMichael Rolnik case TCG_COND_ALWAYS: 28649baade8dSMichael Rolnik /* 28659baade8dSMichael Rolnik * Breakpoint case: cpu_skip is known to be true, via TB_FLAGS_SKIP. 28669baade8dSMichael Rolnik * The breakpoint is on the instruction being skipped, at the start 28679baade8dSMichael Rolnik * of the TranslationBlock. No need to update. 28689baade8dSMichael Rolnik */ 28699baade8dSMichael Rolnik return false; 28709baade8dSMichael Rolnik 28719baade8dSMichael Rolnik case TCG_COND_NE: 28729baade8dSMichael Rolnik if (ctx->skip_var1 == NULL) { 28739baade8dSMichael Rolnik tcg_gen_mov_tl(cpu_skip, ctx->skip_var0); 28749baade8dSMichael Rolnik } else { 28759baade8dSMichael Rolnik tcg_gen_xor_tl(cpu_skip, ctx->skip_var0, ctx->skip_var1); 28769baade8dSMichael Rolnik ctx->skip_var1 = NULL; 28779baade8dSMichael Rolnik } 28789baade8dSMichael Rolnik break; 28799baade8dSMichael Rolnik 28809baade8dSMichael Rolnik default: 28819baade8dSMichael Rolnik /* Convert to a NE condition vs 0. */ 28829baade8dSMichael Rolnik if (ctx->skip_var1 == NULL) { 28839baade8dSMichael Rolnik tcg_gen_setcondi_tl(ctx->skip_cond, cpu_skip, ctx->skip_var0, 0); 28849baade8dSMichael Rolnik } else { 28859baade8dSMichael Rolnik tcg_gen_setcond_tl(ctx->skip_cond, cpu_skip, 28869baade8dSMichael Rolnik ctx->skip_var0, ctx->skip_var1); 28879baade8dSMichael Rolnik ctx->skip_var1 = NULL; 28889baade8dSMichael Rolnik } 28899baade8dSMichael Rolnik ctx->skip_cond = TCG_COND_NE; 28909baade8dSMichael Rolnik break; 28919baade8dSMichael Rolnik } 28929baade8dSMichael Rolnik if (ctx->free_skip_var0) { 28939baade8dSMichael Rolnik tcg_temp_free(ctx->skip_var0); 28949baade8dSMichael Rolnik ctx->free_skip_var0 = false; 28959baade8dSMichael Rolnik } 28969baade8dSMichael Rolnik ctx->skip_var0 = cpu_skip; 28979baade8dSMichael Rolnik return true; 28989baade8dSMichael Rolnik } 28999baade8dSMichael Rolnik 2900*3fbd28d8SRichard Henderson static void gen_breakpoint(DisasContext *ctx) 29019baade8dSMichael Rolnik { 2902*3fbd28d8SRichard Henderson canonicalize_skip(ctx); 2903*3fbd28d8SRichard Henderson tcg_gen_movi_tl(cpu_pc, ctx->npc); 2904*3fbd28d8SRichard Henderson gen_helper_debug(cpu_env); 2905*3fbd28d8SRichard Henderson ctx->base.is_jmp = DISAS_NORETURN; 2906*3fbd28d8SRichard Henderson } 2907*3fbd28d8SRichard Henderson 2908*3fbd28d8SRichard Henderson static void avr_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) 2909*3fbd28d8SRichard Henderson { 2910*3fbd28d8SRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 29119baade8dSMichael Rolnik CPUAVRState *env = cs->env_ptr; 2912*3fbd28d8SRichard Henderson uint32_t tb_flags = ctx->base.tb->flags; 29139baade8dSMichael Rolnik 2914*3fbd28d8SRichard Henderson ctx->cs = cs; 2915*3fbd28d8SRichard Henderson ctx->env = env; 2916*3fbd28d8SRichard Henderson ctx->npc = ctx->base.pc_first / 2; 29179baade8dSMichael Rolnik 2918*3fbd28d8SRichard Henderson ctx->skip_cond = TCG_COND_NEVER; 2919*3fbd28d8SRichard Henderson if (tb_flags & TB_FLAGS_SKIP) { 2920bcef6d76SRichard Henderson ctx->skip_cond = TCG_COND_ALWAYS; 2921bcef6d76SRichard Henderson ctx->skip_var0 = cpu_skip; 29229baade8dSMichael Rolnik } 29239baade8dSMichael Rolnik 2924*3fbd28d8SRichard Henderson if (tb_flags & TB_FLAGS_FULL_ACCESS) { 2925*3fbd28d8SRichard Henderson /* 2926*3fbd28d8SRichard Henderson * This flag is set by ST/LD instruction we will regenerate it ONLY 2927*3fbd28d8SRichard Henderson * with mem/cpu memory access instead of mem access 2928*3fbd28d8SRichard Henderson */ 2929*3fbd28d8SRichard Henderson ctx->base.max_insns = 1; 2930*3fbd28d8SRichard Henderson } 2931*3fbd28d8SRichard Henderson } 2932*3fbd28d8SRichard Henderson 2933*3fbd28d8SRichard Henderson static void avr_tr_tb_start(DisasContextBase *db, CPUState *cs) 2934*3fbd28d8SRichard Henderson { 2935*3fbd28d8SRichard Henderson } 2936*3fbd28d8SRichard Henderson 2937*3fbd28d8SRichard Henderson static void avr_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) 2938*3fbd28d8SRichard Henderson { 2939*3fbd28d8SRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 2940*3fbd28d8SRichard Henderson 2941*3fbd28d8SRichard Henderson tcg_gen_insn_start(ctx->npc); 2942*3fbd28d8SRichard Henderson } 2943*3fbd28d8SRichard Henderson 2944*3fbd28d8SRichard Henderson static bool avr_tr_breakpoint_check(DisasContextBase *dcbase, CPUState *cs, 2945*3fbd28d8SRichard Henderson const CPUBreakpoint *bp) 2946*3fbd28d8SRichard Henderson { 2947*3fbd28d8SRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 2948*3fbd28d8SRichard Henderson 2949*3fbd28d8SRichard Henderson gen_breakpoint(ctx); 2950*3fbd28d8SRichard Henderson return true; 2951*3fbd28d8SRichard Henderson } 2952*3fbd28d8SRichard Henderson 2953*3fbd28d8SRichard Henderson static void avr_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) 2954*3fbd28d8SRichard Henderson { 2955*3fbd28d8SRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 29569baade8dSMichael Rolnik TCGLabel *skip_label = NULL; 29579baade8dSMichael Rolnik 29589baade8dSMichael Rolnik /* 2959*3fbd28d8SRichard Henderson * This is due to some strange GDB behavior 2960*3fbd28d8SRichard Henderson * Let's assume main has address 0x100: 29619baade8dSMichael Rolnik * b main - sets breakpoint at address 0x00000100 (code) 29629baade8dSMichael Rolnik * b *0x100 - sets breakpoint at address 0x00800100 (data) 2963*3fbd28d8SRichard Henderson * 2964*3fbd28d8SRichard Henderson * The translator driver has already taken care of the code pointer. 29659baade8dSMichael Rolnik */ 2966*3fbd28d8SRichard Henderson if (!ctx->base.singlestep_enabled && 2967*3fbd28d8SRichard Henderson cpu_breakpoint_test(cs, OFFSET_DATA + ctx->base.pc_next, BP_ANY)) { 2968*3fbd28d8SRichard Henderson gen_breakpoint(ctx); 2969*3fbd28d8SRichard Henderson return; 29709baade8dSMichael Rolnik } 29719baade8dSMichael Rolnik 29729baade8dSMichael Rolnik /* Conditionally skip the next instruction, if indicated. */ 2973bcef6d76SRichard Henderson if (ctx->skip_cond != TCG_COND_NEVER) { 29749baade8dSMichael Rolnik skip_label = gen_new_label(); 2975bcef6d76SRichard Henderson if (ctx->skip_var0 == cpu_skip) { 29769baade8dSMichael Rolnik /* 29779baade8dSMichael Rolnik * Copy cpu_skip so that we may zero it before the branch. 29789baade8dSMichael Rolnik * This ensures that cpu_skip is non-zero after the label 29799baade8dSMichael Rolnik * if and only if the skipped insn itself sets a skip. 29809baade8dSMichael Rolnik */ 2981bcef6d76SRichard Henderson ctx->free_skip_var0 = true; 2982bcef6d76SRichard Henderson ctx->skip_var0 = tcg_temp_new(); 2983bcef6d76SRichard Henderson tcg_gen_mov_tl(ctx->skip_var0, cpu_skip); 29849baade8dSMichael Rolnik tcg_gen_movi_tl(cpu_skip, 0); 29859baade8dSMichael Rolnik } 2986bcef6d76SRichard Henderson if (ctx->skip_var1 == NULL) { 2987*3fbd28d8SRichard Henderson tcg_gen_brcondi_tl(ctx->skip_cond, ctx->skip_var0, 0, skip_label); 29889baade8dSMichael Rolnik } else { 2989bcef6d76SRichard Henderson tcg_gen_brcond_tl(ctx->skip_cond, ctx->skip_var0, 2990bcef6d76SRichard Henderson ctx->skip_var1, skip_label); 2991bcef6d76SRichard Henderson ctx->skip_var1 = NULL; 29929baade8dSMichael Rolnik } 2993bcef6d76SRichard Henderson if (ctx->free_skip_var0) { 2994bcef6d76SRichard Henderson tcg_temp_free(ctx->skip_var0); 2995bcef6d76SRichard Henderson ctx->free_skip_var0 = false; 29969baade8dSMichael Rolnik } 2997bcef6d76SRichard Henderson ctx->skip_cond = TCG_COND_NEVER; 2998bcef6d76SRichard Henderson ctx->skip_var0 = NULL; 29999baade8dSMichael Rolnik } 30009baade8dSMichael Rolnik 3001bcef6d76SRichard Henderson translate(ctx); 30029baade8dSMichael Rolnik 3003*3fbd28d8SRichard Henderson ctx->base.pc_next = ctx->npc * 2; 3004*3fbd28d8SRichard Henderson 30059baade8dSMichael Rolnik if (skip_label) { 3006bcef6d76SRichard Henderson canonicalize_skip(ctx); 30079baade8dSMichael Rolnik gen_set_label(skip_label); 3008bcef6d76SRichard Henderson if (ctx->base.is_jmp == DISAS_NORETURN) { 3009bcef6d76SRichard Henderson ctx->base.is_jmp = DISAS_CHAIN; 30109baade8dSMichael Rolnik } 30119baade8dSMichael Rolnik } 30129baade8dSMichael Rolnik 3013*3fbd28d8SRichard Henderson if (ctx->base.is_jmp == DISAS_NEXT) { 3014*3fbd28d8SRichard Henderson target_ulong page_first = ctx->base.pc_first & TARGET_PAGE_MASK; 3015*3fbd28d8SRichard Henderson 3016*3fbd28d8SRichard Henderson if ((ctx->base.pc_next - page_first) >= TARGET_PAGE_SIZE - 4) { 3017*3fbd28d8SRichard Henderson ctx->base.is_jmp = DISAS_TOO_MANY; 3018*3fbd28d8SRichard Henderson } 3019*3fbd28d8SRichard Henderson } 30209baade8dSMichael Rolnik } 30219baade8dSMichael Rolnik 3022*3fbd28d8SRichard Henderson static void avr_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) 3023*3fbd28d8SRichard Henderson { 3024*3fbd28d8SRichard Henderson DisasContext *ctx = container_of(dcbase, DisasContext, base); 3025bcef6d76SRichard Henderson bool nonconst_skip = canonicalize_skip(ctx); 30269baade8dSMichael Rolnik 3027bcef6d76SRichard Henderson switch (ctx->base.is_jmp) { 30289baade8dSMichael Rolnik case DISAS_NORETURN: 30299baade8dSMichael Rolnik assert(!nonconst_skip); 30309baade8dSMichael Rolnik break; 30319baade8dSMichael Rolnik case DISAS_NEXT: 30329baade8dSMichael Rolnik case DISAS_TOO_MANY: 30339baade8dSMichael Rolnik case DISAS_CHAIN: 30349baade8dSMichael Rolnik if (!nonconst_skip) { 30359baade8dSMichael Rolnik /* Note gen_goto_tb checks singlestep. */ 3036bcef6d76SRichard Henderson gen_goto_tb(ctx, 1, ctx->npc); 30379baade8dSMichael Rolnik break; 30389baade8dSMichael Rolnik } 3039bcef6d76SRichard Henderson tcg_gen_movi_tl(cpu_pc, ctx->npc); 30409baade8dSMichael Rolnik /* fall through */ 30419baade8dSMichael Rolnik case DISAS_LOOKUP: 3042bcef6d76SRichard Henderson if (!ctx->base.singlestep_enabled) { 30439baade8dSMichael Rolnik tcg_gen_lookup_and_goto_ptr(); 30449baade8dSMichael Rolnik break; 30459baade8dSMichael Rolnik } 30469baade8dSMichael Rolnik /* fall through */ 30479baade8dSMichael Rolnik case DISAS_EXIT: 3048bcef6d76SRichard Henderson if (ctx->base.singlestep_enabled) { 30499baade8dSMichael Rolnik gen_helper_debug(cpu_env); 30509baade8dSMichael Rolnik } else { 30519baade8dSMichael Rolnik tcg_gen_exit_tb(NULL, 0); 30529baade8dSMichael Rolnik } 30539baade8dSMichael Rolnik break; 30549baade8dSMichael Rolnik default: 30559baade8dSMichael Rolnik g_assert_not_reached(); 30569baade8dSMichael Rolnik } 30579d8caa67SMichael Rolnik } 3058*3fbd28d8SRichard Henderson 3059*3fbd28d8SRichard Henderson static void avr_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) 3060*3fbd28d8SRichard Henderson { 3061*3fbd28d8SRichard Henderson qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); 3062*3fbd28d8SRichard Henderson log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); 3063*3fbd28d8SRichard Henderson } 3064*3fbd28d8SRichard Henderson 3065*3fbd28d8SRichard Henderson static const TranslatorOps avr_tr_ops = { 3066*3fbd28d8SRichard Henderson .init_disas_context = avr_tr_init_disas_context, 3067*3fbd28d8SRichard Henderson .tb_start = avr_tr_tb_start, 3068*3fbd28d8SRichard Henderson .insn_start = avr_tr_insn_start, 3069*3fbd28d8SRichard Henderson .breakpoint_check = avr_tr_breakpoint_check, 3070*3fbd28d8SRichard Henderson .translate_insn = avr_tr_translate_insn, 3071*3fbd28d8SRichard Henderson .tb_stop = avr_tr_tb_stop, 3072*3fbd28d8SRichard Henderson .disas_log = avr_tr_disas_log, 3073*3fbd28d8SRichard Henderson }; 3074*3fbd28d8SRichard Henderson 3075*3fbd28d8SRichard Henderson void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) 3076*3fbd28d8SRichard Henderson { 3077*3fbd28d8SRichard Henderson DisasContext dc = { }; 3078*3fbd28d8SRichard Henderson translator_loop(&avr_tr_ops, &dc.base, cs, tb, max_insns); 30799baade8dSMichael Rolnik } 30809baade8dSMichael Rolnik 30819baade8dSMichael Rolnik void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, 30829baade8dSMichael Rolnik target_ulong *data) 30839baade8dSMichael Rolnik { 30849baade8dSMichael Rolnik env->pc_w = data[0]; 30859baade8dSMichael Rolnik } 3086