target/avr: Add instruction translation - Arithmetic and Logic Instructions
[qemu/ar7.git] / target / avr / translate.c
blobfae9ed742df16cc00cb79f81df6f92bdb098200e
1 /*
2 * QEMU AVR CPU
4 * Copyright (c) 2019-2020 Michael Rolnik
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see
18 * <http://www.gnu.org/licenses/lgpl-2.1.html>
21 #include "qemu/osdep.h"
22 #include "qemu/qemu-print.h"
23 #include "tcg/tcg.h"
24 #include "cpu.h"
25 #include "exec/exec-all.h"
26 #include "tcg/tcg-op.h"
27 #include "exec/cpu_ldst.h"
28 #include "exec/helper-proto.h"
29 #include "exec/helper-gen.h"
30 #include "exec/log.h"
31 #include "exec/translator.h"
32 #include "exec/gen-icount.h"
35 * Define if you want a BREAK instruction translated to a breakpoint
36 * Active debugging connection is assumed
37 * This is for
38 * https://github.com/seharris/qemu-avr-tests/tree/master/instruction-tests
39 * tests
41 #undef BREAKPOINT_ON_BREAK
43 static TCGv cpu_pc;
45 static TCGv cpu_Cf;
46 static TCGv cpu_Zf;
47 static TCGv cpu_Nf;
48 static TCGv cpu_Vf;
49 static TCGv cpu_Sf;
50 static TCGv cpu_Hf;
51 static TCGv cpu_Tf;
52 static TCGv cpu_If;
54 static TCGv cpu_rampD;
55 static TCGv cpu_rampX;
56 static TCGv cpu_rampY;
57 static TCGv cpu_rampZ;
59 static TCGv cpu_r[NUMBER_OF_CPU_REGISTERS];
60 static TCGv cpu_eind;
61 static TCGv cpu_sp;
63 static TCGv cpu_skip;
65 static const char reg_names[NUMBER_OF_CPU_REGISTERS][8] = {
66 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
67 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
68 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
69 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
71 #define REG(x) (cpu_r[x])
73 enum {
74 DISAS_EXIT = DISAS_TARGET_0, /* We want return to the cpu main loop. */
75 DISAS_LOOKUP = DISAS_TARGET_1, /* We have a variable condition exit. */
76 DISAS_CHAIN = DISAS_TARGET_2, /* We have a single condition exit. */
79 typedef struct DisasContext DisasContext;
81 /* This is the state at translation time. */
82 struct DisasContext {
83 TranslationBlock *tb;
85 CPUAVRState *env;
86 CPUState *cs;
88 target_long npc;
89 uint32_t opcode;
91 /* Routine used to access memory */
92 int memidx;
93 int bstate;
94 int singlestep;
97 * some AVR instructions can make the following instruction to be skipped
98 * Let's name those instructions
99 * A - instruction that can skip the next one
100 * B - instruction that can be skipped. this depends on execution of A
101 * there are two scenarios
102 * 1. A and B belong to the same translation block
103 * 2. A is the last instruction in the translation block and B is the last
105 * following variables are used to simplify the skipping logic, they are
106 * used in the following manner (sketch)
108 * TCGLabel *skip_label = NULL;
109 * if (ctx.skip_cond != TCG_COND_NEVER) {
110 * skip_label = gen_new_label();
111 * tcg_gen_brcond_tl(skip_cond, skip_var0, skip_var1, skip_label);
114 * if (free_skip_var0) {
115 * tcg_temp_free(skip_var0);
116 * free_skip_var0 = false;
119 * translate(&ctx);
121 * if (skip_label) {
122 * gen_set_label(skip_label);
125 TCGv skip_var0;
126 TCGv skip_var1;
127 TCGCond skip_cond;
128 bool free_skip_var0;
131 static int to_regs_16_31_by_one(DisasContext *ctx, int indx)
133 return 16 + (indx % 16);
136 static int to_regs_16_23_by_one(DisasContext *ctx, int indx)
138 return 16 + (indx % 8);
141 static int to_regs_24_30_by_two(DisasContext *ctx, int indx)
143 return 24 + (indx % 4) * 2;
147 static bool avr_have_feature(DisasContext *ctx, int feature)
149 if (!avr_feature(ctx->env, feature)) {
150 gen_helper_unsupported(cpu_env);
151 ctx->bstate = DISAS_NORETURN;
152 return false;
154 return true;
157 static bool decode_insn(DisasContext *ctx, uint16_t insn);
158 #include "decode_insn.inc.c"
161 * Arithmetic Instructions
165 * Utility functions for updating status registers:
167 * - gen_add_CHf()
168 * - gen_add_Vf()
169 * - gen_sub_CHf()
170 * - gen_sub_Vf()
171 * - gen_NSf()
172 * - gen_ZNSf()
176 static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr)
178 TCGv t1 = tcg_temp_new_i32();
179 TCGv t2 = tcg_temp_new_i32();
180 TCGv t3 = tcg_temp_new_i32();
182 tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */
183 tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */
184 tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */
185 tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */
186 tcg_gen_or_tl(t1, t1, t3);
188 tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */
189 tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */
190 tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
192 tcg_temp_free_i32(t3);
193 tcg_temp_free_i32(t2);
194 tcg_temp_free_i32(t1);
197 static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
199 TCGv t1 = tcg_temp_new_i32();
200 TCGv t2 = tcg_temp_new_i32();
202 /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */
203 /* = (Rd ^ R) & ~(Rd ^ Rr) */
204 tcg_gen_xor_tl(t1, Rd, R);
205 tcg_gen_xor_tl(t2, Rd, Rr);
206 tcg_gen_andc_tl(t1, t1, t2);
208 tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
210 tcg_temp_free_i32(t2);
211 tcg_temp_free_i32(t1);
214 static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
216 TCGv t1 = tcg_temp_new_i32();
217 TCGv t2 = tcg_temp_new_i32();
218 TCGv t3 = tcg_temp_new_i32();
220 tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */
221 tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */
222 tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */
223 tcg_gen_and_tl(t3, t3, R);
224 tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */
226 tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */
227 tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */
228 tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
230 tcg_temp_free_i32(t3);
231 tcg_temp_free_i32(t2);
232 tcg_temp_free_i32(t1);
235 static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
237 TCGv t1 = tcg_temp_new_i32();
238 TCGv t2 = tcg_temp_new_i32();
240 /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */
241 /* = (Rd ^ R) & (Rd ^ R) */
242 tcg_gen_xor_tl(t1, Rd, R);
243 tcg_gen_xor_tl(t2, Rd, Rr);
244 tcg_gen_and_tl(t1, t1, t2);
246 tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
248 tcg_temp_free_i32(t2);
249 tcg_temp_free_i32(t1);
252 static void gen_NSf(TCGv R)
254 tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
255 tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
258 static void gen_ZNSf(TCGv R)
260 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
262 /* update status register */
263 tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
264 tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
268 * Adds two registers without the C Flag and places the result in the
269 * destination register Rd.
271 static bool trans_ADD(DisasContext *ctx, arg_ADD *a)
273 TCGv Rd = cpu_r[a->rd];
274 TCGv Rr = cpu_r[a->rr];
275 TCGv R = tcg_temp_new_i32();
277 tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */
278 tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
280 /* update status register */
281 gen_add_CHf(R, Rd, Rr);
282 gen_add_Vf(R, Rd, Rr);
283 gen_ZNSf(R);
285 /* update output registers */
286 tcg_gen_mov_tl(Rd, R);
288 tcg_temp_free_i32(R);
290 return true;
294 * Adds two registers and the contents of the C Flag and places the result in
295 * the destination register Rd.
297 static bool trans_ADC(DisasContext *ctx, arg_ADC *a)
299 TCGv Rd = cpu_r[a->rd];
300 TCGv Rr = cpu_r[a->rr];
301 TCGv R = tcg_temp_new_i32();
303 tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */
304 tcg_gen_add_tl(R, R, cpu_Cf);
305 tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
307 /* update status register */
308 gen_add_CHf(R, Rd, Rr);
309 gen_add_Vf(R, Rd, Rr);
310 gen_ZNSf(R);
312 /* update output registers */
313 tcg_gen_mov_tl(Rd, R);
315 tcg_temp_free_i32(R);
317 return true;
321 * Adds an immediate value (0 - 63) to a register pair and places the result
322 * in the register pair. This instruction operates on the upper four register
323 * pairs, and is well suited for operations on the pointer registers. This
324 * instruction is not available in all devices. Refer to the device specific
325 * instruction set summary.
327 static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a)
329 if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
330 return true;
333 TCGv RdL = cpu_r[a->rd];
334 TCGv RdH = cpu_r[a->rd + 1];
335 int Imm = (a->imm);
336 TCGv R = tcg_temp_new_i32();
337 TCGv Rd = tcg_temp_new_i32();
339 tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
340 tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */
341 tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
343 /* update status register */
344 tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
345 tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15);
346 tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */
347 tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15);
348 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
349 tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
350 tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */
352 /* update output registers */
353 tcg_gen_andi_tl(RdL, R, 0xff);
354 tcg_gen_shri_tl(RdH, R, 8);
356 tcg_temp_free_i32(Rd);
357 tcg_temp_free_i32(R);
359 return true;
363 * Subtracts two registers and places the result in the destination
364 * register Rd.
366 static bool trans_SUB(DisasContext *ctx, arg_SUB *a)
368 TCGv Rd = cpu_r[a->rd];
369 TCGv Rr = cpu_r[a->rr];
370 TCGv R = tcg_temp_new_i32();
372 tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
373 tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
375 /* update status register */
376 tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
377 gen_sub_CHf(R, Rd, Rr);
378 gen_sub_Vf(R, Rd, Rr);
379 gen_ZNSf(R);
381 /* update output registers */
382 tcg_gen_mov_tl(Rd, R);
384 tcg_temp_free_i32(R);
386 return true;
390 * Subtracts a register and a constant and places the result in the
391 * destination register Rd. This instruction is working on Register R16 to R31
392 * and is very well suited for operations on the X, Y, and Z-pointers.
394 static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a)
396 TCGv Rd = cpu_r[a->rd];
397 TCGv Rr = tcg_const_i32(a->imm);
398 TCGv R = tcg_temp_new_i32();
400 tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */
401 tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
403 /* update status register */
404 gen_sub_CHf(R, Rd, Rr);
405 gen_sub_Vf(R, Rd, Rr);
406 gen_ZNSf(R);
408 /* update output registers */
409 tcg_gen_mov_tl(Rd, R);
411 tcg_temp_free_i32(R);
412 tcg_temp_free_i32(Rr);
414 return true;
418 * Subtracts two registers and subtracts with the C Flag and places the
419 * result in the destination register Rd.
421 static bool trans_SBC(DisasContext *ctx, arg_SBC *a)
423 TCGv Rd = cpu_r[a->rd];
424 TCGv Rr = cpu_r[a->rr];
425 TCGv R = tcg_temp_new_i32();
426 TCGv zero = tcg_const_i32(0);
428 tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
429 tcg_gen_sub_tl(R, R, cpu_Cf);
430 tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
432 /* update status register */
433 gen_sub_CHf(R, Rd, Rr);
434 gen_sub_Vf(R, Rd, Rr);
435 gen_NSf(R);
438 * Previous value remains unchanged when the result is zero;
439 * cleared otherwise.
441 tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
443 /* update output registers */
444 tcg_gen_mov_tl(Rd, R);
446 tcg_temp_free_i32(zero);
447 tcg_temp_free_i32(R);
449 return true;
453 * SBCI -- Subtract Immediate with Carry
455 static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a)
457 TCGv Rd = cpu_r[a->rd];
458 TCGv Rr = tcg_const_i32(a->imm);
459 TCGv R = tcg_temp_new_i32();
460 TCGv zero = tcg_const_i32(0);
462 tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
463 tcg_gen_sub_tl(R, R, cpu_Cf);
464 tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
466 /* update status register */
467 gen_sub_CHf(R, Rd, Rr);
468 gen_sub_Vf(R, Rd, Rr);
469 gen_NSf(R);
472 * Previous value remains unchanged when the result is zero;
473 * cleared otherwise.
475 tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
477 /* update output registers */
478 tcg_gen_mov_tl(Rd, R);
480 tcg_temp_free_i32(zero);
481 tcg_temp_free_i32(R);
482 tcg_temp_free_i32(Rr);
484 return true;
488 * Subtracts an immediate value (0-63) from a register pair and places the
489 * result in the register pair. This instruction operates on the upper four
490 * register pairs, and is well suited for operations on the Pointer Registers.
491 * This instruction is not available in all devices. Refer to the device
492 * specific instruction set summary.
494 static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a)
496 if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
497 return true;
500 TCGv RdL = cpu_r[a->rd];
501 TCGv RdH = cpu_r[a->rd + 1];
502 int Imm = (a->imm);
503 TCGv R = tcg_temp_new_i32();
504 TCGv Rd = tcg_temp_new_i32();
506 tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
507 tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */
508 tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
510 /* update status register */
511 tcg_gen_andc_tl(cpu_Cf, R, Rd);
512 tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */
513 tcg_gen_andc_tl(cpu_Vf, Rd, R);
514 tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */
515 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
516 tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
517 tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
519 /* update output registers */
520 tcg_gen_andi_tl(RdL, R, 0xff);
521 tcg_gen_shri_tl(RdH, R, 8);
523 tcg_temp_free_i32(Rd);
524 tcg_temp_free_i32(R);
526 return true;
530 * Performs the logical AND between the contents of register Rd and register
531 * Rr and places the result in the destination register Rd.
533 static bool trans_AND(DisasContext *ctx, arg_AND *a)
535 TCGv Rd = cpu_r[a->rd];
536 TCGv Rr = cpu_r[a->rr];
537 TCGv R = tcg_temp_new_i32();
539 tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */
541 /* update status register */
542 tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
543 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
544 gen_ZNSf(R);
546 /* update output registers */
547 tcg_gen_mov_tl(Rd, R);
549 tcg_temp_free_i32(R);
551 return true;
555 * Performs the logical AND between the contents of register Rd and a constant
556 * and places the result in the destination register Rd.
558 static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a)
560 TCGv Rd = cpu_r[a->rd];
561 int Imm = (a->imm);
563 tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */
565 /* update status register */
566 tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
567 gen_ZNSf(Rd);
569 return true;
573 * Performs the logical OR between the contents of register Rd and register
574 * Rr and places the result in the destination register Rd.
576 static bool trans_OR(DisasContext *ctx, arg_OR *a)
578 TCGv Rd = cpu_r[a->rd];
579 TCGv Rr = cpu_r[a->rr];
580 TCGv R = tcg_temp_new_i32();
582 tcg_gen_or_tl(R, Rd, Rr);
584 /* update status register */
585 tcg_gen_movi_tl(cpu_Vf, 0);
586 gen_ZNSf(R);
588 /* update output registers */
589 tcg_gen_mov_tl(Rd, R);
591 tcg_temp_free_i32(R);
593 return true;
597 * Performs the logical OR between the contents of register Rd and a
598 * constant and places the result in the destination register Rd.
600 static bool trans_ORI(DisasContext *ctx, arg_ORI *a)
602 TCGv Rd = cpu_r[a->rd];
603 int Imm = (a->imm);
605 tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */
607 /* update status register */
608 tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
609 gen_ZNSf(Rd);
611 return true;
615 * Performs the logical EOR between the contents of register Rd and
616 * register Rr and places the result in the destination register Rd.
618 static bool trans_EOR(DisasContext *ctx, arg_EOR *a)
620 TCGv Rd = cpu_r[a->rd];
621 TCGv Rr = cpu_r[a->rr];
623 tcg_gen_xor_tl(Rd, Rd, Rr);
625 /* update status register */
626 tcg_gen_movi_tl(cpu_Vf, 0);
627 gen_ZNSf(Rd);
629 return true;
633 * Clears the specified bits in register Rd. Performs the logical AND
634 * between the contents of register Rd and the complement of the constant mask
635 * K. The result will be placed in register Rd.
637 static bool trans_COM(DisasContext *ctx, arg_COM *a)
639 TCGv Rd = cpu_r[a->rd];
640 TCGv R = tcg_temp_new_i32();
642 tcg_gen_xori_tl(Rd, Rd, 0xff);
644 /* update status register */
645 tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */
646 tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
647 gen_ZNSf(Rd);
649 tcg_temp_free_i32(R);
651 return true;
655 * Replaces the contents of register Rd with its two's complement; the
656 * value $80 is left unchanged.
658 static bool trans_NEG(DisasContext *ctx, arg_NEG *a)
660 TCGv Rd = cpu_r[a->rd];
661 TCGv t0 = tcg_const_i32(0);
662 TCGv R = tcg_temp_new_i32();
664 tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */
665 tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
667 /* update status register */
668 gen_sub_CHf(R, t0, Rd);
669 gen_sub_Vf(R, t0, Rd);
670 gen_ZNSf(R);
672 /* update output registers */
673 tcg_gen_mov_tl(Rd, R);
675 tcg_temp_free_i32(t0);
676 tcg_temp_free_i32(R);
678 return true;
682 * Adds one -1- to the contents of register Rd and places the result in the
683 * destination register Rd. The C Flag in SREG is not affected by the
684 * operation, thus allowing the INC instruction to be used on a loop counter in
685 * multiple-precision computations. When operating on unsigned numbers, only
686 * BREQ and BRNE branches can be expected to perform consistently. When
687 * operating on two's complement values, all signed branches are available.
689 static bool trans_INC(DisasContext *ctx, arg_INC *a)
691 TCGv Rd = cpu_r[a->rd];
693 tcg_gen_addi_tl(Rd, Rd, 1);
694 tcg_gen_andi_tl(Rd, Rd, 0xff);
696 /* update status register */
697 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */
698 gen_ZNSf(Rd);
700 return true;
704 * Subtracts one -1- from the contents of register Rd and places the result
705 * in the destination register Rd. The C Flag in SREG is not affected by the
706 * operation, thus allowing the DEC instruction to be used on a loop counter in
707 * multiple-precision computations. When operating on unsigned values, only
708 * BREQ and BRNE branches can be expected to perform consistently. When
709 * operating on two's complement values, all signed branches are available.
711 static bool trans_DEC(DisasContext *ctx, arg_DEC *a)
713 TCGv Rd = cpu_r[a->rd];
715 tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
716 tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
718 /* update status register */
719 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */
720 gen_ZNSf(Rd);
722 return true;
726 * This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication.
728 static bool trans_MUL(DisasContext *ctx, arg_MUL *a)
730 if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
731 return true;
734 TCGv R0 = cpu_r[0];
735 TCGv R1 = cpu_r[1];
736 TCGv Rd = cpu_r[a->rd];
737 TCGv Rr = cpu_r[a->rr];
738 TCGv R = tcg_temp_new_i32();
740 tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
741 tcg_gen_andi_tl(R0, R, 0xff);
742 tcg_gen_shri_tl(R1, R, 8);
744 /* update status register */
745 tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
746 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
748 tcg_temp_free_i32(R);
750 return true;
754 * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication.
756 static bool trans_MULS(DisasContext *ctx, arg_MULS *a)
758 if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
759 return true;
762 TCGv R0 = cpu_r[0];
763 TCGv R1 = cpu_r[1];
764 TCGv Rd = cpu_r[a->rd];
765 TCGv Rr = cpu_r[a->rr];
766 TCGv R = tcg_temp_new_i32();
767 TCGv t0 = tcg_temp_new_i32();
768 TCGv t1 = tcg_temp_new_i32();
770 tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
771 tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
772 tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
773 tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
774 tcg_gen_andi_tl(R0, R, 0xff);
775 tcg_gen_shri_tl(R1, R, 8);
777 /* update status register */
778 tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
779 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
781 tcg_temp_free_i32(t1);
782 tcg_temp_free_i32(t0);
783 tcg_temp_free_i32(R);
785 return true;
789 * This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a
790 * signed and an unsigned number.
792 static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a)
794 if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
795 return true;
798 TCGv R0 = cpu_r[0];
799 TCGv R1 = cpu_r[1];
800 TCGv Rd = cpu_r[a->rd];
801 TCGv Rr = cpu_r[a->rr];
802 TCGv R = tcg_temp_new_i32();
803 TCGv t0 = tcg_temp_new_i32();
805 tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
806 tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
807 tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */
808 tcg_gen_andi_tl(R0, R, 0xff);
809 tcg_gen_shri_tl(R1, R, 8);
811 /* update status register */
812 tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
813 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
815 tcg_temp_free_i32(t0);
816 tcg_temp_free_i32(R);
818 return true;
822 * This instruction performs 8-bit x 8-bit -> 16-bit unsigned
823 * multiplication and shifts the result one bit left.
825 static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a)
827 if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
828 return true;
831 TCGv R0 = cpu_r[0];
832 TCGv R1 = cpu_r[1];
833 TCGv Rd = cpu_r[a->rd];
834 TCGv Rr = cpu_r[a->rr];
835 TCGv R = tcg_temp_new_i32();
837 tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
839 /* update status register */
840 tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
841 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
843 /* update output registers */
844 tcg_gen_shli_tl(R, R, 1);
845 tcg_gen_andi_tl(R0, R, 0xff);
846 tcg_gen_shri_tl(R1, R, 8);
847 tcg_gen_andi_tl(R1, R1, 0xff);
850 tcg_temp_free_i32(R);
852 return true;
856 * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
857 * and shifts the result one bit left.
859 static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a)
861 if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
862 return true;
865 TCGv R0 = cpu_r[0];
866 TCGv R1 = cpu_r[1];
867 TCGv Rd = cpu_r[a->rd];
868 TCGv Rr = cpu_r[a->rr];
869 TCGv R = tcg_temp_new_i32();
870 TCGv t0 = tcg_temp_new_i32();
871 TCGv t1 = tcg_temp_new_i32();
873 tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
874 tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
875 tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
876 tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
878 /* update status register */
879 tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
880 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
882 /* update output registers */
883 tcg_gen_shli_tl(R, R, 1);
884 tcg_gen_andi_tl(R0, R, 0xff);
885 tcg_gen_shri_tl(R1, R, 8);
886 tcg_gen_andi_tl(R1, R1, 0xff);
888 tcg_temp_free_i32(t1);
889 tcg_temp_free_i32(t0);
890 tcg_temp_free_i32(R);
892 return true;
896 * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
897 * and shifts the result one bit left.
899 static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a)
901 if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
902 return true;
905 TCGv R0 = cpu_r[0];
906 TCGv R1 = cpu_r[1];
907 TCGv Rd = cpu_r[a->rd];
908 TCGv Rr = cpu_r[a->rr];
909 TCGv R = tcg_temp_new_i32();
910 TCGv t0 = tcg_temp_new_i32();
912 tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
913 tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
914 tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
916 /* update status register */
917 tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
918 tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
920 /* update output registers */
921 tcg_gen_shli_tl(R, R, 1);
922 tcg_gen_andi_tl(R0, R, 0xff);
923 tcg_gen_shri_tl(R1, R, 8);
924 tcg_gen_andi_tl(R1, R1, 0xff);
926 tcg_temp_free_i32(t0);
927 tcg_temp_free_i32(R);
929 return true;
933 * The module is an instruction set extension to the AVR CPU, performing
934 * DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in
935 * the CPU register file, registers R0-R7, where LSB of data is placed in LSB
936 * of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including
937 * parity bits) is placed in registers R8- R15, organized in the register file
938 * with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES
939 * instruction performs one round in the DES algorithm. Sixteen rounds must be
940 * executed in increasing order to form the correct DES ciphertext or
941 * plaintext. Intermediate results are stored in the register file (R0-R15)
942 * after each DES instruction. The instruction's operand (K) determines which
943 * round is executed, and the half carry flag (H) determines whether encryption
944 * or decryption is performed. The DES algorithm is described in
945 * "Specifications for the Data Encryption Standard" (Federal Information
946 * Processing Standards Publication 46). Intermediate results in this
947 * implementation differ from the standard because the initial permutation and
948 * the inverse initial permutation are performed each iteration. This does not
949 * affect the result in the final ciphertext or plaintext, but reduces
950 * execution time.
952 static bool trans_DES(DisasContext *ctx, arg_DES *a)
954 /* TODO */
955 if (!avr_have_feature(ctx, AVR_FEATURE_DES)) {
956 return true;
959 qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
961 return true;