1e03feba0SMichael Rolnik /* 2e03feba0SMichael Rolnik * QEMU AVR CPU 3e03feba0SMichael Rolnik * 4e03feba0SMichael Rolnik * Copyright (c) 2019-2020 Michael Rolnik 5e03feba0SMichael Rolnik * 6e03feba0SMichael Rolnik * This library is free software; you can redistribute it and/or 7e03feba0SMichael Rolnik * modify it under the terms of the GNU Lesser General Public 8e03feba0SMichael Rolnik * License as published by the Free Software Foundation; either 9e03feba0SMichael Rolnik * version 2.1 of the License, or (at your option) any later version. 10e03feba0SMichael Rolnik * 11e03feba0SMichael Rolnik * This library is distributed in the hope that it will be useful, 12e03feba0SMichael Rolnik * but WITHOUT ANY WARRANTY; without even the implied warranty of 13e03feba0SMichael Rolnik * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14e03feba0SMichael Rolnik * Lesser General Public License for more details. 15e03feba0SMichael Rolnik * 16e03feba0SMichael Rolnik * You should have received a copy of the GNU Lesser General Public 17e03feba0SMichael Rolnik * License along with this library; if not, see 18e03feba0SMichael Rolnik * <http://www.gnu.org/licenses/lgpl-2.1.html> 19e03feba0SMichael Rolnik */ 20e03feba0SMichael Rolnik 21e03feba0SMichael Rolnik #include "qemu/osdep.h" 22e03feba0SMichael Rolnik #include "qemu/qemu-print.h" 23e03feba0SMichael Rolnik #include "tcg/tcg.h" 24e03feba0SMichael Rolnik #include "cpu.h" 25e03feba0SMichael Rolnik #include "exec/exec-all.h" 26e03feba0SMichael Rolnik #include "tcg/tcg-op.h" 27e03feba0SMichael Rolnik #include "exec/cpu_ldst.h" 28e03feba0SMichael Rolnik #include "exec/helper-proto.h" 29e03feba0SMichael Rolnik #include "exec/helper-gen.h" 30e03feba0SMichael Rolnik #include "exec/log.h" 31e03feba0SMichael Rolnik #include "exec/translator.h" 32e03feba0SMichael Rolnik #include "exec/gen-icount.h" 33e03feba0SMichael Rolnik 34e03feba0SMichael Rolnik /* 35e03feba0SMichael Rolnik * Define if you want a BREAK instruction translated to a breakpoint 36e03feba0SMichael Rolnik * Active debugging connection is assumed 37e03feba0SMichael Rolnik * This is for 38e03feba0SMichael Rolnik * https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tests 39e03feba0SMichael Rolnik * tests 40e03feba0SMichael Rolnik */ 41e03feba0SMichael Rolnik #undef BREAKPOINT_ON_BREAK 42e03feba0SMichael Rolnik 43e03feba0SMichael Rolnik static TCGv cpu_pc; 44e03feba0SMichael Rolnik 45e03feba0SMichael Rolnik static TCGv cpu_Cf; 46e03feba0SMichael Rolnik static TCGv cpu_Zf; 47e03feba0SMichael Rolnik static TCGv cpu_Nf; 48e03feba0SMichael Rolnik static TCGv cpu_Vf; 49e03feba0SMichael Rolnik static TCGv cpu_Sf; 50e03feba0SMichael Rolnik static TCGv cpu_Hf; 51e03feba0SMichael Rolnik static TCGv cpu_Tf; 52e03feba0SMichael Rolnik static TCGv cpu_If; 53e03feba0SMichael Rolnik 54e03feba0SMichael Rolnik static TCGv cpu_rampD; 55e03feba0SMichael Rolnik static TCGv cpu_rampX; 56e03feba0SMichael Rolnik static TCGv cpu_rampY; 57e03feba0SMichael Rolnik static TCGv cpu_rampZ; 58e03feba0SMichael Rolnik 59e03feba0SMichael Rolnik static TCGv cpu_r[NUMBER_OF_CPU_REGISTERS]; 60e03feba0SMichael Rolnik static TCGv cpu_eind; 61e03feba0SMichael Rolnik static TCGv cpu_sp; 62e03feba0SMichael Rolnik 63e03feba0SMichael Rolnik static TCGv cpu_skip; 64e03feba0SMichael Rolnik 65e03feba0SMichael Rolnik static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = { 66e03feba0SMichael Rolnik "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 67e03feba0SMichael Rolnik "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 68e03feba0SMichael Rolnik "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 69e03feba0SMichael Rolnik "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", 70e03feba0SMichael Rolnik }; 71e03feba0SMichael Rolnik #define REG(x) (cpu_r[x]) 72e03feba0SMichael Rolnik 73e03feba0SMichael Rolnik enum { 74e03feba0SMichael Rolnik DISAS_EXIT = DISAS_TARGET_0, /* We want return to the cpu main loop. */ 75e03feba0SMichael Rolnik DISAS_LOOKUP = DISAS_TARGET_1, /* We have a variable condition exit. */ 76e03feba0SMichael Rolnik DISAS_CHAIN = DISAS_TARGET_2, /* We have a single condition exit. */ 77e03feba0SMichael Rolnik }; 78e03feba0SMichael Rolnik 79e03feba0SMichael Rolnik typedef struct DisasContext DisasContext; 80e03feba0SMichael Rolnik 81e03feba0SMichael Rolnik /* This is the state at translation time. */ 82e03feba0SMichael Rolnik struct DisasContext { 83e03feba0SMichael Rolnik TranslationBlock *tb; 84e03feba0SMichael Rolnik 85e03feba0SMichael Rolnik CPUAVRState *env; 86e03feba0SMichael Rolnik CPUState *cs; 87e03feba0SMichael Rolnik 88e03feba0SMichael Rolnik target_long npc; 89e03feba0SMichael Rolnik uint32_t opcode; 90e03feba0SMichael Rolnik 91e03feba0SMichael Rolnik /* Routine used to access memory */ 92e03feba0SMichael Rolnik int memidx; 93e03feba0SMichael Rolnik int bstate; 94e03feba0SMichael Rolnik int singlestep; 95e03feba0SMichael Rolnik 96e03feba0SMichael Rolnik /* 97e03feba0SMichael Rolnik * some AVR instructions can make the following instruction to be skipped 98e03feba0SMichael Rolnik * Let's name those instructions 99e03feba0SMichael Rolnik * A - instruction that can skip the next one 100e03feba0SMichael Rolnik * B - instruction that can be skipped. this depends on execution of A 101e03feba0SMichael Rolnik * there are two scenarios 102e03feba0SMichael Rolnik * 1. A and B belong to the same translation block 103e03feba0SMichael Rolnik * 2. A is the last instruction in the translation block and B is the last 104e03feba0SMichael Rolnik * 105e03feba0SMichael Rolnik * following variables are used to simplify the skipping logic, they are 106e03feba0SMichael Rolnik * used in the following manner (sketch) 107e03feba0SMichael Rolnik * 108e03feba0SMichael Rolnik * TCGLabel *skip_label = NULL; 109e03feba0SMichael Rolnik * if (ctx.skip_cond != TCG_COND_NEVER) { 110e03feba0SMichael Rolnik * skip_label = gen_new_label(); 111e03feba0SMichael Rolnik * tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label); 112e03feba0SMichael Rolnik * } 113e03feba0SMichael Rolnik * 114e03feba0SMichael Rolnik * if (free_skip_var0) { 115e03feba0SMichael Rolnik * tcg_temp_free(skip_var0); 116e03feba0SMichael Rolnik * free_skip_var0 = false; 117e03feba0SMichael Rolnik * } 118e03feba0SMichael Rolnik * 119e03feba0SMichael Rolnik * translate(&ctx); 120e03feba0SMichael Rolnik * 121e03feba0SMichael Rolnik * if (skip_label) { 122e03feba0SMichael Rolnik * gen_set_label(skip_label); 123e03feba0SMichael Rolnik * } 124e03feba0SMichael Rolnik */ 125e03feba0SMichael Rolnik TCGv skip_var0; 126e03feba0SMichael Rolnik TCGv skip_var1; 127e03feba0SMichael Rolnik TCGCond skip_cond; 128e03feba0SMichael Rolnik bool free_skip_var0; 129e03feba0SMichael Rolnik }; 130e03feba0SMichael Rolnik 131*865f3bb9SMichael Rolnik static int to_regs_16_31_by_one(DisasContext *ctx, int indx) 132*865f3bb9SMichael Rolnik { 133*865f3bb9SMichael Rolnik return 16 + (indx % 16); 134*865f3bb9SMichael Rolnik } 135*865f3bb9SMichael Rolnik 136*865f3bb9SMichael Rolnik static int to_regs_16_23_by_one(DisasContext *ctx, int indx) 137*865f3bb9SMichael Rolnik { 138*865f3bb9SMichael Rolnik return 16 + (indx % 8); 139*865f3bb9SMichael Rolnik } 140*865f3bb9SMichael Rolnik 141*865f3bb9SMichael Rolnik static int to_regs_24_30_by_two(DisasContext *ctx, int indx) 142*865f3bb9SMichael Rolnik { 143*865f3bb9SMichael Rolnik return 24 + (indx % 4) * 2; 144*865f3bb9SMichael Rolnik } 145*865f3bb9SMichael Rolnik 146*865f3bb9SMichael Rolnik 147e03feba0SMichael Rolnik static bool avr_have_feature(DisasContext *ctx, int feature) 148e03feba0SMichael Rolnik { 149e03feba0SMichael Rolnik if (!avr_feature(ctx->env, feature)) { 150e03feba0SMichael Rolnik gen_helper_unsupported(cpu_env); 151e03feba0SMichael Rolnik ctx->bstate = DISAS_NORETURN; 152e03feba0SMichael Rolnik return false; 153e03feba0SMichael Rolnik } 154e03feba0SMichael Rolnik return true; 155e03feba0SMichael Rolnik } 156e03feba0SMichael Rolnik 157e03feba0SMichael Rolnik static bool decode_insn(DisasContext *ctx, uint16_t insn); 158e03feba0SMichael Rolnik #include "decode_insn.inc.c" 159*865f3bb9SMichael Rolnik 160*865f3bb9SMichael Rolnik /* 161*865f3bb9SMichael Rolnik * Arithmetic Instructions 162*865f3bb9SMichael Rolnik */ 163*865f3bb9SMichael Rolnik 164*865f3bb9SMichael Rolnik /* 165*865f3bb9SMichael Rolnik * Utility functions for updating status registers: 166*865f3bb9SMichael Rolnik * 167*865f3bb9SMichael Rolnik * - gen_add_CHf() 168*865f3bb9SMichael Rolnik * - gen_add_Vf() 169*865f3bb9SMichael Rolnik * - gen_sub_CHf() 170*865f3bb9SMichael Rolnik * - gen_sub_Vf() 171*865f3bb9SMichael Rolnik * - gen_NSf() 172*865f3bb9SMichael Rolnik * - gen_ZNSf() 173*865f3bb9SMichael Rolnik * 174*865f3bb9SMichael Rolnik */ 175*865f3bb9SMichael Rolnik 176*865f3bb9SMichael Rolnik static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) 177*865f3bb9SMichael Rolnik { 178*865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 179*865f3bb9SMichael Rolnik TCGv t2 = tcg_temp_new_i32(); 180*865f3bb9SMichael Rolnik TCGv t3 = tcg_temp_new_i32(); 181*865f3bb9SMichael Rolnik 182*865f3bb9SMichael Rolnik tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */ 183*865f3bb9SMichael Rolnik tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */ 184*865f3bb9SMichael Rolnik tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */ 185*865f3bb9SMichael Rolnik tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */ 186*865f3bb9SMichael Rolnik tcg_gen_or_tl(t1, t1, t3); 187*865f3bb9SMichael Rolnik 188*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */ 189*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */ 190*865f3bb9SMichael Rolnik tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); 191*865f3bb9SMichael Rolnik 192*865f3bb9SMichael Rolnik tcg_temp_free_i32(t3); 193*865f3bb9SMichael Rolnik tcg_temp_free_i32(t2); 194*865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 195*865f3bb9SMichael Rolnik } 196*865f3bb9SMichael Rolnik 197*865f3bb9SMichael Rolnik static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) 198*865f3bb9SMichael Rolnik { 199*865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 200*865f3bb9SMichael Rolnik TCGv t2 = tcg_temp_new_i32(); 201*865f3bb9SMichael Rolnik 202*865f3bb9SMichael Rolnik /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */ 203*865f3bb9SMichael Rolnik /* = (Rd ^ R) & ~(Rd ^ Rr) */ 204*865f3bb9SMichael Rolnik tcg_gen_xor_tl(t1, Rd, R); 205*865f3bb9SMichael Rolnik tcg_gen_xor_tl(t2, Rd, Rr); 206*865f3bb9SMichael Rolnik tcg_gen_andc_tl(t1, t1, t2); 207*865f3bb9SMichael Rolnik 208*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ 209*865f3bb9SMichael Rolnik 210*865f3bb9SMichael Rolnik tcg_temp_free_i32(t2); 211*865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 212*865f3bb9SMichael Rolnik } 213*865f3bb9SMichael Rolnik 214*865f3bb9SMichael Rolnik static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr) 215*865f3bb9SMichael Rolnik { 216*865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 217*865f3bb9SMichael Rolnik TCGv t2 = tcg_temp_new_i32(); 218*865f3bb9SMichael Rolnik TCGv t3 = tcg_temp_new_i32(); 219*865f3bb9SMichael Rolnik 220*865f3bb9SMichael Rolnik tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */ 221*865f3bb9SMichael Rolnik tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */ 222*865f3bb9SMichael Rolnik tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */ 223*865f3bb9SMichael Rolnik tcg_gen_and_tl(t3, t3, R); 224*865f3bb9SMichael Rolnik tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */ 225*865f3bb9SMichael Rolnik 226*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */ 227*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */ 228*865f3bb9SMichael Rolnik tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); 229*865f3bb9SMichael Rolnik 230*865f3bb9SMichael Rolnik tcg_temp_free_i32(t3); 231*865f3bb9SMichael Rolnik tcg_temp_free_i32(t2); 232*865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 233*865f3bb9SMichael Rolnik } 234*865f3bb9SMichael Rolnik 235*865f3bb9SMichael Rolnik static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr) 236*865f3bb9SMichael Rolnik { 237*865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 238*865f3bb9SMichael Rolnik TCGv t2 = tcg_temp_new_i32(); 239*865f3bb9SMichael Rolnik 240*865f3bb9SMichael Rolnik /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */ 241*865f3bb9SMichael Rolnik /* = (Rd ^ R) & (Rd ^ R) */ 242*865f3bb9SMichael Rolnik tcg_gen_xor_tl(t1, Rd, R); 243*865f3bb9SMichael Rolnik tcg_gen_xor_tl(t2, Rd, Rr); 244*865f3bb9SMichael Rolnik tcg_gen_and_tl(t1, t1, t2); 245*865f3bb9SMichael Rolnik 246*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ 247*865f3bb9SMichael Rolnik 248*865f3bb9SMichael Rolnik tcg_temp_free_i32(t2); 249*865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 250*865f3bb9SMichael Rolnik } 251*865f3bb9SMichael Rolnik 252*865f3bb9SMichael Rolnik static void gen_NSf(TCGv R) 253*865f3bb9SMichael Rolnik { 254*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ 255*865f3bb9SMichael Rolnik tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ 256*865f3bb9SMichael Rolnik } 257*865f3bb9SMichael Rolnik 258*865f3bb9SMichael Rolnik static void gen_ZNSf(TCGv R) 259*865f3bb9SMichael Rolnik { 260*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 261*865f3bb9SMichael Rolnik 262*865f3bb9SMichael Rolnik /* update status register */ 263*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */ 264*865f3bb9SMichael Rolnik tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ 265*865f3bb9SMichael Rolnik } 266*865f3bb9SMichael Rolnik 267*865f3bb9SMichael Rolnik /* 268*865f3bb9SMichael Rolnik * Adds two registers without the C Flag and places the result in the 269*865f3bb9SMichael Rolnik * destination register Rd. 270*865f3bb9SMichael Rolnik */ 271*865f3bb9SMichael Rolnik static bool trans_ADD(DisasContext *ctx, arg_ADD *a) 272*865f3bb9SMichael Rolnik { 273*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 274*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 275*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 276*865f3bb9SMichael Rolnik 277*865f3bb9SMichael Rolnik tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */ 278*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 279*865f3bb9SMichael Rolnik 280*865f3bb9SMichael Rolnik /* update status register */ 281*865f3bb9SMichael Rolnik gen_add_CHf(R, Rd, Rr); 282*865f3bb9SMichael Rolnik gen_add_Vf(R, Rd, Rr); 283*865f3bb9SMichael Rolnik gen_ZNSf(R); 284*865f3bb9SMichael Rolnik 285*865f3bb9SMichael Rolnik /* update output registers */ 286*865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 287*865f3bb9SMichael Rolnik 288*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 289*865f3bb9SMichael Rolnik 290*865f3bb9SMichael Rolnik return true; 291*865f3bb9SMichael Rolnik } 292*865f3bb9SMichael Rolnik 293*865f3bb9SMichael Rolnik /* 294*865f3bb9SMichael Rolnik * Adds two registers and the contents of the C Flag and places the result in 295*865f3bb9SMichael Rolnik * the destination register Rd. 296*865f3bb9SMichael Rolnik */ 297*865f3bb9SMichael Rolnik static bool trans_ADC(DisasContext *ctx, arg_ADC *a) 298*865f3bb9SMichael Rolnik { 299*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 300*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 301*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 302*865f3bb9SMichael Rolnik 303*865f3bb9SMichael Rolnik tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */ 304*865f3bb9SMichael Rolnik tcg_gen_add_tl(R, R, cpu_Cf); 305*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 306*865f3bb9SMichael Rolnik 307*865f3bb9SMichael Rolnik /* update status register */ 308*865f3bb9SMichael Rolnik gen_add_CHf(R, Rd, Rr); 309*865f3bb9SMichael Rolnik gen_add_Vf(R, Rd, Rr); 310*865f3bb9SMichael Rolnik gen_ZNSf(R); 311*865f3bb9SMichael Rolnik 312*865f3bb9SMichael Rolnik /* update output registers */ 313*865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 314*865f3bb9SMichael Rolnik 315*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 316*865f3bb9SMichael Rolnik 317*865f3bb9SMichael Rolnik return true; 318*865f3bb9SMichael Rolnik } 319*865f3bb9SMichael Rolnik 320*865f3bb9SMichael Rolnik /* 321*865f3bb9SMichael Rolnik * Adds an immediate value (0 - 63) to a register pair and places the result 322*865f3bb9SMichael Rolnik * in the register pair. This instruction operates on the upper four register 323*865f3bb9SMichael Rolnik * pairs, and is well suited for operations on the pointer registers. This 324*865f3bb9SMichael Rolnik * instruction is not available in all devices. Refer to the device specific 325*865f3bb9SMichael Rolnik * instruction set summary. 326*865f3bb9SMichael Rolnik */ 327*865f3bb9SMichael Rolnik static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a) 328*865f3bb9SMichael Rolnik { 329*865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { 330*865f3bb9SMichael Rolnik return true; 331*865f3bb9SMichael Rolnik } 332*865f3bb9SMichael Rolnik 333*865f3bb9SMichael Rolnik TCGv RdL = cpu_r[a->rd]; 334*865f3bb9SMichael Rolnik TCGv RdH = cpu_r[a->rd + 1]; 335*865f3bb9SMichael Rolnik int Imm = (a->imm); 336*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 337*865f3bb9SMichael Rolnik TCGv Rd = tcg_temp_new_i32(); 338*865f3bb9SMichael Rolnik 339*865f3bb9SMichael Rolnik tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ 340*865f3bb9SMichael Rolnik tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */ 341*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ 342*865f3bb9SMichael Rolnik 343*865f3bb9SMichael Rolnik /* update status register */ 344*865f3bb9SMichael Rolnik tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ 345*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); 346*865f3bb9SMichael Rolnik tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */ 347*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); 348*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 349*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ 350*865f3bb9SMichael Rolnik tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */ 351*865f3bb9SMichael Rolnik 352*865f3bb9SMichael Rolnik /* update output registers */ 353*865f3bb9SMichael Rolnik tcg_gen_andi_tl(RdL, R, 0xff); 354*865f3bb9SMichael Rolnik tcg_gen_shri_tl(RdH, R, 8); 355*865f3bb9SMichael Rolnik 356*865f3bb9SMichael Rolnik tcg_temp_free_i32(Rd); 357*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 358*865f3bb9SMichael Rolnik 359*865f3bb9SMichael Rolnik return true; 360*865f3bb9SMichael Rolnik } 361*865f3bb9SMichael Rolnik 362*865f3bb9SMichael Rolnik /* 363*865f3bb9SMichael Rolnik * Subtracts two registers and places the result in the destination 364*865f3bb9SMichael Rolnik * register Rd. 365*865f3bb9SMichael Rolnik */ 366*865f3bb9SMichael Rolnik static bool trans_SUB(DisasContext *ctx, arg_SUB *a) 367*865f3bb9SMichael Rolnik { 368*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 369*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 370*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 371*865f3bb9SMichael Rolnik 372*865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */ 373*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 374*865f3bb9SMichael Rolnik 375*865f3bb9SMichael Rolnik /* update status register */ 376*865f3bb9SMichael Rolnik tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */ 377*865f3bb9SMichael Rolnik gen_sub_CHf(R, Rd, Rr); 378*865f3bb9SMichael Rolnik gen_sub_Vf(R, Rd, Rr); 379*865f3bb9SMichael Rolnik gen_ZNSf(R); 380*865f3bb9SMichael Rolnik 381*865f3bb9SMichael Rolnik /* update output registers */ 382*865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 383*865f3bb9SMichael Rolnik 384*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 385*865f3bb9SMichael Rolnik 386*865f3bb9SMichael Rolnik return true; 387*865f3bb9SMichael Rolnik } 388*865f3bb9SMichael Rolnik 389*865f3bb9SMichael Rolnik /* 390*865f3bb9SMichael Rolnik * Subtracts a register and a constant and places the result in the 391*865f3bb9SMichael Rolnik * destination register Rd. This instruction is working on Register R16 to R31 392*865f3bb9SMichael Rolnik * and is very well suited for operations on the X, Y, and Z-pointers. 393*865f3bb9SMichael Rolnik */ 394*865f3bb9SMichael Rolnik static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a) 395*865f3bb9SMichael Rolnik { 396*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 397*865f3bb9SMichael Rolnik TCGv Rr = tcg_const_i32(a->imm); 398*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 399*865f3bb9SMichael Rolnik 400*865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */ 401*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 402*865f3bb9SMichael Rolnik 403*865f3bb9SMichael Rolnik /* update status register */ 404*865f3bb9SMichael Rolnik gen_sub_CHf(R, Rd, Rr); 405*865f3bb9SMichael Rolnik gen_sub_Vf(R, Rd, Rr); 406*865f3bb9SMichael Rolnik gen_ZNSf(R); 407*865f3bb9SMichael Rolnik 408*865f3bb9SMichael Rolnik /* update output registers */ 409*865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 410*865f3bb9SMichael Rolnik 411*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 412*865f3bb9SMichael Rolnik tcg_temp_free_i32(Rr); 413*865f3bb9SMichael Rolnik 414*865f3bb9SMichael Rolnik return true; 415*865f3bb9SMichael Rolnik } 416*865f3bb9SMichael Rolnik 417*865f3bb9SMichael Rolnik /* 418*865f3bb9SMichael Rolnik * Subtracts two registers and subtracts with the C Flag and places the 419*865f3bb9SMichael Rolnik * result in the destination register Rd. 420*865f3bb9SMichael Rolnik */ 421*865f3bb9SMichael Rolnik static bool trans_SBC(DisasContext *ctx, arg_SBC *a) 422*865f3bb9SMichael Rolnik { 423*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 424*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 425*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 426*865f3bb9SMichael Rolnik TCGv zero = tcg_const_i32(0); 427*865f3bb9SMichael Rolnik 428*865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ 429*865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, R, cpu_Cf); 430*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 431*865f3bb9SMichael Rolnik 432*865f3bb9SMichael Rolnik /* update status register */ 433*865f3bb9SMichael Rolnik gen_sub_CHf(R, Rd, Rr); 434*865f3bb9SMichael Rolnik gen_sub_Vf(R, Rd, Rr); 435*865f3bb9SMichael Rolnik gen_NSf(R); 436*865f3bb9SMichael Rolnik 437*865f3bb9SMichael Rolnik /* 438*865f3bb9SMichael Rolnik * Previous value remains unchanged when the result is zero; 439*865f3bb9SMichael Rolnik * cleared otherwise. 440*865f3bb9SMichael Rolnik */ 441*865f3bb9SMichael Rolnik tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); 442*865f3bb9SMichael Rolnik 443*865f3bb9SMichael Rolnik /* update output registers */ 444*865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 445*865f3bb9SMichael Rolnik 446*865f3bb9SMichael Rolnik tcg_temp_free_i32(zero); 447*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 448*865f3bb9SMichael Rolnik 449*865f3bb9SMichael Rolnik return true; 450*865f3bb9SMichael Rolnik } 451*865f3bb9SMichael Rolnik 452*865f3bb9SMichael Rolnik /* 453*865f3bb9SMichael Rolnik * SBCI -- Subtract Immediate with Carry 454*865f3bb9SMichael Rolnik */ 455*865f3bb9SMichael Rolnik static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a) 456*865f3bb9SMichael Rolnik { 457*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 458*865f3bb9SMichael Rolnik TCGv Rr = tcg_const_i32(a->imm); 459*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 460*865f3bb9SMichael Rolnik TCGv zero = tcg_const_i32(0); 461*865f3bb9SMichael Rolnik 462*865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */ 463*865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, R, cpu_Cf); 464*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 465*865f3bb9SMichael Rolnik 466*865f3bb9SMichael Rolnik /* update status register */ 467*865f3bb9SMichael Rolnik gen_sub_CHf(R, Rd, Rr); 468*865f3bb9SMichael Rolnik gen_sub_Vf(R, Rd, Rr); 469*865f3bb9SMichael Rolnik gen_NSf(R); 470*865f3bb9SMichael Rolnik 471*865f3bb9SMichael Rolnik /* 472*865f3bb9SMichael Rolnik * Previous value remains unchanged when the result is zero; 473*865f3bb9SMichael Rolnik * cleared otherwise. 474*865f3bb9SMichael Rolnik */ 475*865f3bb9SMichael Rolnik tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero); 476*865f3bb9SMichael Rolnik 477*865f3bb9SMichael Rolnik /* update output registers */ 478*865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 479*865f3bb9SMichael Rolnik 480*865f3bb9SMichael Rolnik tcg_temp_free_i32(zero); 481*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 482*865f3bb9SMichael Rolnik tcg_temp_free_i32(Rr); 483*865f3bb9SMichael Rolnik 484*865f3bb9SMichael Rolnik return true; 485*865f3bb9SMichael Rolnik } 486*865f3bb9SMichael Rolnik 487*865f3bb9SMichael Rolnik /* 488*865f3bb9SMichael Rolnik * Subtracts an immediate value (0-63) from a register pair and places the 489*865f3bb9SMichael Rolnik * result in the register pair. This instruction operates on the upper four 490*865f3bb9SMichael Rolnik * register pairs, and is well suited for operations on the Pointer Registers. 491*865f3bb9SMichael Rolnik * This instruction is not available in all devices. Refer to the device 492*865f3bb9SMichael Rolnik * specific instruction set summary. 493*865f3bb9SMichael Rolnik */ 494*865f3bb9SMichael Rolnik static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a) 495*865f3bb9SMichael Rolnik { 496*865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) { 497*865f3bb9SMichael Rolnik return true; 498*865f3bb9SMichael Rolnik } 499*865f3bb9SMichael Rolnik 500*865f3bb9SMichael Rolnik TCGv RdL = cpu_r[a->rd]; 501*865f3bb9SMichael Rolnik TCGv RdH = cpu_r[a->rd + 1]; 502*865f3bb9SMichael Rolnik int Imm = (a->imm); 503*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 504*865f3bb9SMichael Rolnik TCGv Rd = tcg_temp_new_i32(); 505*865f3bb9SMichael Rolnik 506*865f3bb9SMichael Rolnik tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */ 507*865f3bb9SMichael Rolnik tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */ 508*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ 509*865f3bb9SMichael Rolnik 510*865f3bb9SMichael Rolnik /* update status register */ 511*865f3bb9SMichael Rolnik tcg_gen_andc_tl(cpu_Cf, R, Rd); 512*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */ 513*865f3bb9SMichael Rolnik tcg_gen_andc_tl(cpu_Vf, Rd, R); 514*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */ 515*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 516*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */ 517*865f3bb9SMichael Rolnik tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ 518*865f3bb9SMichael Rolnik 519*865f3bb9SMichael Rolnik /* update output registers */ 520*865f3bb9SMichael Rolnik tcg_gen_andi_tl(RdL, R, 0xff); 521*865f3bb9SMichael Rolnik tcg_gen_shri_tl(RdH, R, 8); 522*865f3bb9SMichael Rolnik 523*865f3bb9SMichael Rolnik tcg_temp_free_i32(Rd); 524*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 525*865f3bb9SMichael Rolnik 526*865f3bb9SMichael Rolnik return true; 527*865f3bb9SMichael Rolnik } 528*865f3bb9SMichael Rolnik 529*865f3bb9SMichael Rolnik /* 530*865f3bb9SMichael Rolnik * Performs the logical AND between the contents of register Rd and register 531*865f3bb9SMichael Rolnik * Rr and places the result in the destination register Rd. 532*865f3bb9SMichael Rolnik */ 533*865f3bb9SMichael Rolnik static bool trans_AND(DisasContext *ctx, arg_AND *a) 534*865f3bb9SMichael Rolnik { 535*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 536*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 537*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 538*865f3bb9SMichael Rolnik 539*865f3bb9SMichael Rolnik tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */ 540*865f3bb9SMichael Rolnik 541*865f3bb9SMichael Rolnik /* update status register */ 542*865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ 543*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 544*865f3bb9SMichael Rolnik gen_ZNSf(R); 545*865f3bb9SMichael Rolnik 546*865f3bb9SMichael Rolnik /* update output registers */ 547*865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 548*865f3bb9SMichael Rolnik 549*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 550*865f3bb9SMichael Rolnik 551*865f3bb9SMichael Rolnik return true; 552*865f3bb9SMichael Rolnik } 553*865f3bb9SMichael Rolnik 554*865f3bb9SMichael Rolnik /* 555*865f3bb9SMichael Rolnik * Performs the logical AND between the contents of register Rd and a constant 556*865f3bb9SMichael Rolnik * and places the result in the destination register Rd. 557*865f3bb9SMichael Rolnik */ 558*865f3bb9SMichael Rolnik static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a) 559*865f3bb9SMichael Rolnik { 560*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 561*865f3bb9SMichael Rolnik int Imm = (a->imm); 562*865f3bb9SMichael Rolnik 563*865f3bb9SMichael Rolnik tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */ 564*865f3bb9SMichael Rolnik 565*865f3bb9SMichael Rolnik /* update status register */ 566*865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ 567*865f3bb9SMichael Rolnik gen_ZNSf(Rd); 568*865f3bb9SMichael Rolnik 569*865f3bb9SMichael Rolnik return true; 570*865f3bb9SMichael Rolnik } 571*865f3bb9SMichael Rolnik 572*865f3bb9SMichael Rolnik /* 573*865f3bb9SMichael Rolnik * Performs the logical OR between the contents of register Rd and register 574*865f3bb9SMichael Rolnik * Rr and places the result in the destination register Rd. 575*865f3bb9SMichael Rolnik */ 576*865f3bb9SMichael Rolnik static bool trans_OR(DisasContext *ctx, arg_OR *a) 577*865f3bb9SMichael Rolnik { 578*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 579*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 580*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 581*865f3bb9SMichael Rolnik 582*865f3bb9SMichael Rolnik tcg_gen_or_tl(R, Rd, Rr); 583*865f3bb9SMichael Rolnik 584*865f3bb9SMichael Rolnik /* update status register */ 585*865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0); 586*865f3bb9SMichael Rolnik gen_ZNSf(R); 587*865f3bb9SMichael Rolnik 588*865f3bb9SMichael Rolnik /* update output registers */ 589*865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 590*865f3bb9SMichael Rolnik 591*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 592*865f3bb9SMichael Rolnik 593*865f3bb9SMichael Rolnik return true; 594*865f3bb9SMichael Rolnik } 595*865f3bb9SMichael Rolnik 596*865f3bb9SMichael Rolnik /* 597*865f3bb9SMichael Rolnik * Performs the logical OR between the contents of register Rd and a 598*865f3bb9SMichael Rolnik * constant and places the result in the destination register Rd. 599*865f3bb9SMichael Rolnik */ 600*865f3bb9SMichael Rolnik static bool trans_ORI(DisasContext *ctx, arg_ORI *a) 601*865f3bb9SMichael Rolnik { 602*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 603*865f3bb9SMichael Rolnik int Imm = (a->imm); 604*865f3bb9SMichael Rolnik 605*865f3bb9SMichael Rolnik tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */ 606*865f3bb9SMichael Rolnik 607*865f3bb9SMichael Rolnik /* update status register */ 608*865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */ 609*865f3bb9SMichael Rolnik gen_ZNSf(Rd); 610*865f3bb9SMichael Rolnik 611*865f3bb9SMichael Rolnik return true; 612*865f3bb9SMichael Rolnik } 613*865f3bb9SMichael Rolnik 614*865f3bb9SMichael Rolnik /* 615*865f3bb9SMichael Rolnik * Performs the logical EOR between the contents of register Rd and 616*865f3bb9SMichael Rolnik * register Rr and places the result in the destination register Rd. 617*865f3bb9SMichael Rolnik */ 618*865f3bb9SMichael Rolnik static bool trans_EOR(DisasContext *ctx, arg_EOR *a) 619*865f3bb9SMichael Rolnik { 620*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 621*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 622*865f3bb9SMichael Rolnik 623*865f3bb9SMichael Rolnik tcg_gen_xor_tl(Rd, Rd, Rr); 624*865f3bb9SMichael Rolnik 625*865f3bb9SMichael Rolnik /* update status register */ 626*865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0); 627*865f3bb9SMichael Rolnik gen_ZNSf(Rd); 628*865f3bb9SMichael Rolnik 629*865f3bb9SMichael Rolnik return true; 630*865f3bb9SMichael Rolnik } 631*865f3bb9SMichael Rolnik 632*865f3bb9SMichael Rolnik /* 633*865f3bb9SMichael Rolnik * Clears the specified bits in register Rd. Performs the logical AND 634*865f3bb9SMichael Rolnik * between the contents of register Rd and the complement of the constant mask 635*865f3bb9SMichael Rolnik * K. The result will be placed in register Rd. 636*865f3bb9SMichael Rolnik */ 637*865f3bb9SMichael Rolnik static bool trans_COM(DisasContext *ctx, arg_COM *a) 638*865f3bb9SMichael Rolnik { 639*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 640*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 641*865f3bb9SMichael Rolnik 642*865f3bb9SMichael Rolnik tcg_gen_xori_tl(Rd, Rd, 0xff); 643*865f3bb9SMichael Rolnik 644*865f3bb9SMichael Rolnik /* update status register */ 645*865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */ 646*865f3bb9SMichael Rolnik tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */ 647*865f3bb9SMichael Rolnik gen_ZNSf(Rd); 648*865f3bb9SMichael Rolnik 649*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 650*865f3bb9SMichael Rolnik 651*865f3bb9SMichael Rolnik return true; 652*865f3bb9SMichael Rolnik } 653*865f3bb9SMichael Rolnik 654*865f3bb9SMichael Rolnik /* 655*865f3bb9SMichael Rolnik * Replaces the contents of register Rd with its two's complement; the 656*865f3bb9SMichael Rolnik * value $80 is left unchanged. 657*865f3bb9SMichael Rolnik */ 658*865f3bb9SMichael Rolnik static bool trans_NEG(DisasContext *ctx, arg_NEG *a) 659*865f3bb9SMichael Rolnik { 660*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 661*865f3bb9SMichael Rolnik TCGv t0 = tcg_const_i32(0); 662*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 663*865f3bb9SMichael Rolnik 664*865f3bb9SMichael Rolnik tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */ 665*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */ 666*865f3bb9SMichael Rolnik 667*865f3bb9SMichael Rolnik /* update status register */ 668*865f3bb9SMichael Rolnik gen_sub_CHf(R, t0, Rd); 669*865f3bb9SMichael Rolnik gen_sub_Vf(R, t0, Rd); 670*865f3bb9SMichael Rolnik gen_ZNSf(R); 671*865f3bb9SMichael Rolnik 672*865f3bb9SMichael Rolnik /* update output registers */ 673*865f3bb9SMichael Rolnik tcg_gen_mov_tl(Rd, R); 674*865f3bb9SMichael Rolnik 675*865f3bb9SMichael Rolnik tcg_temp_free_i32(t0); 676*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 677*865f3bb9SMichael Rolnik 678*865f3bb9SMichael Rolnik return true; 679*865f3bb9SMichael Rolnik } 680*865f3bb9SMichael Rolnik 681*865f3bb9SMichael Rolnik /* 682*865f3bb9SMichael Rolnik * Adds one -1- to the contents of register Rd and places the result in the 683*865f3bb9SMichael Rolnik * destination register Rd. The C Flag in SREG is not affected by the 684*865f3bb9SMichael Rolnik * operation, thus allowing the INC instruction to be used on a loop counter in 685*865f3bb9SMichael Rolnik * multiple-precision computations. When operating on unsigned numbers, only 686*865f3bb9SMichael Rolnik * BREQ and BRNE branches can be expected to perform consistently. When 687*865f3bb9SMichael Rolnik * operating on two's complement values, all signed branches are available. 688*865f3bb9SMichael Rolnik */ 689*865f3bb9SMichael Rolnik static bool trans_INC(DisasContext *ctx, arg_INC *a) 690*865f3bb9SMichael Rolnik { 691*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 692*865f3bb9SMichael Rolnik 693*865f3bb9SMichael Rolnik tcg_gen_addi_tl(Rd, Rd, 1); 694*865f3bb9SMichael Rolnik tcg_gen_andi_tl(Rd, Rd, 0xff); 695*865f3bb9SMichael Rolnik 696*865f3bb9SMichael Rolnik /* update status register */ 697*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */ 698*865f3bb9SMichael Rolnik gen_ZNSf(Rd); 699*865f3bb9SMichael Rolnik 700*865f3bb9SMichael Rolnik return true; 701*865f3bb9SMichael Rolnik } 702*865f3bb9SMichael Rolnik 703*865f3bb9SMichael Rolnik /* 704*865f3bb9SMichael Rolnik * Subtracts one -1- from the contents of register Rd and places the result 705*865f3bb9SMichael Rolnik * in the destination register Rd. The C Flag in SREG is not affected by the 706*865f3bb9SMichael Rolnik * operation, thus allowing the DEC instruction to be used on a loop counter in 707*865f3bb9SMichael Rolnik * multiple-precision computations. When operating on unsigned values, only 708*865f3bb9SMichael Rolnik * BREQ and BRNE branches can be expected to perform consistently. When 709*865f3bb9SMichael Rolnik * operating on two's complement values, all signed branches are available. 710*865f3bb9SMichael Rolnik */ 711*865f3bb9SMichael Rolnik static bool trans_DEC(DisasContext *ctx, arg_DEC *a) 712*865f3bb9SMichael Rolnik { 713*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 714*865f3bb9SMichael Rolnik 715*865f3bb9SMichael Rolnik tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */ 716*865f3bb9SMichael Rolnik tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */ 717*865f3bb9SMichael Rolnik 718*865f3bb9SMichael Rolnik /* update status register */ 719*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */ 720*865f3bb9SMichael Rolnik gen_ZNSf(Rd); 721*865f3bb9SMichael Rolnik 722*865f3bb9SMichael Rolnik return true; 723*865f3bb9SMichael Rolnik } 724*865f3bb9SMichael Rolnik 725*865f3bb9SMichael Rolnik /* 726*865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication. 727*865f3bb9SMichael Rolnik */ 728*865f3bb9SMichael Rolnik static bool trans_MUL(DisasContext *ctx, arg_MUL *a) 729*865f3bb9SMichael Rolnik { 730*865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 731*865f3bb9SMichael Rolnik return true; 732*865f3bb9SMichael Rolnik } 733*865f3bb9SMichael Rolnik 734*865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 735*865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 736*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 737*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 738*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 739*865f3bb9SMichael Rolnik 740*865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ 741*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 742*865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 743*865f3bb9SMichael Rolnik 744*865f3bb9SMichael Rolnik /* update status register */ 745*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 746*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 747*865f3bb9SMichael Rolnik 748*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 749*865f3bb9SMichael Rolnik 750*865f3bb9SMichael Rolnik return true; 751*865f3bb9SMichael Rolnik } 752*865f3bb9SMichael Rolnik 753*865f3bb9SMichael Rolnik /* 754*865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication. 755*865f3bb9SMichael Rolnik */ 756*865f3bb9SMichael Rolnik static bool trans_MULS(DisasContext *ctx, arg_MULS *a) 757*865f3bb9SMichael Rolnik { 758*865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 759*865f3bb9SMichael Rolnik return true; 760*865f3bb9SMichael Rolnik } 761*865f3bb9SMichael Rolnik 762*865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 763*865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 764*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 765*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 766*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 767*865f3bb9SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 768*865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 769*865f3bb9SMichael Rolnik 770*865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ 771*865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ 772*865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ 773*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ 774*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 775*865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 776*865f3bb9SMichael Rolnik 777*865f3bb9SMichael Rolnik /* update status register */ 778*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 779*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 780*865f3bb9SMichael Rolnik 781*865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 782*865f3bb9SMichael Rolnik tcg_temp_free_i32(t0); 783*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 784*865f3bb9SMichael Rolnik 785*865f3bb9SMichael Rolnik return true; 786*865f3bb9SMichael Rolnik } 787*865f3bb9SMichael Rolnik 788*865f3bb9SMichael Rolnik /* 789*865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a 790*865f3bb9SMichael Rolnik * signed and an unsigned number. 791*865f3bb9SMichael Rolnik */ 792*865f3bb9SMichael Rolnik static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a) 793*865f3bb9SMichael Rolnik { 794*865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 795*865f3bb9SMichael Rolnik return true; 796*865f3bb9SMichael Rolnik } 797*865f3bb9SMichael Rolnik 798*865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 799*865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 800*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 801*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 802*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 803*865f3bb9SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 804*865f3bb9SMichael Rolnik 805*865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ 806*865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ 807*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */ 808*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 809*865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 810*865f3bb9SMichael Rolnik 811*865f3bb9SMichael Rolnik /* update status register */ 812*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 813*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 814*865f3bb9SMichael Rolnik 815*865f3bb9SMichael Rolnik tcg_temp_free_i32(t0); 816*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 817*865f3bb9SMichael Rolnik 818*865f3bb9SMichael Rolnik return true; 819*865f3bb9SMichael Rolnik } 820*865f3bb9SMichael Rolnik 821*865f3bb9SMichael Rolnik /* 822*865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit unsigned 823*865f3bb9SMichael Rolnik * multiplication and shifts the result one bit left. 824*865f3bb9SMichael Rolnik */ 825*865f3bb9SMichael Rolnik static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a) 826*865f3bb9SMichael Rolnik { 827*865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 828*865f3bb9SMichael Rolnik return true; 829*865f3bb9SMichael Rolnik } 830*865f3bb9SMichael Rolnik 831*865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 832*865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 833*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 834*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 835*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 836*865f3bb9SMichael Rolnik 837*865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */ 838*865f3bb9SMichael Rolnik 839*865f3bb9SMichael Rolnik /* update status register */ 840*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 841*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 842*865f3bb9SMichael Rolnik 843*865f3bb9SMichael Rolnik /* update output registers */ 844*865f3bb9SMichael Rolnik tcg_gen_shli_tl(R, R, 1); 845*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 846*865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 847*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R1, R1, 0xff); 848*865f3bb9SMichael Rolnik 849*865f3bb9SMichael Rolnik 850*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 851*865f3bb9SMichael Rolnik 852*865f3bb9SMichael Rolnik return true; 853*865f3bb9SMichael Rolnik } 854*865f3bb9SMichael Rolnik 855*865f3bb9SMichael Rolnik /* 856*865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication 857*865f3bb9SMichael Rolnik * and shifts the result one bit left. 858*865f3bb9SMichael Rolnik */ 859*865f3bb9SMichael Rolnik static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a) 860*865f3bb9SMichael Rolnik { 861*865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 862*865f3bb9SMichael Rolnik return true; 863*865f3bb9SMichael Rolnik } 864*865f3bb9SMichael Rolnik 865*865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 866*865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 867*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 868*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 869*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 870*865f3bb9SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 871*865f3bb9SMichael Rolnik TCGv t1 = tcg_temp_new_i32(); 872*865f3bb9SMichael Rolnik 873*865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ 874*865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */ 875*865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */ 876*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ 877*865f3bb9SMichael Rolnik 878*865f3bb9SMichael Rolnik /* update status register */ 879*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 880*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 881*865f3bb9SMichael Rolnik 882*865f3bb9SMichael Rolnik /* update output registers */ 883*865f3bb9SMichael Rolnik tcg_gen_shli_tl(R, R, 1); 884*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 885*865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 886*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R1, R1, 0xff); 887*865f3bb9SMichael Rolnik 888*865f3bb9SMichael Rolnik tcg_temp_free_i32(t1); 889*865f3bb9SMichael Rolnik tcg_temp_free_i32(t0); 890*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 891*865f3bb9SMichael Rolnik 892*865f3bb9SMichael Rolnik return true; 893*865f3bb9SMichael Rolnik } 894*865f3bb9SMichael Rolnik 895*865f3bb9SMichael Rolnik /* 896*865f3bb9SMichael Rolnik * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication 897*865f3bb9SMichael Rolnik * and shifts the result one bit left. 898*865f3bb9SMichael Rolnik */ 899*865f3bb9SMichael Rolnik static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a) 900*865f3bb9SMichael Rolnik { 901*865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) { 902*865f3bb9SMichael Rolnik return true; 903*865f3bb9SMichael Rolnik } 904*865f3bb9SMichael Rolnik 905*865f3bb9SMichael Rolnik TCGv R0 = cpu_r[0]; 906*865f3bb9SMichael Rolnik TCGv R1 = cpu_r[1]; 907*865f3bb9SMichael Rolnik TCGv Rd = cpu_r[a->rd]; 908*865f3bb9SMichael Rolnik TCGv Rr = cpu_r[a->rr]; 909*865f3bb9SMichael Rolnik TCGv R = tcg_temp_new_i32(); 910*865f3bb9SMichael Rolnik TCGv t0 = tcg_temp_new_i32(); 911*865f3bb9SMichael Rolnik 912*865f3bb9SMichael Rolnik tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */ 913*865f3bb9SMichael Rolnik tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */ 914*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */ 915*865f3bb9SMichael Rolnik 916*865f3bb9SMichael Rolnik /* update status register */ 917*865f3bb9SMichael Rolnik tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */ 918*865f3bb9SMichael Rolnik tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */ 919*865f3bb9SMichael Rolnik 920*865f3bb9SMichael Rolnik /* update output registers */ 921*865f3bb9SMichael Rolnik tcg_gen_shli_tl(R, R, 1); 922*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R0, R, 0xff); 923*865f3bb9SMichael Rolnik tcg_gen_shri_tl(R1, R, 8); 924*865f3bb9SMichael Rolnik tcg_gen_andi_tl(R1, R1, 0xff); 925*865f3bb9SMichael Rolnik 926*865f3bb9SMichael Rolnik tcg_temp_free_i32(t0); 927*865f3bb9SMichael Rolnik tcg_temp_free_i32(R); 928*865f3bb9SMichael Rolnik 929*865f3bb9SMichael Rolnik return true; 930*865f3bb9SMichael Rolnik } 931*865f3bb9SMichael Rolnik 932*865f3bb9SMichael Rolnik /* 933*865f3bb9SMichael Rolnik * The module is an instruction set extension to the AVR CPU, performing 934*865f3bb9SMichael Rolnik * DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in 935*865f3bb9SMichael Rolnik * the CPU register file, registers R0-R7, where LSB of data is placed in LSB 936*865f3bb9SMichael Rolnik * of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including 937*865f3bb9SMichael Rolnik * parity bits) is placed in registers R8- R15, organized in the register file 938*865f3bb9SMichael Rolnik * with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES 939*865f3bb9SMichael Rolnik * instruction performs one round in the DES algorithm. Sixteen rounds must be 940*865f3bb9SMichael Rolnik * executed in increasing order to form the correct DES ciphertext or 941*865f3bb9SMichael Rolnik * plaintext. Intermediate results are stored in the register file (R0-R15) 942*865f3bb9SMichael Rolnik * after each DES instruction. The instruction's operand (K) determines which 943*865f3bb9SMichael Rolnik * round is executed, and the half carry flag (H) determines whether encryption 944*865f3bb9SMichael Rolnik * or decryption is performed. The DES algorithm is described in 945*865f3bb9SMichael Rolnik * "Specifications for the Data Encryption Standard" (Federal Information 946*865f3bb9SMichael Rolnik * Processing Standards Publication 46). Intermediate results in this 947*865f3bb9SMichael Rolnik * implementation differ from the standard because the initial permutation and 948*865f3bb9SMichael Rolnik * the inverse initial permutation are performed each iteration. This does not 949*865f3bb9SMichael Rolnik * affect the result in the final ciphertext or plaintext, but reduces 950*865f3bb9SMichael Rolnik * execution time. 951*865f3bb9SMichael Rolnik */ 952*865f3bb9SMichael Rolnik static bool trans_DES(DisasContext *ctx, arg_DES *a) 953*865f3bb9SMichael Rolnik { 954*865f3bb9SMichael Rolnik /* TODO */ 955*865f3bb9SMichael Rolnik if (!avr_have_feature(ctx, AVR_FEATURE_DES)) { 956*865f3bb9SMichael Rolnik return true; 957*865f3bb9SMichael Rolnik } 958*865f3bb9SMichael Rolnik 959*865f3bb9SMichael Rolnik qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__); 960*865f3bb9SMichael Rolnik 961*865f3bb9SMichael Rolnik return true; 962*865f3bb9SMichael Rolnik } 963