From: Aleksandar Markovic <aleksandar.markovic@rt-rk.com>
To: qemu-devel@nongnu.org
Cc: Richard Henderson <richard.henderson@linaro.org>,
Michael Rolnik <mrolnik@gmail.com>,
Aleksandar Markovic <aleksandar.m.mail@gmail.com>
Subject: [PATCH rc4 09/29] target/avr: Add instruction translation - Arithmetic and Logic Instructions
Date: Fri, 31 Jan 2020 01:02:53 +0100 [thread overview]
Message-ID: <1580428993-4767-10-git-send-email-aleksandar.markovic@rt-rk.com> (raw)
In-Reply-To: <1580428993-4767-1-git-send-email-aleksandar.markovic@rt-rk.com>
From: Michael Rolnik <mrolnik@gmail.com>
This includes:
- ADD, ADC, ADIW
- SBIW, SUB, SUBI, SBC, SBCI
- AND, ANDI
- OR, ORI, EOR
- COM, NEG
- INC, DEC
- MUL, MULS, MULSU
- FMUL, FMULS, FMULSU
- DES
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Aleksandar Markovic <aleksandar.m.mail@gmail.com>
---
target/avr/insn.decode | 93 ++++++
target/avr/translate.c | 752 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 845 insertions(+)
create mode 100644 target/avr/insn.decode
diff --git a/target/avr/insn.decode b/target/avr/insn.decode
new file mode 100644
index 0000000..9c71ed6
--- /dev/null
+++ b/target/avr/insn.decode
@@ -0,0 +1,93 @@
+#
+# AVR instruction decode definitions.
+#
+# Copyright (c) 2019 Michael Rolnik <mrolnik@gmail.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# regs_16_31_by_one = [16 .. 31]
+# regs_16_23_by_one = [16 .. 23]
+# regs_24_30_by_two = [24, 26, 28, 30]
+# regs_00_30_by_two = [0, 2, 4, 6, 8, .. 30]
+
+%rd 4:5
+%rr 9:1 0:4
+
+%rd_a 4:4 !function=to_regs_16_31_by_one
+%rd_b 4:3 !function=to_regs_16_23_by_one
+%rd_c 4:2 !function=to_regs_24_30_by_two
+%rd_d 4:4 !function=to_regs_00_30_by_two
+%rr_a 0:4 !function=to_regs_16_31_by_one
+%rr_b 0:3 !function=to_regs_16_23_by_one
+%rr_d 0:4 !function=to_regs_00_30_by_two
+
+%imm6 6:2 0:4
+%imm8 8:4 0:4
+
+%io_imm 9:2 0:4
+%ldst_d_imm 13:1 10:2 0:3
+
+# The 22-bit immediate is partially in the opcode word,
+# and partially in the next. Use append_16 to build the
+# complete 22-bit value.
+%imm_call 4:5 0:1 !function=append_16
+
+
+&rd_rr rd rr
+&rd_imm rd imm
+
+@op_rd_rr .... .. . ..... .... &rd_rr rd=%rd rr=%rr
+@op_rd_imm6 .... .... .. .. .... &rd_imm rd=%rd_c imm=%imm6
+@op_rd_imm8 .... .... .... .... &rd_imm rd=%rd_a imm=%imm8
+@op_bit .... .... . bit:3 ....
+@op_bit_imm .... .. imm:s7 bit:3
+@fmul .... .... . ... . ... &rd_rr rd=%rd_b rr=%rr_b
+@io_rd_imm .... . .. ..... .... &rd_imm rd=%rd imm=%io_imm
+@ldst_d .. . . .. . rd:5 . ... &rd_imm imm=%ldst_d_imm
+
+# The 16-bit immediate is completely in the next word.
+# Fields cannot be defined with no bits, so we cannot play
+# the same trick and append to a zero-bit value.
+# Defer reading the immediate until trans_{LDS,STS}.
+@ldst_s .... ... rd:5 .... imm=0
+
+#
+# Arithmetic Instructions
+#
+ADD 0000 11 . ..... .... @op_rd_rr
+ADC 0001 11 . ..... .... @op_rd_rr
+ADIW 1001 0110 .. .. .... @op_rd_imm6
+SUB 0001 10 . ..... .... @op_rd_rr
+SUBI 0101 .... .... .... @op_rd_imm8
+SBC 0000 10 . ..... .... @op_rd_rr
+SBCI 0100 .... .... .... @op_rd_imm8
+SBIW 1001 0111 .. .. .... @op_rd_imm6
+AND 0010 00 . ..... .... @op_rd_rr
+ANDI 0111 .... .... .... @op_rd_imm8
+OR 0010 10 . ..... .... @op_rd_rr
+ORI 0110 .... .... .... @op_rd_imm8
+EOR 0010 01 . ..... .... @op_rd_rr
+COM 1001 010 rd:5 0000
+NEG 1001 010 rd:5 0001
+INC 1001 010 rd:5 0011
+DEC 1001 010 rd:5 1010
+MUL 1001 11 . ..... .... @op_rd_rr
+MULS 0000 0010 .... .... &rd_rr rd=%rd_a rr=%rr_a
+MULSU 0000 0011 0 ... 0 ... @fmul
+FMUL 0000 0011 0 ... 1 ... @fmul
+FMULS 0000 0011 1 ... 0 ... @fmul
+FMULSU 0000 0011 1 ... 1 ... @fmul
+DES 1001 0100 imm:4 1011
diff --git a/target/avr/translate.c b/target/avr/translate.c
index 535f666..00fb3f5 100644
--- a/target/avr/translate.c
+++ b/target/avr/translate.c
@@ -169,3 +169,755 @@ static bool avr_have_feature(DisasContext *ctx, int feature)
static bool decode_insn(DisasContext *ctx, uint16_t insn);
#include "decode_insn.inc.c"
+
+/*
+ * Arithmetic Instructions
+ */
+
+static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr)
+{
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv t2 = tcg_temp_new_i32();
+ TCGv t3 = tcg_temp_new_i32();
+
+ tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */
+ tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */
+ tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */
+ tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */
+ tcg_gen_or_tl(t1, t1, t3);
+ tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */
+ tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */
+ tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
+
+ tcg_temp_free_i32(t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+}
+
+
+static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
+{
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv t2 = tcg_temp_new_i32();
+
+ /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */
+ /* = (Rd ^ R) & ~(Rd ^ Rr) */
+ tcg_gen_xor_tl(t1, Rd, R);
+ tcg_gen_xor_tl(t2, Rd, Rr);
+ tcg_gen_andc_tl(t1, t1, t2);
+ tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
+
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+}
+
+
+static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
+{
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv t2 = tcg_temp_new_i32();
+ TCGv t3 = tcg_temp_new_i32();
+
+ tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd */
+ tcg_gen_and_tl(t2, t1, Rr); /* t2 = ~Rd & Rr */
+ tcg_gen_or_tl(t3, t1, Rr); /* t3 = (~Rd | Rr) & R */
+ tcg_gen_and_tl(t3, t3, R);
+ tcg_gen_or_tl(t2, t2, t3); /* t2 = ~Rd & Rr | ~Rd & R | R & Rr */
+ tcg_gen_shri_tl(cpu_Cf, t2, 7); /* Cf = t2(7) */
+ tcg_gen_shri_tl(cpu_Hf, t2, 3); /* Hf = t2(3) */
+ tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
+
+ tcg_temp_free_i32(t3);
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+}
+
+
+static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
+{
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv t2 = tcg_temp_new_i32();
+
+ /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */
+ /* = (Rd ^ R) & (Rd ^ R) */
+ tcg_gen_xor_tl(t1, Rd, R);
+ tcg_gen_xor_tl(t2, Rd, Rr);
+ tcg_gen_and_tl(t1, t1, t2);
+ tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
+
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+}
+
+
+static void gen_NSf(TCGv R)
+{
+ tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
+ tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
+}
+
+
+static void gen_ZNSf(TCGv R)
+{
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
+ tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
+ tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
+}
+
+/*
+ * Adds two registers without the C Flag and places the result in the
+ * destination register Rd.
+ */
+static bool trans_ADD(DisasContext *ctx, arg_ADD *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+ /* update status register */
+ gen_add_CHf(R, Rd, Rr);
+ gen_add_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+ /* update output registers */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * Adds two registers and the contents of the C Flag and places the result in
+ * the destination register Rd.
+ */
+static bool trans_ADC(DisasContext *ctx, arg_ADC *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_add_tl(R, Rd, Rr); /* R = Rd + Rr + Cf */
+ tcg_gen_add_tl(R, R, cpu_Cf);
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+ /* update status register */
+ gen_add_CHf(R, Rd, Rr);
+ gen_add_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+ /* update output registers */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * Adds an immediate value (0 - 63) to a register pair and places the result
+ * in the register pair. This instruction operates on the upper four register
+ * pairs, and is well suited for operations on the pointer registers. This
+ * instruction is not available in all devices. Refer to the device specific
+ * instruction set summary.
+ */
+static bool trans_ADIW(DisasContext *ctx, arg_ADIW *a)
+{
+ if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
+ return true;
+ }
+
+ TCGv RdL = cpu_r[a->rd];
+ TCGv RdH = cpu_r[a->rd + 1];
+ int Imm = (a->imm);
+ TCGv R = tcg_temp_new_i32();
+ TCGv Rd = tcg_temp_new_i32();
+
+ tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
+ tcg_gen_addi_tl(R, Rd, Imm); /* R = Rd + Imm */
+ tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
+ /* update status register */
+ tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
+ tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15);
+ tcg_gen_andc_tl(cpu_Vf, R, Rd); /* Vf = R & ~Rd */
+ tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15);
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
+ tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
+ tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf ^ Vf */
+ /* update output registers */
+ tcg_gen_andi_tl(RdL, R, 0xff);
+ tcg_gen_shri_tl(RdH, R, 8);
+
+ tcg_temp_free_i32(Rd);
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * Subtracts two registers and places the result in the destination
+ * register Rd.
+ */
+static bool trans_SUB(DisasContext *ctx, arg_SUB *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+ /* update status register */
+ tcg_gen_andc_tl(cpu_Cf, Rd, R); /* Cf = Rd & ~R */
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+ /* update output registers */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * Subtracts a register and a constant and places the result in the
+ * destination register Rd. This instruction is working on Register R16 to R31
+ * and is very well suited for operations on the X, Y, and Z-pointers.
+ */
+static bool trans_SUBI(DisasContext *ctx, arg_SUBI *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = tcg_const_i32(a->imm);
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Imm */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+ /* update status register */
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+ /* update output registers */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+ tcg_temp_free_i32(Rr);
+
+ return true;
+}
+
+/*
+ * Subtracts two registers and subtracts with the C Flag and places the
+ * result in the destination register Rd.
+ */
+static bool trans_SBC(DisasContext *ctx, arg_SBC *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+ TCGv zero = tcg_const_i32(0);
+
+ tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
+ tcg_gen_sub_tl(R, R, cpu_Cf);
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+ /* update status register */
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_NSf(R);
+
+ /*
+ * Previous value remains unchanged when the result is zero;
+ * cleared otherwise.
+ */
+ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
+ /* update output registers */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(zero);
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * SBCI -- Subtract Immediate with Carry
+ */
+static bool trans_SBCI(DisasContext *ctx, arg_SBCI *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = tcg_const_i32(a->imm);
+ TCGv R = tcg_temp_new_i32();
+ TCGv zero = tcg_const_i32(0);
+
+ tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr - Cf */
+ tcg_gen_sub_tl(R, R, cpu_Cf);
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+ /* update status register */
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_NSf(R);
+
+ /*
+ * Previous value remains unchanged when the result is zero;
+ * cleared otherwise.
+ */
+ tcg_gen_movcond_tl(TCG_COND_EQ, cpu_Zf, R, zero, cpu_Zf, zero);
+ /* update output registers */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(zero);
+ tcg_temp_free_i32(R);
+ tcg_temp_free_i32(Rr);
+
+ return true;
+}
+
+/*
+ * Subtracts an immediate value (0-63) from a register pair and places the
+ * result in the register pair. This instruction operates on the upper four
+ * register pairs, and is well suited for operations on the Pointer Registers.
+ * This instruction is not available in all devices. Refer to the device
+ * specific instruction set summary.
+ */
+static bool trans_SBIW(DisasContext *ctx, arg_SBIW *a)
+{
+ if (!avr_have_feature(ctx, AVR_FEATURE_ADIW_SBIW)) {
+ return true;
+ }
+
+ TCGv RdL = cpu_r[a->rd];
+ TCGv RdH = cpu_r[a->rd + 1];
+ int Imm = (a->imm);
+ TCGv R = tcg_temp_new_i32();
+ TCGv Rd = tcg_temp_new_i32();
+
+ tcg_gen_deposit_tl(Rd, RdL, RdH, 8, 8); /* Rd = RdH:RdL */
+ tcg_gen_subi_tl(R, Rd, Imm); /* R = Rd - Imm */
+ tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
+ /* update status register */
+ tcg_gen_andc_tl(cpu_Cf, R, Rd);
+ tcg_gen_shri_tl(cpu_Cf, cpu_Cf, 15); /* Cf = R & ~Rd */
+ tcg_gen_andc_tl(cpu_Vf, Rd, R);
+ tcg_gen_shri_tl(cpu_Vf, cpu_Vf, 15); /* Vf = Rd & ~R */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
+ tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
+ tcg_gen_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */
+ /* update output registers */
+ tcg_gen_andi_tl(RdL, R, 0xff);
+ tcg_gen_shri_tl(RdH, R, 8);
+
+ tcg_temp_free_i32(Rd);
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * Performs the logical AND between the contents of register Rd and register
+ * Rr and places the result in the destination register Rd.
+ */
+static bool trans_AND(DisasContext *ctx, arg_AND *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */
+ /* update status register */
+ tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
+ gen_ZNSf(R);
+ /* update output registers */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * Performs the logical AND between the contents of register Rd and a constant
+ * and places the result in the destination register Rd.
+ */
+static bool trans_ANDI(DisasContext *ctx, arg_ANDI *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ int Imm = (a->imm);
+
+ tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */
+ /* update status register */
+ tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
+ gen_ZNSf(Rd);
+
+ return true;
+}
+
+/*
+ * Performs the logical OR between the contents of register Rd and register
+ * Rr and places the result in the destination register Rd.
+ */
+static bool trans_OR(DisasContext *ctx, arg_OR *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_or_tl(R, Rd, Rr);
+ /* update status register */
+ tcg_gen_movi_tl(cpu_Vf, 0);
+ gen_ZNSf(R);
+ /* update output registers */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * Performs the logical OR between the contents of register Rd and a
+ * constant and places the result in the destination register Rd.
+ */
+static bool trans_ORI(DisasContext *ctx, arg_ORI *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ int Imm = (a->imm);
+
+ tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */
+ /* update status register */
+ tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
+ gen_ZNSf(Rd);
+
+ return true;
+}
+
+/*
+ * Performs the logical EOR between the contents of register Rd and
+ * register Rr and places the result in the destination register Rd.
+ */
+static bool trans_EOR(DisasContext *ctx, arg_EOR *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+
+ tcg_gen_xor_tl(Rd, Rd, Rr);
+ /* update status register */
+ tcg_gen_movi_tl(cpu_Vf, 0);
+ gen_ZNSf(Rd);
+
+ return true;
+}
+
+/*
+ * Clears the specified bits in register Rd. Performs the logical AND
+ * between the contents of register Rd and the complement of the constant mask
+ * K. The result will be placed in register Rd.
+ */
+static bool trans_COM(DisasContext *ctx, arg_COM *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_xori_tl(Rd, Rd, 0xff);
+ /* update status register */
+ tcg_gen_movi_tl(cpu_Cf, 1); /* Cf = 1 */
+ tcg_gen_movi_tl(cpu_Vf, 0); /* Vf = 0 */
+ gen_ZNSf(Rd);
+
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * Replaces the contents of register Rd with its two's complement; the
+ * value $80 is left unchanged.
+ */
+static bool trans_NEG(DisasContext *ctx, arg_NEG *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+ TCGv t0 = tcg_const_i32(0);
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_sub_tl(R, t0, Rd); /* R = 0 - Rd */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+ /* update status register */
+ gen_sub_CHf(R, t0, Rd);
+ gen_sub_Vf(R, t0, Rd);
+ gen_ZNSf(R);
+ /* update output registers */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * Adds one -1- to the contents of register Rd and places the result in the
+ * destination register Rd. The C Flag in SREG is not affected by the
+ * operation, thus allowing the INC instruction to be used on a loop counter in
+ * multiple-precision computations. When operating on unsigned numbers, only
+ * BREQ and BRNE branches can be expected to perform consistently. When
+ * operating on two's complement values, all signed branches are available.
+ */
+static bool trans_INC(DisasContext *ctx, arg_INC *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+
+ tcg_gen_addi_tl(Rd, Rd, 1);
+ tcg_gen_andi_tl(Rd, Rd, 0xff);
+ /* update status register */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* Vf = Rd == 0x80 */
+ gen_ZNSf(Rd);
+
+ return true;
+}
+
+/*
+ * Subtracts one -1- from the contents of register Rd and places the result
+ * in the destination register Rd. The C Flag in SREG is not affected by the
+ * operation, thus allowing the DEC instruction to be used on a loop counter in
+ * multiple-precision computations. When operating on unsigned values, only
+ * BREQ and BRNE branches can be expected to perform consistently. When
+ * operating on two's complement values, all signed branches are available.
+ */
+static bool trans_DEC(DisasContext *ctx, arg_DEC *a)
+{
+ TCGv Rd = cpu_r[a->rd];
+
+ tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
+ tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
+ /* update status register */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* Vf = Rd == 0x7f */
+ gen_ZNSf(Rd);
+
+ return true;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication.
+ */
+static bool trans_MUL(DisasContext *ctx, arg_MUL *a)
+{
+ if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
+ return true;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R1, R, 8);
+ /* update status register */
+ tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
+
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication.
+ */
+static bool trans_MULS(DisasContext *ctx, arg_MULS *a)
+{
+ if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
+ return true;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv t1 = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
+ tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
+ tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
+ tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R1, R, 8);
+ /* update status register */
+ tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a
+ * signed and an unsigned number.
+ */
+static bool trans_MULSU(DisasContext *ctx, arg_MULSU *a)
+{
+ if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
+ return true;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
+ tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
+ tcg_gen_andi_tl(R, R, 0xffff); /* make R 16 bits */
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R1, R, 8);
+ /* update status register */
+ tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit unsigned
+ * multiplication and shifts the result one bit left.
+ */
+static bool trans_FMUL(DisasContext *ctx, arg_FMUL *a)
+{
+ if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
+ return true;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd * Rr */
+ /* update status register */
+ tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
+ /* update output registers */
+ tcg_gen_shli_tl(R, R, 1);
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R1, R, 8);
+ tcg_gen_andi_tl(R1, R1, 0xff);
+
+
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
+ * and shifts the result one bit left.
+ */
+static bool trans_FMULS(DisasContext *ctx, arg_FMULS *a)
+{
+ if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
+ return true;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv t1 = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
+ tcg_gen_ext8s_tl(t1, Rr); /* make Rr full 32 bit signed */
+ tcg_gen_mul_tl(R, t0, t1); /* R = Rd * Rr */
+ tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
+ /* update status register */
+ tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
+ /* update output registers */
+ tcg_gen_shli_tl(R, R, 1);
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R1, R, 8);
+ tcg_gen_andi_tl(R1, R1, 0xff);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication
+ * and shifts the result one bit left.
+ */
+static bool trans_FMULSU(DisasContext *ctx, arg_FMULSU *a)
+{
+ if (!avr_have_feature(ctx, AVR_FEATURE_MUL)) {
+ return true;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[a->rd];
+ TCGv Rr = cpu_r[a->rr];
+ TCGv R = tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl(t0, Rd); /* make Rd full 32 bit signed */
+ tcg_gen_mul_tl(R, t0, Rr); /* R = Rd * Rr */
+ tcg_gen_andi_tl(R, R, 0xffff); /* make it 16 bits */
+ /* update status register */
+ tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(15) */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Zf, R, 0); /* Zf = R == 0 */
+ /* update output registers */
+ tcg_gen_shli_tl(R, R, 1);
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R1, R, 8);
+ tcg_gen_andi_tl(R1, R1, 0xff);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(R);
+
+ return true;
+}
+
+/*
+ * The module is an instruction set extension to the AVR CPU, performing
+ * DES iterations. The 64-bit data block (plaintext or ciphertext) is placed in
+ * the CPU register file, registers R0-R7, where LSB of data is placed in LSB
+ * of R0 and MSB of data is placed in MSB of R7. The full 64-bit key (including
+ * parity bits) is placed in registers R8- R15, organized in the register file
+ * with LSB of key in LSB of R8 and MSB of key in MSB of R15. Executing one DES
+ * instruction performs one round in the DES algorithm. Sixteen rounds must be
+ * executed in increasing order to form the correct DES ciphertext or
+ * plaintext. Intermediate results are stored in the register file (R0-R15)
+ * after each DES instruction. The instruction's operand (K) determines which
+ * round is executed, and the half carry flag (H) determines whether encryption
+ * or decryption is performed. The DES algorithm is described in
+ * "Specifications for the Data Encryption Standard" (Federal Information
+ * Processing Standards Publication 46). Intermediate results in this
+ * implementation differ from the standard because the initial permutation and
+ * the inverse initial permutation are performed each iteration. This does not
+ * affect the result in the final ciphertext or plaintext, but reduces
+ * execution time.
+ */
+static bool trans_DES(DisasContext *ctx, arg_DES *a)
+{
+ /* TODO */
+ if (!avr_have_feature(ctx, AVR_FEATURE_DES)) {
+ return true;
+ }
+
+ return true;
+}
--
2.7.4
next prev parent reply other threads:[~2020-01-31 0:10 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-01-31 0:02 [PATCH rc4 00/29] target/avr merger Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 01/29] target/avr: Add basic parameters for new AVR platform Aleksandar Markovic
2020-01-31 18:47 ` Aleksandar Markovic
2020-01-31 19:23 ` Aleksandar Markovic
2020-01-31 20:07 ` Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 02/29] target/avr: Introduce AVR CPU class object Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 03/29] target/avr: Add migration support Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 04/29] target/avr: Add GDB support Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 05/29] target/avr: Introduce enumeration AVRFeature Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 06/29] target/avr: Add defintions of AVR core types Aleksandar Markovic
2020-02-02 15:40 ` Joaquin de Andres
2020-02-08 7:35 ` Aleksandar Markovic
2020-02-10 7:39 ` Michael Rolnik
2020-02-21 11:03 ` Michael Rolnik
2020-02-21 15:31 ` Aleksandar Markovic
2020-02-27 8:38 ` Michael Rolnik
2020-03-06 13:34 ` Michael Rolnik
2020-06-16 8:56 ` Philippe Mathieu-Daudé
2020-06-29 9:51 ` Philippe Mathieu-Daudé
2020-01-31 0:02 ` [PATCH rc4 07/29] target/avr: Add instruction helpers Aleksandar Markovic
2020-02-01 12:27 ` Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 08/29] target/avr: Add instruction translation - Register definitions Aleksandar Markovic
2020-01-31 0:02 ` Aleksandar Markovic [this message]
2020-01-31 0:02 ` [PATCH rc4 10/29] target/avr: Add instruction translation - Branch Instructions Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 11/29] target/avr: Add instruction translation - Data Transfer Instructions Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 12/29] target/avr: Add instruction translation - Bit and Bit-test Instructions Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 13/29] target/avr: Add instruction translation - MCU Control Instructions Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 14/29] target/avr: Add instruction translation - CPU main translation function Aleksandar Markovic
2020-01-31 0:02 ` [PATCH rc4 15/29] target/avr: Add instruction disassembly function Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 16/29] hw/char: Add limited support for AVR USART peripheral Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 17/29] hw/timer: Add limited support for AVR 16-bit timer peripheral Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 18/29] hw/misc: Add limited support for AVR power device Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 19/29] target/avr: Add section about AVR into QEMU documentation Aleksandar Markovic
2020-02-01 13:19 ` Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 20/29] target/avr: Register AVR support with the rest of QEMU Aleksandar Markovic
2020-01-31 0:23 ` Philippe Mathieu-Daudé
2020-01-31 0:27 ` Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 21/29] target/avr: Add machine none test Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 22/29] target/avr: Update MAINTAINERS file Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 23/29] hw/avr: Add helper to load raw/ELF firmware binaries Aleksandar Markovic
2020-01-31 0:20 ` Philippe Mathieu-Daudé
2020-01-31 0:26 ` Aleksandar Markovic
2020-01-31 0:28 ` Philippe Mathieu-Daudé
2020-01-31 0:30 ` Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 24/29] hw/avr: Add some ATmega microcontrollers Aleksandar Markovic
2020-01-31 1:56 ` Aleksandar Markovic
2020-01-31 3:09 ` Philippe Mathieu-Daudé
2020-01-31 3:45 ` Aleksandar Markovic
2020-01-31 4:11 ` Aleksandar Markovic
2020-01-31 9:35 ` Thomas Huth
2020-01-31 9:40 ` Aleksandar Markovic
2020-01-31 10:45 ` Philippe Mathieu-Daudé
2020-01-31 11:07 ` Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 25/29] hw/avr: Add some Arduino boards Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 26/29] target/avr: Update build system Aleksandar Markovic
2020-02-04 22:58 ` Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 27/29] tests/boot-serial-test: Test some Arduino boards (AVR based) Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 28/29] tests/acceptance: Test the Arduino MEGA2560 board Aleksandar Markovic
2020-01-31 0:03 ` [PATCH rc4 29/29] .travis.yml: Run the AVR acceptance tests Aleksandar Markovic
2020-01-31 0:12 ` [PATCH rc4 00/29] target/avr merger Aleksandar Markovic
2020-01-31 1:23 ` Philippe Mathieu-Daudé
2020-01-31 14:43 ` Michael Rolnik
2020-01-31 1:09 ` [PATCH 0/2] !fixup target/avr merger-rc4 Philippe Mathieu-Daudé
2020-01-31 1:09 ` [PATCH 1/2] !fixup "hw/misc: Add limited support for AVR power device" Philippe Mathieu-Daudé
2020-01-31 11:27 ` Alex Bennée
2020-01-31 12:39 ` Philippe Mathieu-Daudé
2020-01-31 14:52 ` Alex Bennée
2020-01-31 1:09 ` [PATCH 2/2] !fixup "hw/timer: Add limited support for AVR 16-bit timer peripheral" Philippe Mathieu-Daudé
2020-01-31 11:31 ` Alex Bennée
2020-01-31 1:12 ` [PATCH 0/2] !fixup target/avr merger-rc4 Aleksandar Markovic
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1580428993-4767-10-git-send-email-aleksandar.markovic@rt-rk.com \
--to=aleksandar.markovic@rt-rk.com \
--cc=aleksandar.m.mail@gmail.com \
--cc=mrolnik@gmail.com \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).