* [Qemu-devel] [PATCH 02/10] target-avr: adding AVR CPU features/flavors
2016-06-02 20:03 [Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions Michael Rolnik
@ 2016-06-02 20:03 ` Michael Rolnik
2016-06-02 20:03 ` [Qemu-devel] [PATCH 03/10] target-avr: adding a sample AVR board Michael Rolnik
` (7 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Michael Rolnik @ 2016-06-02 20:03 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Rolnik, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/cpu.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
target-avr/cpu.h | 59 ++++++++++
2 files changed, 383 insertions(+), 2 deletions(-)
diff --git a/target-avr/cpu.c b/target-avr/cpu.c
index ff26018..9be0a1d 100644
--- a/target-avr/cpu.c
+++ b/target-avr/cpu.c
@@ -31,7 +31,7 @@ static void avr_cpu_set_pc(
{
AVRCPU *cpu = AVR_CPU(cs);
- cpu->env.pc = value / 2; /* internaly PC points to words, not bytes */
+ cpu->env.pc = value / 2; /* internally PC points to words */
}
static bool avr_cpu_has_work(
@@ -52,7 +52,7 @@ static void avr_cpu_synchronize_from_tb(
AVRCPU *cpu = AVR_CPU(cs);
CPUAVRState *env = &cpu->env;
- env->pc = tb->pc / 2;
+ env->pc = tb->pc / 2; /* internally PC points to words */
}
static void avr_cpu_reset(
@@ -61,12 +61,14 @@ static void avr_cpu_reset(
AVRCPU *cpu = AVR_CPU(s);
AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
CPUAVRState *env = &cpu->env;
+ uint32_t features = env->features;
mcc->parent_reset(s);
memset(env, 0, sizeof(CPUAVRState));
env->pc = 0;
env->sregI = 1;
+ env->features = features;
tlb_flush(s, 1);
}
@@ -206,6 +208,311 @@ static void avr_cpu_class_init(
= true;
}
+static void avr_avr1_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+}
+static void avr_avr2_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+}
+
+static void avr_avr25_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+}
+
+static void avr_avr3_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+}
+
+static void avr_avr31_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+}
+
+static void avr_avr35_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+}
+
+static void avr_avr4_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+}
+
+static void avr_avr5_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+}
+
+static void avr_avr51_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+}
+static void avr_avr6_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+}
+static void avr_xmega2_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+ avr_set_feature(env, AVR_FEATURE_RMW);
+}
+static void avr_xmega4_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+ avr_set_feature(env, AVR_FEATURE_RMW);
+}
+static void avr_xmega5_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPD);
+ avr_set_feature(env, AVR_FEATURE_RAMPX);
+ avr_set_feature(env, AVR_FEATURE_RAMPY);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+ avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
+static void avr_xmega6_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+ avr_set_feature(env, AVR_FEATURE_RMW);
+}
+static void avr_xmega7_initfn(
+ Object *obj)
+{
+ AVRCPU *cpu = AVR_CPU(obj);
+ CPUAVRState *env = &cpu->env;
+
+ avr_set_feature(env, AVR_FEATURE_LPM);
+ avr_set_feature(env, AVR_FEATURE_IJMP_ICALL);
+ avr_set_feature(env, AVR_FEATURE_ADIW_SBIW);
+ avr_set_feature(env, AVR_FEATURE_SRAM);
+ avr_set_feature(env, AVR_FEATURE_BREAK);
+
+ avr_set_feature(env, AVR_FEATURE_3_BYTE_PC);
+ avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
+ avr_set_feature(env, AVR_FEATURE_RAMPD);
+ avr_set_feature(env, AVR_FEATURE_RAMPX);
+ avr_set_feature(env, AVR_FEATURE_RAMPY);
+ avr_set_feature(env, AVR_FEATURE_RAMPZ);
+ avr_set_feature(env, AVR_FEATURE_EIJMP_EICALL);
+ avr_set_feature(env, AVR_FEATURE_ELPMX);
+ avr_set_feature(env, AVR_FEATURE_ELPM);
+ avr_set_feature(env, AVR_FEATURE_JMP_CALL);
+ avr_set_feature(env, AVR_FEATURE_LPMX);
+ avr_set_feature(env, AVR_FEATURE_MOVW);
+ avr_set_feature(env, AVR_FEATURE_MUL);
+ avr_set_feature(env, AVR_FEATURE_RMW);
+}
+
static void avr_any_initfn(
Object *obj)
{
@@ -218,6 +525,21 @@ typedef struct AVRCPUInfo {
} AVRCPUInfo;
static const AVRCPUInfo avr_cpus[] = {
+ { .name = "avr1", .initfn = avr_avr1_initfn},
+ { .name = "avr2", .initfn = avr_avr2_initfn},
+ { .name = "avr25", .initfn = avr_avr25_initfn},
+ { .name = "avr3", .initfn = avr_avr3_initfn},
+ { .name = "avr31", .initfn = avr_avr31_initfn},
+ { .name = "avr35", .initfn = avr_avr35_initfn},
+ { .name = "avr4", .initfn = avr_avr4_initfn},
+ { .name = "avr5", .initfn = avr_avr5_initfn},
+ { .name = "avr51", .initfn = avr_avr51_initfn},
+ { .name = "avr6", .initfn = avr_avr6_initfn},
+ { .name = "xmega2", .initfn = avr_xmega2_initfn},
+ { .name = "xmega4", .initfn = avr_xmega4_initfn},
+ { .name = "xmega5", .initfn = avr_xmega5_initfn},
+ { .name = "xmega6", .initfn = avr_xmega6_initfn},
+ { .name = "xmega7", .initfn = avr_xmega7_initfn},
{ .name = "any", .initfn = avr_any_initfn },
};
diff --git a/target-avr/cpu.h b/target-avr/cpu.h
index 3692329..2b67e89 100644
--- a/target-avr/cpu.h
+++ b/target-avr/cpu.h
@@ -47,6 +47,43 @@
#define PHYS_CODE_BASE 0x00000000
#define PHYS_DATA_BASE 0x00800000
+enum avr_features {
+ AVR_FEATURE_SRAM,
+
+ AVR_FEATURE_1_BYTE_PC,
+ AVR_FEATURE_2_BYTE_PC,
+ AVR_FEATURE_3_BYTE_PC,
+
+ AVR_FEATURE_1_BYTE_SP,
+ AVR_FEATURE_2_BYTE_SP,
+
+ AVR_FEATURE_BREAK,
+ AVR_FEATURE_DES,
+ AVR_FEATURE_RMW, /* Read Modify Write - XCH LAC LAS LAT */
+
+ AVR_FEATURE_EIJMP_EICALL,
+ AVR_FEATURE_IJMP_ICALL,
+ AVR_FEATURE_JMP_CALL,
+
+ AVR_FEATURE_ADIW_SBIW,
+
+ AVR_FEATURE_SPM,
+ AVR_FEATURE_SPMX,
+
+ AVR_FEATURE_ELPMX,
+ AVR_FEATURE_ELPM,
+ AVR_FEATURE_LPMX,
+ AVR_FEATURE_LPM,
+
+ AVR_FEATURE_MOVW,
+ AVR_FEATURE_MUL,
+ AVR_FEATURE_RAMPD,
+ AVR_FEATURE_RAMPX,
+ AVR_FEATURE_RAMPY,
+ AVR_FEATURE_RAMPZ,
+};
+
+
typedef struct CPUAVRState CPUAVRState;
struct CPUAVRState {
@@ -74,10 +111,32 @@ struct CPUAVRState {
uint64_t intsrc; /* interrupt sources */
+ uint32_t features;
+
/* Those resources are used only in QEMU core */
CPU_COMMON
};
+static inline int avr_feature(
+ CPUAVRState *env,
+ int feature)
+{
+ return (env->features & (1UL << feature)) != 0;
+}
+
+static inline void avr_set_feature(
+ CPUAVRState *env,
+ int feature)
+{
+ env->features |= (1Ul << feature);
+}
+static inline void avr_del_feature(
+ CPUAVRState *env,
+ int feature)
+{
+ env->features &= ~(1Ul << feature);
+}
+
#define cpu_list avr_cpu_list
#define cpu_exec cpu_avr_exec
#define cpu_signal_handler cpu_avr_signal_handler
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 03/10] target-avr: adding a sample AVR board
2016-06-02 20:03 [Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions Michael Rolnik
2016-06-02 20:03 ` [Qemu-devel] [PATCH 02/10] target-avr: adding AVR CPU features/flavors Michael Rolnik
@ 2016-06-02 20:03 ` Michael Rolnik
2016-06-02 20:04 ` [Qemu-devel] [PATCH 04/10] target-avr: adding instructions encodings Michael Rolnik
` (6 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Michael Rolnik @ 2016-06-02 20:03 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Rolnik, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
hw/Makefile.objs | 1 +
hw/avr/Makefile.objs | 1 +
hw/avr/sample-io.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++++++
hw/avr/sample.c | 120 +++++++++++++++++++++++++
4 files changed, 368 insertions(+)
create mode 100644 hw/avr/Makefile.objs
create mode 100644 hw/avr/sample-io.c
create mode 100644 hw/avr/sample.c
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 4a07ed4..262ca15 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -33,6 +33,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/
devices-dirs-$(CONFIG_SOFTMMU) += xen/
devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem/
devices-dirs-$(CONFIG_SMBIOS) += smbios/
+devices-dirs-$(CONFIG_SOFTMMU) += avr/
devices-dirs-y += core/
common-obj-y += $(devices-dirs-y)
obj-y += $(devices-dirs-y)
diff --git a/hw/avr/Makefile.objs b/hw/avr/Makefile.objs
new file mode 100644
index 0000000..9f6be2f
--- /dev/null
+++ b/hw/avr/Makefile.objs
@@ -0,0 +1 @@
+obj-y += sample.o sample-io.o
diff --git a/hw/avr/sample-io.c b/hw/avr/sample-io.c
new file mode 100644
index 0000000..133c72f
--- /dev/null
+++ b/hw/avr/sample-io.c
@@ -0,0 +1,246 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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/lgpl-2.1.html>
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "include/hw/sysbus.h"
+
+#define TYPE_SAMPLEIO "SampleIO"
+#define SAMPLEIO(obj) OBJECT_CHECK(SAMPLEIOState, (obj), TYPE_SAMPLEIO)
+
+#ifndef DEBUG_SAMPLEIO
+#define DEBUG_SAMPLEIO 1
+#endif
+
+#define DPRINTF(fmt, args...) \
+ do { \
+ if (DEBUG_SAMPLEIO) { \
+ fprintf(stderr, "[%s]%s: " fmt , TYPE_SAMPLEIO, __func__, ##args);\
+ } \
+ } \
+ while (0)
+
+#define AVR_IO_CPU_REGS_SIZE 0x0020
+#define AVR_IO_CPU_IO_SIZE 0x0040
+#define AVR_IO_EXTERN_IO_SIZE 0x00a0
+#define AVR_IO_SIZE (AVR_IO_CPU_REGS_SIZE \
+ + AVR_IO_CPU_IO_SIZE \
+ + AVR_IO_EXTERN_IO_SIZE)
+
+#define AVR_IO_CPU_REGS_BASE 0x0000
+#define AVR_IO_CPU_IO_BASE (AVR_IO_CPU_REGS_BASE \
+ + AVR_IO_CPU_REGS_SIZE)
+#define AVR_IO_EXTERN_IO_BASE (AVR_IO_CPU_IO_BASE \
+ + AVR_IO_CPU_IO_SIZE)
+
+
+typedef struct SAMPLEIOState {
+ SysBusDevice parent;
+
+ MemoryRegion iomem;
+
+ AVRCPU *cpu;
+
+ uint8_t io[0x40];
+ uint8_t exio[0xa0];
+} SAMPLEIOState;
+
+static uint64_t sample_io_read(
+ void *opaque,
+ hwaddr offset,
+ unsigned size);
+static void sample_io_write(void *opaque,
+ hwaddr offset,
+ uint64_t value,
+ unsigned size);
+static int sample_io_init(
+ DeviceState *sbd);
+static void sample_io_class_init(
+ ObjectClass *klass,
+ void *data);
+static void sample_io_register_types(void);
+
+static void write_Rx(
+ CPUAVRState *env,
+ int inst,
+ uint8_t data);
+static uint8_t read_Rx(
+ CPUAVRState *env,
+ int inst);
+
+static const
+MemoryRegionOps sample_io_ops = {
+ .read = sample_io_read,
+ .write = sample_io_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static
+Property sample_io_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+static const
+VMStateDescription sample_io_vmstate = {
+ .name = TYPE_SAMPLEIO,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[])
+ {
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+void write_Rx(
+ CPUAVRState *env,
+ int inst,
+ uint8_t data)
+{
+ env->r[inst] = data;
+}
+uint8_t read_Rx(
+ CPUAVRState *env,
+ int inst)
+{
+ return env->r[inst];
+}
+
+static
+void sample_io_reset(DeviceState *dev)
+{
+ DPRINTF("\n");
+}
+
+static
+uint64_t sample_io_read(
+ void *opaque,
+ hwaddr offset,
+ unsigned size)
+{
+ SAMPLEIOState *s = SAMPLEIO(opaque);
+ AVRCPU *cpu = s->cpu;
+ CPUAVRState *env = &cpu->env;
+ uint64_t res = 0;
+
+ assert(size == 1);
+
+ if (AVR_IO_CPU_REGS_BASE <= offset
+ && offset < (AVR_IO_CPU_REGS_BASE + AVR_IO_CPU_REGS_SIZE)) {
+ res = read_Rx(env, offset - AVR_IO_CPU_REGS_BASE);
+ } else if (AVR_IO_CPU_IO_BASE <= offset
+ && offset < (AVR_IO_CPU_IO_BASE + AVR_IO_CPU_IO_SIZE)) {
+ /* TODO: do IO related stuff here */
+ res = s->io[offset - AVR_IO_CPU_IO_BASE];
+ } else if (AVR_IO_EXTERN_IO_BASE <= offset
+ && offset < (AVR_IO_EXTERN_IO_BASE + AVR_IO_EXTERN_IO_SIZE)) {
+ /* TODO: do IO related stuff here */
+ res = s->io[offset - AVR_IO_EXTERN_IO_BASE];
+ } else {
+ g_assert_not_reached();
+ }
+
+ return res;
+}
+
+static
+void sample_io_write(
+ void *opaque,
+ hwaddr offset,
+ uint64_t value,
+ unsigned size)
+{
+ SAMPLEIOState *s = SAMPLEIO(opaque);
+ AVRCPU *cpu = s->cpu;
+ CPUAVRState *env = &cpu->env;
+
+ assert(size == 1);
+
+ if (AVR_IO_CPU_REGS_BASE <= offset
+ && offset < (AVR_IO_CPU_REGS_BASE + AVR_IO_CPU_REGS_SIZE)) {
+ return write_Rx(env, offset - AVR_IO_CPU_REGS_BASE, value);
+ } else if (AVR_IO_CPU_IO_BASE <= offset
+ && offset < (AVR_IO_CPU_IO_BASE + AVR_IO_CPU_IO_SIZE)) {
+ /* TODO: do IO related stuff here */
+ s->io[offset - AVR_IO_CPU_IO_BASE] = value;
+ } else if (AVR_IO_EXTERN_IO_BASE <= offset
+ && offset < (AVR_IO_EXTERN_IO_BASE + AVR_IO_EXTERN_IO_SIZE)) {
+ /* TODO: do IO related stuff here */
+ s->io[offset - AVR_IO_EXTERN_IO_BASE] = value;
+ } else {
+ g_assert_not_reached();
+ }
+}
+
+static
+int sample_io_init(
+ DeviceState *dev)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ SAMPLEIOState *s = SAMPLEIO(dev);
+
+ assert(AVR_IO_SIZE <= TARGET_PAGE_SIZE);
+
+ s->cpu = AVR_CPU(qemu_get_cpu(0));
+
+ memory_region_init_io(
+ &s->iomem,
+ OBJECT(s),
+ &sample_io_ops,
+ s,
+ TYPE_SAMPLEIO,
+ AVR_IO_SIZE);
+ sysbus_init_mmio(sbd, &s->iomem);
+
+ return 0;
+}
+
+static
+void sample_io_class_init(
+ ObjectClass *klass,
+ void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ DPRINTF("\n");
+
+ dc->init = sample_io_init;
+ dc->reset = sample_io_reset;
+ dc->desc = "at90 io regs";
+ dc->vmsd = &sample_io_vmstate;
+ dc->props = sample_io_properties;
+}
+
+static const
+TypeInfo sample_io_info = {
+ .name = TYPE_SAMPLEIO,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SAMPLEIOState),
+ .class_init = sample_io_class_init,
+};
+
+static
+void sample_io_register_types(void)
+{
+ DPRINTF("\n");
+ type_register_static(&sample_io_info);
+}
+
+type_init(sample_io_register_types)
diff --git a/hw/avr/sample.c b/hw/avr/sample.c
new file mode 100644
index 0000000..d8b9d5c
--- /dev/null
+++ b/hw/avr/sample.c
@@ -0,0 +1,120 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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/lgpl-2.1.html>
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "hw/hw.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
+#include "ui/console.h"
+#include "hw/boards.h"
+#include "hw/devices.h"
+#include "hw/loader.h"
+#include "qemu/error-report.h"
+#include "exec/address-spaces.h"
+#include "include/hw/sysbus.h"
+
+#define VIRT_BASE_FLASH 0x00000000
+#define VIRT_BASE_IOREG 0x00000000
+#define VIRT_BASE_ISRAM 0x00000100
+#define VIRT_BASE_EXMEM 0x00001100
+#define VIRT_BASE_EEPROM 0x00000000
+
+#define VIRT_BASE_BOOT 0x0001e000
+#define PHYS_BASE_BOOT (PHYS_BASE_FLASH + VIRT_BASE_BOOT)
+
+#define SIZE_FLASH 0x00020000
+#define SIZE_IOREG 0x00000100
+#define SIZE_ISRAM 0x00001000
+#define SIZE_EXMEM 0x00010000
+#define SIZE_EEPROM 0x00001000
+
+#define PHYS_BASE_FLASH (PHYS_CODE_BASE)
+#define PHYS_BASE_IOREG (PHYS_DATA_BASE)
+#define PHYS_BASE_ISRAM (PHYS_BASE_IOREG + SIZE_IOREG)
+#define PHYS_BASE_EXMEM (PHYS_BASE_ISRAM + SIZE_ISRAM)
+#define PHYS_BASE_EEPROM (PHYS_BASE_EXMEM + SIZE_EXMEM)
+
+
+static
+void sample_init(MachineState *machine)
+{
+ MemoryRegion *address_space_mem = get_system_memory();
+
+ MemoryRegion *flash;
+ MemoryRegion *isram;
+ MemoryRegion *exmem;
+
+ AVRCPU *cpu_avr;
+ DeviceState *io;
+ SysBusDevice *bus;
+
+ flash = g_new(MemoryRegion, 1);
+ isram = g_new(MemoryRegion, 1);
+ exmem = g_new(MemoryRegion, 1);
+
+ cpu_avr = cpu_avr_init("avr5");
+ io = qdev_create(NULL, "SampleIO");
+ bus = SYS_BUS_DEVICE(io);
+ qdev_init_nofail(io);
+
+ memory_region_init_ram(flash, NULL, "flash", SIZE_FLASH, &error_fatal);
+ memory_region_init_ram(isram, NULL, "isram", SIZE_ISRAM, &error_fatal);
+ memory_region_init_ram(exmem, NULL, "exmem", SIZE_EXMEM, &error_fatal);
+
+ memory_region_add_subregion(address_space_mem, PHYS_BASE_FLASH, flash);
+ memory_region_add_subregion(address_space_mem, PHYS_BASE_ISRAM, isram);
+ memory_region_add_subregion(address_space_mem, PHYS_BASE_EXMEM, exmem);
+
+ vmstate_register_ram_global(flash);
+ vmstate_register_ram_global(isram);
+ vmstate_register_ram_global(exmem);
+
+ memory_region_set_readonly(flash, true);
+
+ char const *firmware = NULL;
+ char const *filename;
+
+ if (machine->firmware) {
+ firmware = machine->firmware;
+ }
+
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware);
+ if (!filename) {
+ error_report("Could not find flash image file '%s'", firmware);
+ exit(1);
+ }
+
+ load_image_targphys(filename, PHYS_BASE_FLASH, SIZE_FLASH);
+
+ sysbus_mmio_map(bus, 0, PHYS_BASE_IOREG);
+}
+
+static
+void sample_machine_init(MachineClass *mc)
+{
+ mc->desc = "sample";
+ mc->init = sample_init;
+ mc->is_default = 1;
+}
+
+DEFINE_MACHINE("sample", sample_machine_init)
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 04/10] target-avr: adding instructions encodings
2016-06-02 20:03 [Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions Michael Rolnik
2016-06-02 20:03 ` [Qemu-devel] [PATCH 02/10] target-avr: adding AVR CPU features/flavors Michael Rolnik
2016-06-02 20:03 ` [Qemu-devel] [PATCH 03/10] target-avr: adding a sample AVR board Michael Rolnik
@ 2016-06-02 20:04 ` Michael Rolnik
2016-06-02 20:04 ` [Qemu-devel] [PATCH 05/10] target-avr: adding AVR interrupt handling Michael Rolnik
` (5 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Michael Rolnik @ 2016-06-02 20:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Rolnik, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.co>
---
target-avr/translate-inst.h | 838 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 838 insertions(+)
create mode 100644 target-avr/translate-inst.h
diff --git a/target-avr/translate-inst.h b/target-avr/translate-inst.h
new file mode 100644
index 0000000..6bd180d
--- /dev/null
+++ b/target-avr/translate-inst.h
@@ -0,0 +1,838 @@
+
+#ifndef AVR_TRANSLATE_INST_H_
+#define AVR_TRANSLATE_INST_H_
+
+typedef struct DisasContext DisasContext;
+
+int avr_translate_NOP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_MOVW(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t MOVW_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t MOVW_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+int avr_translate_MULS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t MULS_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t MULS_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+int avr_translate_MULSU(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t MULSU_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t MULSU_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_FMUL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t FMUL_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t FMUL_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_FMULS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t FMULS_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t FMULS_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_FMULSU(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t FMULSU_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t FMULSU_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_CPC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CPC_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t CPC_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t CPC_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_SBC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBC_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t SBC_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t SBC_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_ADD(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ADD_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t ADD_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t ADD_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_AND(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t AND_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t AND_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t AND_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_EOR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t EOR_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t EOR_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t EOR_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_OR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t OR_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t OR_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t OR_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_MOV(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t MOV_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t MOV_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t MOV_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_CPSE(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CPSE_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t CPSE_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t CPSE_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_CP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CP_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t CP_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t CP_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_SUB(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SUB_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t SUB_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t SUB_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_ADC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ADC_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t ADC_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t ADC_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_CPI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CPI_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t CPI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+static inline uint32_t CPI_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 8, 4);
+}
+
+int avr_translate_SBCI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBCI_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t SBCI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+static inline uint32_t SBCI_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 8, 4);
+}
+
+int avr_translate_ORI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ORI_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t ORI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+static inline uint32_t ORI_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 8, 4);
+}
+
+int avr_translate_SUBI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SUBI_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t SUBI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+static inline uint32_t SUBI_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 8, 4);
+}
+
+int avr_translate_ANDI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ANDI_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t ANDI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+static inline uint32_t ANDI_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 8, 4);
+}
+
+int avr_translate_LDDZ(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDDZ_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t LDDZ_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t LDDZ_mImm(uint32_t opcode)
+{
+ return extract32(opcode, 10, 2);
+}
+static inline uint32_t LDDZ_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 13, 1);
+}
+
+int avr_translate_LDDY(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDDY_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t LDDY_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t LDDY_mImm(uint32_t opcode)
+{
+ return extract32(opcode, 10, 2);
+}
+static inline uint32_t LDDY_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 13, 1);
+}
+
+int avr_translate_STDZ(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STDZ_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t STDZ_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t STDZ_mImm(uint32_t opcode)
+{
+ return extract32(opcode, 10, 2);
+}
+static inline uint32_t STDZ_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 13, 1);
+}
+
+int avr_translate_STDY(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STDY_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t STDY_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t STDY_mImm(uint32_t opcode)
+{
+ return extract32(opcode, 10, 2);
+}
+static inline uint32_t STDY_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 13, 1);
+}
+
+int avr_translate_LDS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDS_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 16);
+}
+static inline uint32_t LDS_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 20, 5);
+}
+
+int avr_translate_LDZ2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDZ2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDZ3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDZ3_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LPM2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LPM2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LPMX(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LPMX_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_ELPM2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ELPM2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_ELPMX(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ELPMX_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDY2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDY2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDY3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDY3_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDX1(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDX1_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDX2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDX2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LDX3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDX3_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_POP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t POP_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STS_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 16);
+}
+static inline uint32_t STS_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 20, 5);
+}
+
+int avr_translate_STZ2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STZ2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STZ3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STZ3_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_XCH(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t XCH_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LAS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LAS_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LAC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LAC_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LAT(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LAT_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STY2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STY2_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STY3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STY3_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STX1(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STX1_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STX2(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STX2_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_STX3(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t STX3_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_PUSH(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t PUSH_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_COM(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t COM_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_NEG(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t NEG_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_SWAP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SWAP_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_INC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t INC_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_ASR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ASR_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_LSR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LSR_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_ROR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ROR_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_BSET(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BSET_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_IJMP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_EIJMP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_BCLR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BCLR_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 4, 3);
+}
+
+int avr_translate_RET(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_RETI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_ICALL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_EICALL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_SLEEP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_BREAK(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_WDR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_LPM1(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_ELPM1(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_SPM(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_SPMX(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+
+int avr_translate_DEC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t DEC_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_DES(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t DES_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+
+int avr_translate_JMP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t JMP_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 17);
+}
+static inline uint32_t JMP_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 20, 5);
+}
+
+int avr_translate_CALL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CALL_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 17);
+}
+static inline uint32_t CALL_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 20, 5);
+}
+
+int avr_translate_ADIW(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t ADIW_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t ADIW_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 2);
+}
+static inline uint32_t ADIW_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 6, 2);
+}
+
+int avr_translate_SBIW(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBIW_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t SBIW_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 2);
+}
+static inline uint32_t SBIW_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 6, 2);
+}
+
+int avr_translate_CBI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t CBI_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t CBI_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 5);
+}
+
+int avr_translate_SBIC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBIC_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t SBIC_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 5);
+}
+
+int avr_translate_SBI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBI_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t SBI_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 5);
+}
+
+int avr_translate_SBIS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBIS_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t SBIS_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 5);
+}
+
+int avr_translate_MUL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t MUL_lRr(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t MUL_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t MUL_hRr(uint32_t opcode)
+{
+ return extract32(opcode, 9, 1);
+}
+
+int avr_translate_IN(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t IN_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t IN_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t IN_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 9, 2);
+}
+
+int avr_translate_OUT(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t OUT_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t OUT_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+static inline uint32_t OUT_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 9, 2);
+}
+
+int avr_translate_RJMP(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t RJMP_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 12);
+}
+
+int avr_translate_LDI(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t LDI_lImm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 4);
+}
+static inline uint32_t LDI_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 4);
+}
+static inline uint32_t LDI_hImm(uint32_t opcode)
+{
+ return extract32(opcode, 8, 4);
+}
+
+int avr_translate_RCALL(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t RCALL_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 0, 12);
+}
+
+int avr_translate_BRBS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BRBS_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t BRBS_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 7);
+}
+
+int avr_translate_BRBC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BRBC_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t BRBC_Imm(uint32_t opcode)
+{
+ return extract32(opcode, 3, 7);
+}
+
+int avr_translate_BLD(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BLD_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t BLD_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_BST(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t BST_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t BST_Rd(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_SBRC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBRC_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t SBRC_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+int avr_translate_SBRS(CPUAVRState *env, DisasContext* ctx, uint32_t opcode);
+static inline uint32_t SBRS_Bit(uint32_t opcode)
+{
+ return extract32(opcode, 0, 3);
+}
+static inline uint32_t SBRS_Rr(uint32_t opcode)
+{
+ return extract32(opcode, 4, 5);
+}
+
+
+#endif
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 05/10] target-avr: adding AVR interrupt handling
2016-06-02 20:03 [Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions Michael Rolnik
` (2 preceding siblings ...)
2016-06-02 20:04 ` [Qemu-devel] [PATCH 04/10] target-avr: adding instructions encodings Michael Rolnik
@ 2016-06-02 20:04 ` Michael Rolnik
2016-06-02 20:04 ` [Qemu-devel] [PATCH 06/10] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions Michael Rolnik
` (4 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Michael Rolnik @ 2016-06-02 20:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Rolnik, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/helper.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)
diff --git a/target-avr/helper.c b/target-avr/helper.c
index aec37af..ed22b37 100644
--- a/target-avr/helper.c
+++ b/target-avr/helper.c
@@ -33,12 +33,74 @@ bool avr_cpu_exec_interrupt(
CPUState *cs,
int interrupt_request)
{
- return false;
+ CPUClass *cc = CPU_GET_CLASS(cs);
+ AVRCPU *cpu = AVR_CPU(cs);
+ CPUAVRState *env = &cpu->env;
+
+ bool ret = false;
+
+ if (interrupt_request & CPU_INTERRUPT_RESET) {
+ if (cpu_interrupts_enabled(env)) {
+ cs->exception_index = EXCP_RESET;
+ cc->do_interrupt(cs);
+
+ cs->interrupt_request &= ~CPU_INTERRUPT_RESET;
+
+ ret = true;
+ }
+ }
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ if (cpu_interrupts_enabled(env) && env->intsrc != 0) {
+ int index = __builtin_ffs(env->intsrc) - 1;
+ cs->exception_index = EXCP_INT(index);
+ cc->do_interrupt(cs);
+
+ env->intsrc &= env->intsrc - 1; /* clear the interrupt */
+ cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
+
+ ret = true;
+ }
+ }
+ return ret;
}
void avr_cpu_do_interrupt(
CPUState *cs)
{
+ AVRCPU *cpu = AVR_CPU(cs);
+ CPUAVRState *env = &cpu->env;
+
+ uint32_t ret = env->pc;
+ int vector;
+ int size = avr_feature(env, AVR_FEATURE_JMP_CALL) ? 2 : 1;
+ int base = 0; /* TODO: where to get it */
+
+ if (cs->exception_index == EXCP_RESET) {
+ vector = 0;
+ } else if (env->intsrc != 0) {
+ vector = __builtin_ffs(env->intsrc);
+ }
+
+ if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
+ stb_phys(cs->as, env->sp--, (ret & 0x0000ff));
+ stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8);
+ stb_phys(cs->as, env->sp--, (ret & 0xff0000) >> 16);
+
+ env->pc = base + vector * size;
+ } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) {
+ stb_phys(cs->as, env->sp--, (ret & 0x0000ff));
+ stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8);
+
+ env->pc = base + vector * size;
+ } else {
+ stb_phys(cs->as, env->sp--, (ret & 0x0000ff));
+
+ env->pc = base + vector * size;
+ }
+
+ env->sregI = 0; /* clear Global Interrupt Flag */
+
+ cs->exception_index = -1;
}
int avr_cpu_memory_rw_debug(
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 06/10] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
2016-06-02 20:03 [Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions Michael Rolnik
` (3 preceding siblings ...)
2016-06-02 20:04 ` [Qemu-devel] [PATCH 05/10] target-avr: adding AVR interrupt handling Michael Rolnik
@ 2016-06-02 20:04 ` Michael Rolnik
2016-06-02 20:04 ` [Qemu-devel] [PATCH 07/10] target-avr: adding instruction decoder Michael Rolnik
` (3 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Michael Rolnik @ 2016-06-02 20:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Rolnik, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/helper.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++
target-avr/helper.h | 5 +++
2 files changed, 108 insertions(+)
diff --git a/target-avr/helper.c b/target-avr/helper.c
index ed22b37..450f598 100644
--- a/target-avr/helper.c
+++ b/target-avr/helper.c
@@ -155,6 +155,23 @@ void tlb_fill(
tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size);
}
+void helper_sleep(
+ CPUAVRState *env)
+{
+ CPUState *cs = CPU(avr_env_get_cpu(env));
+
+ cs->exception_index = EXCP_HLT;
+ cpu_loop_exit(cs);
+}
+void helper_unsupported(
+ CPUAVRState *env)
+{
+ CPUState *cs = CPU(avr_env_get_cpu(env));
+
+ cs->exception_index = EXCP_DEBUG;
+ cpu_dump_state(cs, stderr, fprintf, 0);
+ cpu_loop_exit(cs);
+}
void helper_debug(
CPUAVRState *env)
@@ -165,3 +182,89 @@ void helper_debug(
cpu_loop_exit(cs);
}
+void helper_wdr(
+ CPUAVRState *env)
+{
+ CPUState *cs = CPU(avr_env_get_cpu(env));
+
+ cs->exception_index = EXCP_DEBUG;
+ cpu_loop_exit(cs);
+}
+
+target_ulong helper_inb(
+ CPUAVRState *env,
+ uint32_t port)
+{
+ printf("in: io[%02x]\n", port);
+
+ switch (port) {
+ case 0x3b: {
+ return env->rampZ; /* RAMPZ */
+ }
+ case 0x3d: { /* SPL */
+ return env->sp & 0x00ff;
+ }
+ case 0x3e: { /* SPH */
+ return env->sp >> 8;
+ }
+ case 0x3f: { /* SREG */
+ uint8_t sreg;
+ sreg = (env->sregC & 0x01) << 0
+ | (env->sregZ & 0x01) << 1
+ | (env->sregN & 0x01) << 2
+ | (env->sregV & 0x01) << 3
+ | (env->sregS & 0x01) << 4
+ | (env->sregH & 0x01) << 5
+ | (env->sregT & 0x01) << 6
+ | (env->sregI & 0x01) << 7;
+ return sreg;
+ }
+ }
+ return 0;
+}
+
+void helper_outb(
+ CPUAVRState *env,
+ uint32_t port,
+ uint32_t data)
+{
+ printf("out:%02x -> io[%02x]\n", data, port);
+
+ data &= 0x000000ff;
+
+ switch (port) {
+ case 0x04: {
+ qemu_irq irq;
+ CPUState *cpu = CPU(avr_env_get_cpu(env));
+ irq = qdev_get_gpio_in(DEVICE(cpu), 3);
+ qemu_set_irq(irq, 1);
+ break;
+ }
+ case 0x3b: {
+ env->rampZ = data & 0x01; /* RAMPZ */
+ break;
+ }
+ case 0x3d: { /* SPL */
+ if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) {
+ env->sp = (env->sp & 0xff00) | (data);
+ }
+ break;
+ }
+ case 0x3e: { /* SPH */
+ env->sp = (env->sp & 0x00ff) | (data << 8);
+ break;
+ }
+ case 0x3f: { /* SREG */
+ env->sregC = (data >> 0) & 0x01;
+ env->sregZ = (data >> 1) & 0x01;
+ env->sregN = (data >> 2) & 0x01;
+ env->sregV = (data >> 3) & 0x01;
+ env->sregS = (data >> 4) & 0x01;
+ env->sregH = (data >> 5) & 0x01;
+ env->sregT = (data >> 6) & 0x01;
+ env->sregI = (data >> 7) & 0x01;
+ break;
+ }
+ }
+}
+
diff --git a/target-avr/helper.h b/target-avr/helper.h
index 017e076..5a08cfd 100644
--- a/target-avr/helper.h
+++ b/target-avr/helper.h
@@ -18,4 +18,9 @@
* <http://www.gnu.org/licenses/lgpl-2.1.html>
*/
+DEF_HELPER_1(wdr, void, env)
DEF_HELPER_1(debug, void, env)
+DEF_HELPER_1(sleep, void, env)
+DEF_HELPER_1(unsupported, void, env)
+DEF_HELPER_3(outb, void, env, i32, i32)
+DEF_HELPER_2(inb, tl, env, i32)
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 07/10] target-avr: adding instruction decoder
2016-06-02 20:03 [Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions Michael Rolnik
` (4 preceding siblings ...)
2016-06-02 20:04 ` [Qemu-devel] [PATCH 06/10] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions Michael Rolnik
@ 2016-06-02 20:04 ` Michael Rolnik
2016-06-02 20:04 ` [Qemu-devel] [PATCH 08/10] target-avr: adding instruction translation Michael Rolnik
` (2 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Michael Rolnik @ 2016-06-02 20:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Rolnik, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/decode.c | 724 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 724 insertions(+)
create mode 100644 target-avr/decode.c
diff --git a/target-avr/decode.c b/target-avr/decode.c
new file mode 100644
index 0000000..22e2d36
--- /dev/null
+++ b/target-avr/decode.c
@@ -0,0 +1,724 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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/lgpl-2.1.html>
+ */
+
+
+#include <stdint.h>
+#include "translate.h"
+
+
+uint32_t avr_decode(uint32_t pc, uint32_t *length, uint32_t code, translate_function_t *translate)
+{
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x0000d000) {
+ case 0x00000000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00002c00) {
+ case 0x00000000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000300) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_NOP;
+ break;
+ }
+ case 0x00000100: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_MOVW;
+ break;
+ }
+ case 0x00000200: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_MULS;
+ break;
+ }
+ case 0x00000300: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000088) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_MULSU;
+ break;
+ }
+ case 0x00000008: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_FMUL;
+ break;
+ }
+ case 0x00000080: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_FMULS;
+ break;
+ }
+ case 0x00000088: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_FMULSU;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000400: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_CPC;
+ break;
+ }
+ case 0x00000800: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SBC;
+ break;
+ }
+ case 0x00000c00: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ADD;
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_AND;
+ break;
+ }
+ case 0x00002400: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_EOR;
+ break;
+ }
+ case 0x00002800: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_OR;
+ break;
+ }
+ case 0x00002c00: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_MOV;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00001000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00002000) {
+ case 0x00000000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000c00) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_CPSE;
+ break;
+ }
+ case 0x00000400: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_CP;
+ break;
+ }
+ case 0x00000800: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SUB;
+ break;
+ }
+ case 0x00000c00: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ADC;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_CPI;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00004000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00002000) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SBCI;
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ORI;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00005000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00002000) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SUBI;
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ANDI;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00008000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000208) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LDDZ;
+ break;
+ }
+ case 0x00000008: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LDDY;
+ break;
+ }
+ case 0x00000200: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_STDZ;
+ break;
+ }
+ case 0x00000208: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_STDY;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00009000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00002800) {
+ case 0x00000000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000600) {
+ case 0x00000000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x0000000f) {
+ case 0x00000000: {
+ *length = 32;
+ *translate = (translate_function_t)&avr_translate_LDS;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LDZ2;
+ break;
+ }
+ case 0x00000002: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LDZ3;
+ break;
+ }
+ case 0x00000003: {
+ break;
+ }
+ case 0x00000004: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LPM2;
+ break;
+ }
+ case 0x00000005: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LPMX;
+ break;
+ }
+ case 0x00000006: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ELPM2;
+ break;
+ }
+ case 0x00000007: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ELPMX;
+ break;
+ }
+ case 0x00000008: {
+ break;
+ }
+ case 0x00000009: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LDY2;
+ break;
+ }
+ case 0x0000000a: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LDY3;
+ break;
+ }
+ case 0x0000000b: {
+ break;
+ }
+ case 0x0000000c: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LDX1;
+ break;
+ }
+ case 0x0000000d: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LDX2;
+ break;
+ }
+ case 0x0000000e: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LDX3;
+ break;
+ }
+ case 0x0000000f: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_POP;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000200: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x0000000f) {
+ case 0x00000000: {
+ *length = 32;
+ *translate = (translate_function_t)&avr_translate_STS;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_STZ2;
+ break;
+ }
+ case 0x00000002: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_STZ3;
+ break;
+ }
+ case 0x00000003: {
+ break;
+ }
+ case 0x00000004: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_XCH;
+ break;
+ }
+ case 0x00000005: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LAS;
+ break;
+ }
+ case 0x00000006: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LAC;
+ break;
+ }
+ case 0x00000007: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LAT;
+ break;
+ }
+ case 0x00000008: {
+ break;
+ }
+ case 0x00000009: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_STY2;
+ break;
+ }
+ case 0x0000000a: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_STY3;
+ break;
+ }
+ case 0x0000000b: {
+ break;
+ }
+ case 0x0000000c: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_STX1;
+ break;
+ }
+ case 0x0000000d: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_STX2;
+ break;
+ }
+ case 0x0000000e: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_STX3;
+ break;
+ }
+ case 0x0000000f: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_PUSH;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000400: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x0000000e) {
+ case 0x00000000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000001) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_COM;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_NEG;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000002: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000001) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SWAP;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_INC;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000004: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ASR;
+ break;
+ }
+ case 0x00000006: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000001) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LSR;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ROR;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000008: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000181) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_BSET;
+ break;
+ }
+ case 0x00000001: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000010) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_IJMP;
+ break;
+ }
+ case 0x00000010: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_EIJMP;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000080: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_BCLR;
+ break;
+ }
+ case 0x00000081: {
+ break;
+ }
+ case 0x00000100: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000010) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_RET;
+ break;
+ }
+ case 0x00000010: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_RETI;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000101: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000010) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ICALL;
+ break;
+ }
+ case 0x00000010: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_EICALL;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000180: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000070) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SLEEP;
+ break;
+ }
+ case 0x00000010: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_BREAK;
+ break;
+ }
+ case 0x00000020: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_WDR;
+ break;
+ }
+ case 0x00000030: {
+ break;
+ }
+ case 0x00000040: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LPM1;
+ break;
+ }
+ case 0x00000050: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ELPM1;
+ break;
+ }
+ case 0x00000060: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SPM;
+ break;
+ }
+ case 0x00000070: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SPMX;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000181: {
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000000a: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000001) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_DEC;
+ break;
+ }
+ case 0x00000001: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_DES;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000000c: {
+ *length = 32;
+ *translate = (translate_function_t)&avr_translate_JMP;
+ break;
+ }
+ case 0x0000000e: {
+ *length = 32;
+ *translate = (translate_function_t)&avr_translate_CALL;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000600: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000100) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_ADIW;
+ break;
+ }
+ case 0x00000100: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SBIW;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000800: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000400) {
+ case 0x00000000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000300) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_CBI;
+ break;
+ }
+ case 0x00000100: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SBIC;
+ break;
+ }
+ case 0x00000200: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SBI;
+ break;
+ }
+ case 0x00000300: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SBIS;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000400: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_MUL;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_IN;
+ break;
+ }
+ case 0x00002800: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_OUT;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000c000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00002000) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_RJMP;
+ break;
+ }
+ case 0x00002000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_LDI;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x0000d000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00002000) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_RCALL;
+ break;
+ }
+ case 0x00002000: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000c00) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_BRBS;
+ break;
+ }
+ case 0x00000400: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_BRBC;
+ break;
+ }
+ case 0x00000800: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000200) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_BLD;
+ break;
+ }
+ case 0x00000200: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_BST;
+ break;
+ }
+ }
+ break;
+ }
+ case 0x00000c00: {
+ uint32_t opcode = extract32(code, 0, 16);
+ switch (opcode & 0x00000200) {
+ case 0x00000000: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SBRC;
+ break;
+ }
+ case 0x00000200: {
+ *length = 16;
+ *translate = (translate_function_t)&avr_translate_SBRS;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 08/10] target-avr: adding instruction translation
2016-06-02 20:03 [Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions Michael Rolnik
` (5 preceding siblings ...)
2016-06-02 20:04 ` [Qemu-devel] [PATCH 07/10] target-avr: adding instruction decoder Michael Rolnik
@ 2016-06-02 20:04 ` Michael Rolnik
2016-06-02 20:04 ` [Qemu-devel] [PATCH 09/10] target-avr: updating translate.c to use instructions translation Michael Rolnik
2016-06-02 20:04 ` [Qemu-devel] [PATCH 10/10] target-avr: fixing code style Michael Rolnik
8 siblings, 0 replies; 13+ messages in thread
From: Michael Rolnik @ 2016-06-02 20:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Rolnik, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/translate-inst.c | 2443 +++++++++++++++++++++++++++++++++++++++++++
target-avr/translate.h | 123 +++
2 files changed, 2566 insertions(+)
create mode 100644 target-avr/translate-inst.c
create mode 100644 target-avr/translate.h
diff --git a/target-avr/translate-inst.c b/target-avr/translate-inst.c
new file mode 100644
index 0000000..fe9d9fc
--- /dev/null
+++ b/target-avr/translate-inst.c
@@ -0,0 +1,2443 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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/lgpl-2.1.html>
+ */
+
+#include "translate.h"
+#include "translate-inst.h"
+
+/*
+ NOTE: all registers are assumed to hold 8 bit values.
+ so all operations done on registers should preseve this property
+*/
+
+/*
+ NOTE: the flags C,H,V,N,V have either 0 or 1 values
+ NOTE: the flag Z has inverse logic, when the value of Zf is 0 the flag is assumed to be set, non zero - not set
+*/
+
+void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr);
+void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr);
+void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr);
+void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr);
+void gen_ZNSf(TCGv R);
+void gen_push_ret(CPUAVRState *env, int ret);
+void gen_pop_ret(CPUAVRState *env, TCGv ret);
+void gen_jmp_ez(void);
+void gen_jmp_z(void);
+
+void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv l); /* H:M:L = addr */
+void gen_set_xaddr(TCGv addr);
+void gen_set_yaddr(TCGv addr);
+void gen_set_zaddr(TCGv addr);
+
+TCGv gen_get_addr(TCGv H, TCGv M, TCGv L); /* addr = H:M:L */
+TCGv gen_get_xaddr(void);
+TCGv gen_get_yaddr(void);
+TCGv gen_get_zaddr(void);
+int sex(int Imm, unsigned bits);
+
+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_not_tl(t2, R); /* t2 = Rd & ~R */
+ tcg_gen_and_tl(t2, Rd, t2);
+ tcg_gen_not_tl(t3, R); /* t3 = Rr *~R */
+ tcg_gen_and_tl(t3, Rr, t3);
+ 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);
+}
+
+void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
+{
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv t2 = tcg_temp_new_i32();
+
+ tcg_gen_not_tl(t1, Rd); /* t1 = ~Rd & ~Rr & R */
+ tcg_gen_not_tl(t2, Rr);
+ tcg_gen_and_tl(t1, t1, t2);
+ tcg_gen_and_tl(t1, t1, R);
+
+ tcg_gen_not_tl(t2, R); /* t2 = Rd & Rr & ~R */
+ tcg_gen_and_tl(t2, t2, Rd);
+ tcg_gen_and_tl(t2, t2, Rr);
+
+ tcg_gen_or_tl(t1, t1, t2); /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R */
+
+ tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
+
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+}
+
+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();
+
+ /* Cf & Hf */
+ 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);
+}
+
+void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
+{
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv t2 = tcg_temp_new_i32();
+
+ /* Vf */
+ tcg_gen_and_tl(t1, Rr, R); /* t1 = Rd & ~Rr & ~R */
+ tcg_gen_not_tl(t1, t1);
+ tcg_gen_and_tl(t1, t1, Rd);
+ tcg_gen_not_tl(t2, Rd); /* t2 = ~Rd & Rr & R */
+ tcg_gen_and_tl(t2, t2, Rr);
+ tcg_gen_and_tl(t2, t2, R);
+ tcg_gen_or_tl(t1, t1, t2); /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R */
+ tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */
+
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+}
+
+void gen_ZNSf(TCGv R)
+{
+ tcg_gen_mov_tl(cpu_Zf, R); /* Zf = R */
+ tcg_gen_shri_tl(cpu_Nf, R, 7); /* Nf = R(7) */
+ tcg_gen_and_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf & Vf */
+}
+
+void gen_push_ret(CPUAVRState *env, int ret)
+{
+ tcg_gen_qemu_st8(tcg_const_local_i32((ret & 0x0000ff)), cpu_sp, DATA_INDEX);
+ tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
+
+ if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)
+ || avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
+ tcg_gen_qemu_st8(tcg_const_local_i32((ret & 0x00ff00) >> 8), cpu_sp, DATA_INDEX);
+ tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
+ }
+
+ if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
+ tcg_gen_qemu_st8(tcg_const_local_i32((ret & 0xff0000) >> 16), cpu_sp, DATA_INDEX);
+ tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
+ }
+}
+
+void gen_pop_ret(CPUAVRState *env, TCGv ret)
+{
+ TCGv t0 = tcg_const_i32(0);
+ TCGv t1 = tcg_const_i32(0);
+ TCGv t2 = tcg_const_i32(0);
+
+ if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
+ tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
+ tcg_gen_qemu_ld8u(t2, cpu_sp, DATA_INDEX);
+ tcg_gen_shli_tl(t2, t2, 16);
+ }
+
+ if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)
+ || avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
+ tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
+ tcg_gen_qemu_ld8u(t1, cpu_sp, DATA_INDEX);
+ tcg_gen_shli_tl(t1, t1, 8);
+ }
+
+ tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
+ tcg_gen_qemu_ld8u(t0, cpu_sp, DATA_INDEX);
+
+ tcg_gen_or_tl(ret, t0, t1);
+ tcg_gen_or_tl(ret, ret, t2);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
+}
+
+void gen_jmp_ez()
+{
+ tcg_gen_mov_tl(cpu_pc, cpu_eind);
+ tcg_gen_shli_tl(cpu_pc, cpu_pc, 8);
+ tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_r[31]);
+ tcg_gen_shli_tl(cpu_pc, cpu_pc, 8);
+ tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_r[30]);
+ tcg_gen_andi_tl(cpu_pc, cpu_pc, 0xffffff);
+ tcg_gen_exit_tb(0);
+}
+
+void gen_jmp_z()
+{
+ tcg_gen_mov_tl(cpu_pc, cpu_r[31]);
+ tcg_gen_shli_tl(cpu_pc, cpu_pc, 8);
+ tcg_gen_or_tl(cpu_pc, cpu_pc, cpu_r[30]);
+ tcg_gen_andi_tl(cpu_pc, cpu_pc, 0xffff);
+ tcg_gen_exit_tb(0);
+}
+
+void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv L)
+{
+ tcg_gen_andi_tl(L, addr, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_andi_tl(M, addr, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_andi_tl(H, addr, 0xff);
+}
+
+void gen_set_xaddr(TCGv addr)
+{
+ gen_set_addr(addr, cpu_rampX, cpu_r[27], cpu_r[26]);
+}
+
+void gen_set_yaddr(TCGv addr)
+{
+ gen_set_addr(addr, cpu_rampY, cpu_r[29], cpu_r[28]);
+}
+
+void gen_set_zaddr(TCGv addr)
+{
+ gen_set_addr(addr, cpu_rampZ, cpu_r[31], cpu_r[30]);
+}
+
+TCGv gen_get_addr(TCGv H, TCGv M, TCGv L)
+{
+ TCGv addr= tcg_temp_new_i32();
+
+ tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl(addr, addr, M);
+ tcg_gen_shli_tl(addr, addr, 8);
+ tcg_gen_or_tl(addr, addr, L);
+
+ return addr;
+}
+
+TCGv gen_get_xaddr()
+{
+ return gen_get_addr(cpu_rampX, cpu_r[27], cpu_r[26]);
+}
+
+TCGv gen_get_yaddr()
+{
+ return gen_get_addr(cpu_rampY, cpu_r[29], cpu_r[28]);
+}
+
+TCGv gen_get_zaddr()
+{
+ return gen_get_addr(cpu_rampZ, cpu_r[31], cpu_r[30]);
+}
+
+int sex(int Imm, unsigned bits)
+{
+ Imm <<= 32 - bits;
+ Imm >>= 32 - bits;
+
+ return Imm;
+}
+
+/*
+ Adds two registers and the contents of the C Flag and places the result in the destination register Rd.
+*/
+int avr_translate_ADC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[ADC_Rd(opcode)];
+ TCGv Rr = cpu_r[(ADC_hRr(opcode) << 4) | (ADC_lRr(opcode))];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ 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 */
+
+ gen_add_CHf(R, Rd, Rr);
+ gen_add_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ Adds two registers without the C Flag and places the result in the destination register Rd.
+*/
+int avr_translate_ADD(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[ADD_Rd(opcode)];
+ TCGv Rr = cpu_r[(ADD_hRr(opcode) << 4) | (ADD_lRr(opcode))];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_add_tl(R, Rd, Rr); /* Rd = Rd + Rr */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ gen_add_CHf(R, Rd, Rr);
+ gen_add_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ 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.
+*/
+int avr_translate_ADIW(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_ADIW_SBIW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv RdL = cpu_r[24 + 2 * ADIW_Rd(opcode)];
+ TCGv RdH = cpu_r[25 + 2 * ADIW_Rd(opcode)];
+ int Imm = (ADIW_hImm(opcode) << 4) | (ADIW_lImm(opcode));
+ TCGv R = tcg_temp_new_i32();
+ TCGv Rd = tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_shli_tl(Rd, RdH, 8); /* R = ((H << 8) | L) + Imm */
+ tcg_gen_or_tl(Rd, RdL, Rd);
+ tcg_gen_addi_tl(R, Rd, Imm);
+ tcg_gen_andi_tl(R, R, 0xffff);/* make it 16 bits */
+
+ /* Cf */
+ tcg_gen_not_tl(t0, R); /* t0 = Rd & ~R */
+ tcg_gen_and_tl(t0, Rd, t0);
+ tcg_gen_shri_tl(cpu_Cf, t0, 15); /* Cf = t0(15) */
+
+ /* Vf */
+ tcg_gen_not_tl(t0, Rd); /* t0 = ~Rd & R */
+ tcg_gen_and_tl(t0, R, t0);
+
+ tcg_gen_shri_tl(cpu_Vf, t0, 15); /* Vf = t0(15) */
+
+ /* Zf */
+ tcg_gen_mov_tl(cpu_Zf, R); /* Zf = R */
+
+ /* Nf */
+ tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
+
+ /* Sf */
+ tcg_gen_and_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf & Vf */
+
+ /* R */
+ tcg_gen_andi_tl(RdL, R, 0xff);
+ tcg_gen_shri_tl(RdH, R, 8);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(Rd);
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ Performs the logical AND between the contents of register Rd and register Rr and places the result in the
+ destination register Rd.
+*/
+int avr_translate_AND(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[AND_Rd(opcode)];
+ TCGv Rr = cpu_r[(AND_hRr(opcode) << 4) | (AND_lRr(opcode))];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_and_tl(R, Rd, Rr); /* Rd = Rd and Rr */
+
+ /* Vf */
+ tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
+
+ /* Zf */
+ tcg_gen_mov_tl(cpu_Zf, R); /* Zf = R */
+
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ Performs the logical AND between the contents of register Rd and a constant and places the result in the
+ destination register Rd.
+*/
+int avr_translate_ANDI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[ANDI_Rd(opcode)];
+ int Imm = (ANDI_hImm(opcode) << 4) | (ANDI_lImm(opcode));
+
+ /* op */
+ tcg_gen_andi_tl(Rd, Rd, Imm); /* Rd = Rd & Imm */
+
+ tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
+ gen_ZNSf(Rd);
+
+ return BS_NONE;
+}
+
+/*
+ Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0 is loaded into the C Flag of the SREG. This
+ operation effectively divides a signed value by two without changing its sign. The Carry Flag can be used to
+ round the result.
+*/
+int avr_translate_ASR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[ASR_Rd(opcode)];
+ TCGv t1 = tcg_temp_new_i32();
+ TCGv t2 = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_andi_tl(t1, Rd, 0x80); /* t1 = (Rd & 0x80) | (Rd >> 1) */
+ tcg_gen_shri_tl(t2, Rd, 1);
+ tcg_gen_or_tl(t1, t1, t2);
+
+ /* Cf */
+ tcg_gen_andi_tl(cpu_Cf, Rd, 1); /* Cf = Rd(0) */
+
+ /* Vf */
+ tcg_gen_and_tl(cpu_Vf, cpu_Nf, cpu_Cf);/* Vf = Nf & Cf */
+
+ gen_ZNSf(t1);
+
+ /* op */
+ tcg_gen_mov_tl(Rd, t1);
+
+ tcg_temp_free_i32(t2);
+ tcg_temp_free_i32(t1);
+
+ return BS_NONE;
+}
+
+/*
+ Clears a single Flag in SREG.
+*/
+int avr_translate_BCLR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ switch(BCLR_Bit(opcode)) {
+ case 0x00: tcg_gen_movi_tl(cpu_Cf, 0x00); break;
+ case 0x01: tcg_gen_movi_tl(cpu_Zf, 0x01); break;
+ case 0x02: tcg_gen_movi_tl(cpu_Nf, 0x00); break;
+ case 0x03: tcg_gen_movi_tl(cpu_Vf, 0x00); break;
+ case 0x04: tcg_gen_movi_tl(cpu_Sf, 0x00); break;
+ case 0x05: tcg_gen_movi_tl(cpu_Hf, 0x00); break;
+ case 0x06: tcg_gen_movi_tl(cpu_Tf, 0x00); break;
+ case 0x07: tcg_gen_movi_tl(cpu_If, 0x00); break;
+ }
+
+ return BS_NONE;
+}
+
+/*
+ Copies the T Flag in the SREG (Status Register) to bit b in register Rd.
+*/
+int avr_translate_BLD(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[BLD_Rd(opcode)];
+ TCGv t1 = tcg_temp_new_i32();
+
+ tcg_gen_shli_tl(t1, cpu_Tf, BLD_Bit(opcode));
+ tcg_gen_or_tl(Rd, Rd, t1);
+ tcg_gen_and_tl(Rd, Rd, t1);
+
+ tcg_temp_free_i32(t1);
+
+ return BS_NONE;
+}
+
+/*
+ Conditional relative branch. Tests a single bit in SREG and branches relatively to PC if the bit is cleared. This
+ instruction branches relatively to PC in either direction (PC - 63 <= destination <= PC + 64). The parameter k is the
+ offset from PC and is represented in two’s complement form.
+*/
+int avr_translate_BRBC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGLabel *taken = gen_new_label();
+ int Imm = sex(BRBC_Imm(opcode), 7);
+
+ switch(BRBC_Bit(opcode)) {
+ case 0x00: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Cf, 0, taken); break;
+ case 0x01: tcg_gen_brcondi_i32(TCG_COND_NE, cpu_Zf, 0, taken); break;
+ case 0x02: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Nf, 0, taken); break;
+ case 0x03: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Vf, 0, taken); break;
+ case 0x04: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Sf, 0, taken); break;
+ case 0x05: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Hf, 0, taken); break;
+ case 0x06: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Tf, 0, taken); break;
+ case 0x07: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_If, 0, taken); break;
+ }
+
+ gen_goto_tb(env, ctx, 1, ctx->inst[0].npc);
+ gen_set_label(taken);
+ gen_goto_tb(env, ctx, 0, ctx->inst[0].npc + Imm);
+
+ return BS_BRANCH;
+}
+
+/*
+ Conditional relative branch. Tests a single bit in SREG and branches relatively to PC if the bit is set. This
+ instruction branches relatively to PC in either direction (PC - 63 <= destination <= PC + 64). The parameter k is the
+ offset from PC and is represented in two’s complement form.
+*/
+int avr_translate_BRBS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGLabel *taken = gen_new_label();
+ int Imm = sex(BRBS_Imm(opcode), 7);
+
+ switch(BRBS_Bit(opcode)) {
+ case 0x00: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Cf, 1, taken); break;
+ case 0x01: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Zf, 0, taken); break;
+ case 0x02: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Nf, 1, taken); break;
+ case 0x03: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Vf, 1, taken); break;
+ case 0x04: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Sf, 1, taken); break;
+ case 0x05: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Hf, 1, taken); break;
+ case 0x06: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_Tf, 1, taken); break;
+ case 0x07: tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_If, 1, taken); break;
+ }
+
+ gen_goto_tb(env, ctx, 1, ctx->inst[0].npc);
+ gen_set_label(taken);
+ gen_goto_tb(env, ctx, 0, ctx->inst[0].npc + Imm);
+
+ return BS_BRANCH;
+}
+
+/*
+ Sets a single Flag or bit in SREG.
+*/
+int avr_translate_BSET(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ switch(BSET_Bit(opcode)) {
+ case 0x00: tcg_gen_movi_tl(cpu_Cf, 0x01); break;
+ case 0x01: tcg_gen_movi_tl(cpu_Zf, 0x00); break;
+ case 0x02: tcg_gen_movi_tl(cpu_Nf, 0x01); break;
+ case 0x03: tcg_gen_movi_tl(cpu_Vf, 0x01); break;
+ case 0x04: tcg_gen_movi_tl(cpu_Sf, 0x01); break;
+ case 0x05: tcg_gen_movi_tl(cpu_Hf, 0x01); break;
+ case 0x06: tcg_gen_movi_tl(cpu_Tf, 0x01); break;
+ case 0x07: tcg_gen_movi_tl(cpu_If, 0x01); break;
+ }
+
+ return BS_NONE;
+}
+
+/*
+ The BREAK instruction is used by the On-chip Debug system, and is normally not used in the application
+ software. When the BREAK instruction is executed, the AVR CPU is set in the Stopped Mode. This gives the
+ On-chip Debugger access to internal resources.
+ If any Lock bits are set, or either the JTAGEN or OCDEN Fuses are unprogrammed, the CPU will treat the
+ BREAK instruction as a NOP and will not enter the Stopped mode.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_BREAK(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_BREAK) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ /* TODO: ??? */
+ return BS_NONE;
+}
+
+/*
+ Stores bit b from Rd to the T Flag in SREG (Status Register).
+*/
+int avr_translate_BST(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[BST_Rd(opcode)];
+
+ tcg_gen_andi_tl(cpu_Tf, Rd, 1 << BST_Bit(opcode));
+ tcg_gen_shri_tl(cpu_Tf, cpu_Tf, BST_Bit(opcode));
+
+ return BS_NONE;
+}
+
+/*
+ Calls to a subroutine within the entire Program memory. The return address (to the instruction after the CALL)
+ will be stored onto the Stack. (See also RCALL). The Stack Pointer uses a post-decrement scheme during
+ CALL.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_CALL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_JMP_CALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ int Imm = (CALL_hImm(opcode) << 17) | CALL_lImm(opcode);
+ int ret = ctx->inst[0].npc;
+
+ gen_push_ret(env, ret);
+
+ gen_goto_tb(env, ctx, 0, Imm);
+
+ return BS_BRANCH;
+}
+
+/*
+ Clears a specified bit in an I/O Register. This instruction operates on the lower 32 I/O Registers – addresses 0-31. */
+int avr_translate_CBI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv data= cpu_io[CBI_Imm(opcode)];
+ TCGv port= tcg_const_i32(CBI_Imm(opcode));
+
+ tcg_gen_andi_tl(data, data, ~(1 << CBI_Bit(opcode)));
+ gen_helper_outb(cpu_env, port, data);
+
+ return BS_NONE;
+}
+
+/*
+ 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.
+*/
+int avr_translate_COM(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[COM_Rd(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_movi_tl(R, 0xff);
+ tcg_gen_sub_tl(Rd, R, Rd);
+
+ 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 BS_NONE;
+}
+
+/*
+ This instruction performs a compare between two registers Rd and Rr. None of the registers are changed. All
+ conditional branches can be used after this instruction.
+*/
+int avr_translate_CP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[CP_Rd(opcode)];
+ TCGv Rr = cpu_r[(CP_hRr(opcode) << 4) | (CP_lRr(opcode))];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction performs a compare between two registers Rd and Rr and also takes into account the previous
+ carry. None of the registers are changed. All conditional branches can be used after this instruction.
+*/
+int avr_translate_CPC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[CPC_Rd(opcode)];
+ TCGv Rr = cpu_r[(CPC_hRr(opcode) << 4) | (CPC_lRr(opcode))];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ 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 */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction performs a compare between register Rd and a constant. The register is not changed. All
+ conditional branches can be used after this instruction.
+*/
+int avr_translate_CPI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[CPI_Rd(opcode)];
+ int Imm = (CPI_hImm(opcode) << 4) | CPI_lImm(opcode);
+ TCGv Rr = tcg_const_i32(Imm);
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction performs a compare between two registers Rd and Rr, and skips the next instruction if Rd = Rr.
+*/
+int avr_translate_CPSE(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[CPSE_Rd(opcode)];
+ TCGv Rr = cpu_r[(CPSE_hRr(opcode) << 4) | (CPSE_lRr(opcode))];
+ TCGLabel *skip= gen_new_label();
+
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[1].npc); /* PC if next inst is skipped */
+ tcg_gen_brcond_i32(TCG_COND_EQ, Rd, Rr, skip);
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[0].npc); /* PC if next inst is not skipped */
+ gen_set_label(skip);
+
+ return BS_BRANCH;
+}
+
+/*
+ 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.
+*/
+int avr_translate_DEC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[DEC_Rd(opcode)];
+
+ tcg_gen_subi_tl(Rd, Rd, 1); /* Rd = Rd - 1 */
+ tcg_gen_andi_tl(Rd, Rd, 0xff); /* make it 8 bits */
+
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x7f); /* cpu_Vf = Rd == 0x7f */
+ gen_ZNSf(Rd);
+
+ return BS_NONE;
+}
+
+/*
+
+ 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.
+*/
+int avr_translate_DES(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ /* TODO: */
+ if (avr_feature(env, AVR_FEATURE_DES) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ return BS_NONE;
+}
+
+/*
+ Indirect call of a subroutine pointed to by the Z (16 bits) Pointer Register in the Register File and the EIND
+ Register in the I/O space. This instruction allows for indirect calls to the entire 4M (words) Program memory
+ space. See also ICALL. The Stack Pointer uses a post-decrement scheme during EICALL.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_EICALL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_EIJMP_EICALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ int ret = ctx->inst[0].npc;
+
+ gen_push_ret(env, ret);
+
+ gen_jmp_ez();
+
+ return BS_BRANCH;
+}
+
+/*
+ Indirect jump to the address pointed to by the Z (16 bits) Pointer Register in the Register File and the EIND
+ Register in the I/O space. This instruction allows for indirect jumps to the entire 4M (words) Program memory
+ space. See also IJMP.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_EIJMP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_EIJMP_EICALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ gen_jmp_ez();
+
+ return BS_BRANCH;
+}
+
+/*
+ Loads one byte pointed to by the Z-register and the RAMPZ Register in the I/O space, and places this byte in
+ the destination register Rd. This instruction features a 100% space effective constant initialization or constant
+ data fetch. The Program memory is organized in 16-bit words while the Z-pointer is a byte address. Thus, the
+ least significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This instruction can
+ address the entire Program memory space. The Z-pointer Register can either be left unchanged by the
+ operation, or it can be incremented. The incrementation applies to the entire 24-bit concatenation of the RAMPZ
+ and Z-pointer Registers.
+ Devices with Self-Programming capability can use the ELPM instruction to read the Fuse and Lock bit value.
+ Refer to the device documentation for a detailed description.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_ELPM1(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_ELPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[0];
+ TCGv addr= gen_get_zaddr();
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* Rd = mem[addr] */
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_ELPM2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_ELPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[ELPM2_Rd(opcode)];
+ TCGv addr= gen_get_zaddr();
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* Rd = mem[addr] */
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_ELPMX(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_ELPMX) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[ELPMX_Rd(opcode)];
+ TCGv addr= gen_get_zaddr();
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* Rd = mem[addr] */
+
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ gen_set_zaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Performs the logical EOR between the contents of register Rd and register Rr and places the result in the
+ destination register Rd.
+*/
+int avr_translate_EOR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[EOR_Rd(opcode)];
+ TCGv Rr = cpu_r[(EOR_hRr(opcode) << 4) | (EOR_lRr(opcode))];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_xor_tl(R, Rd, Rr);
+
+ tcg_gen_movi_tl(cpu_Vf, 0);
+ gen_ZNSf(R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication and shifts the result one bit left.
+*/
+int avr_translate_FMUL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[16 + FMUL_Rd(opcode)];
+ TCGv Rr = cpu_r[16 + FMUL_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd *Rr */
+ tcg_gen_shli_tl(R, R, 1);
+
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_andi_tl(R1, R, 0xff);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf = R(16) */
+ tcg_gen_andi_tl(cpu_Zf, R, 0x0000ffff);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication and shifts the result one bit left.
+*/
+int avr_translate_FMULS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[16 + FMULS_Rd(opcode)];
+ TCGv Rr = cpu_r[16 + FMULS_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl(Rd, Rd); /* make Rd full 32 bit signed */
+ tcg_gen_ext8s_tl(Rr, Rr); /* make Rr full 32 bit signed */
+ tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd *Rr */
+ tcg_gen_shli_tl(R, R, 1);
+
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_andi_tl(R1, R, 0xff);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf = R(16) */
+ tcg_gen_andi_tl(cpu_Zf, R, 0x0000ffff);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication and shifts the result one bit left.
+*/
+int avr_translate_FMULSU(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[16 + FMULSU_Rd(opcode)];
+ TCGv Rr = cpu_r[16 + FMULSU_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl(Rd, Rd); /* make Rd full 32 bit signed */
+ tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd *Rr */
+ tcg_gen_shli_tl(R, R, 1);
+
+ tcg_gen_andi_tl(R0, R, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_andi_tl(R1, R, 0xff);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf = R(16) */
+ tcg_gen_andi_tl(cpu_Zf, R, 0x0000ffff);
+
+ return BS_NONE;
+}
+
+/*
+ Calls to a subroutine within the entire 4M (words) Program memory. The return address (to the instruction after
+ the CALL) will be stored onto the Stack. See also RCALL. The Stack Pointer uses a post-decrement scheme
+ during CALL.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_ICALL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_IJMP_ICALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ int ret = ctx->inst[0].npc;
+
+ gen_push_ret(env, ret);
+ gen_jmp_z();
+
+ return BS_BRANCH;
+}
+
+/*
+ Indirect jump to the address pointed to by the Z (16 bits) Pointer Register in the Register File. The Z-pointer
+ Register is 16 bits wide and allows jump within the lowest 64K words (128KB) section of Program memory.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_IJMP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_IJMP_ICALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ gen_jmp_z();
+
+ return BS_BRANCH;
+}
+
+/*
+ Loads data from the I/O Space (Ports, Timers, Configuration Registers, etc.) into register Rd in the Register
+ File.
+*/
+int avr_translate_IN(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[IN_Rd(opcode)];
+ int Imm = (IN_hImm(opcode) << 4) | IN_lImm(opcode);
+ TCGv port= tcg_const_i32(Imm);
+ TCGv data= cpu_io[Imm];
+
+ gen_helper_inb(data, cpu_env, port);
+ tcg_gen_mov_tl(Rd, data);
+
+ return BS_NONE;
+}
+
+/*
+ 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.
+*/
+int avr_translate_INC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[INC_Rd(opcode)];
+
+ tcg_gen_addi_tl(Rd, Rd, 1);
+ tcg_gen_andi_tl(Rd, Rd, 0xff);
+
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, Rd, 0x80); /* cpu_Vf = Rd == 0x80 */
+ gen_ZNSf(Rd);
+ return BS_NONE;
+}
+
+/*
+ Jump to an address within the entire 4M (words) Program memory. See also RJMP.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.0
+*/
+int avr_translate_JMP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_JMP_CALL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ gen_goto_tb(env, ctx, 0, (JMP_hImm(opcode) << 17) | JMP_lImm(opcode));
+ return BS_BRANCH;
+}
+
+/*
+ Load one byte indirect from data space to register and stores an clear the bits in data space specified by the
+ register. The instruction can only be used towards internal SRAM.
+ The data location is pointed to by the Z (16 bits) Pointer Register in the Register File. Memory access is limited
+ to the current data segment of 64KB. To access another data segment in devices with more than 64KB data
+ space, the RAMPZ in register in the I/O area has to be changed.
+ The Z-pointer Register is left unchanged by the operation. This instruction is especially suited for clearing status
+ bits stored in SRAM.
+*/
+int avr_translate_LAC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rr = cpu_r[LAC_Rr(opcode)];
+ TCGv addr= gen_get_zaddr();
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv t1 = tcg_temp_new_i32();
+
+ tcg_gen_qemu_ld8u(
+ t0, addr, DATA_INDEX); /* t0 = mem[addr] */
+ tcg_gen_movi_tl(t1, 0xff); /* t1 = t0 & (0xff - Rr) */
+ tcg_gen_sub_tl(t1, t1, Rr);
+ tcg_gen_and_tl(t1, t0, t1);
+
+ tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
+ tcg_gen_qemu_st8(t1, addr, DATA_INDEX); /* mem[addr] = t1 */
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Load one byte indirect from data space to register and set bits in data space specified by the register. The
+ instruction can only be used towards internal SRAM.
+ The data location is pointed to by the Z (16 bits) Pointer Register in the Register File. Memory access is limited
+ to the current data segment of 64KB. To access another data segment in devices with more than 64KB data
+ space, the RAMPZ in register in the I/O area has to be changed.
+ The Z-pointer Register is left unchanged by the operation. This instruction is especially suited for setting status
+ bits stored in SRAM.
+*/
+int avr_translate_LAS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rr = cpu_r[LAS_Rr(opcode)];
+ TCGv addr= gen_get_zaddr();
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv t1 = tcg_temp_new_i32();
+
+ tcg_gen_qemu_ld8u(
+ t0, addr, DATA_INDEX); /* t0 = mem[addr] */
+ tcg_gen_or_tl(t1, t0, Rr);
+
+ tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
+ tcg_gen_qemu_st8(t1, addr, DATA_INDEX); /* mem[addr] = t1 */
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Load one byte indirect from data space to register and toggles bits in the data space specified by the register.
+ The instruction can only be used towards SRAM.
+ The data location is pointed to by the Z (16 bits) Pointer Register in the Register File. Memory access is limited
+ to the current data segment of 64KB. To access another data segment in devices with more than 64KB data
+ space, the RAMPZ in register in the I/O area has to be changed.
+ The Z-pointer Register is left unchanged by the operation. This instruction is especially suited for changing
+ status bits stored in SRAM.
+*/
+int avr_translate_LAT(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rr = cpu_r[LAT_Rr(opcode)];
+ TCGv addr = gen_get_zaddr();
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv t1 = tcg_temp_new_i32();
+
+ tcg_gen_qemu_ld8u(
+ t0, addr, DATA_INDEX); /* t0 = mem[addr] */
+ tcg_gen_xor_tl(t1, t0, Rr);
+
+ tcg_gen_mov_tl(Rr, t0); /* Rr = t0 */
+ tcg_gen_qemu_st8(t1, addr, DATA_INDEX); /* mem[addr] = t1 */
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Loads one byte indirect from the data space to a register. For parts with SRAM, the data space consists of the
+ Register File, I/O memory and internal SRAM (and external SRAM if applicable). For parts without SRAM, the
+ data space consists of the Register File only. In some parts the Flash Memory has been mapped to the data
+ space and can be read using this command. The EEPROM has a separate address space.
+ The data location is pointed to by the X (16 bits) Pointer Register in the Register File. Memory access is limited
+ to the current data segment of 64KB. To access another data segment in devices with more than 64KB data
+ space, the RAMPX in register in the I/O area has to be changed.
+ The X-pointer Register can either be left unchanged by the operation, or it can be post-incremented or predecremented.
+ These features are especially suited for accessing arrays, tables, and Stack Pointer usage of the
+ X-pointer Register. Note that only the low byte of the X-pointer is updated in devices with no more than 256
+ bytes data space. For such devices, the high byte of the pointer is not used by this instruction and can be used
+ for other purposes. The RAMPX Register in the I/O area is updated in parts with more than 64KB data space or
+ more than 64KB Program memory, and the increment/decrement is added to the entire 24-bit address on such
+ devices.
+ Not all variants of this instruction is available in all devices. Refer to the device specific instruction set summary.
+ In the Reduced Core tinyAVR the LD instruction can be used to achieve the same operation as LPM since the
+ program memory is mapped to the data memory space.
+*/
+int avr_translate_LDX1(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDX1_Rd(opcode)];
+ TCGv addr= gen_get_xaddr();
+
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_LDX2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDX2_Rd(opcode)];
+ TCGv addr= gen_get_xaddr();
+
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ gen_set_xaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_LDX3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDX3_Rd(opcode)];
+ TCGv addr= gen_get_xaddr();
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+ gen_set_xaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Loads one byte indirect with or without displacement from the data space to a register. For parts with SRAM, the
+ data space consists of the Register File, I/O memory and internal SRAM (and external SRAM if applicable). For
+ parts without SRAM, the data space consists of the Register File only. In some parts the Flash Memory has
+ been mapped to the data space and can be read using this command. The EEPROM has a separate address
+ space.
+ The data location is pointed to by the Y (16 bits) Pointer Register in the Register File. Memory access is limited
+ to the current data segment of 64KB. To access another data segment in devices with more than 64KB data
+ space, the RAMPY in register in the I/O area has to be changed.
+ The Y-pointer Register can either be left unchanged by the operation, or it can be post-incremented or predecremented.
+ These features are especially suited for accessing arrays, tables, and Stack Pointer usage of the
+ Y-pointer Register. Note that only the low byte of the Y-pointer is updated in devices with no more than 256
+ bytes data space. For such devices, the high byte of the pointer is not used by this instruction and can be used
+ for other purposes. The RAMPY Register in the I/O area is updated in parts with more than 64KB data space or
+ more than 64KB Program memory, and the increment/decrement/displacement is added to the entire 24-bit
+ address on such devices.
+ Not all variants of this instruction is available in all devices. Refer to the device specific instruction set summary.
+ In the Reduced Core tinyAVR the LD instruction can be used to achieve the same operation as LPM since the
+ program memory is mapped to the data memory space.
+*/
+int avr_translate_LDY2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDY2_Rd(opcode)];
+ TCGv addr= gen_get_yaddr();
+
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ gen_set_yaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_LDY3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDY3_Rd(opcode)];
+ TCGv addr= gen_get_yaddr();
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+ gen_set_yaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_LDDY(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDDY_Rd(opcode)];
+ TCGv addr= gen_get_yaddr();
+
+ tcg_gen_addi_tl(addr, addr, (LDDY_hImm(opcode) << 5) | (LDDY_mImm(opcode) << 2) | LDDY_lImm(opcode));
+ /* addr = addr + q */
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Loads one byte indirect with or without displacement from the data space to a register. For parts with SRAM, the
+ data space consists of the Register File, I/O memory and internal SRAM (and external SRAM if applicable). For
+ parts without SRAM, the data space consists of the Register File only. In some parts the Flash Memory has
+ been mapped to the data space and can be read using this command. The EEPROM has a separate address
+ space.
+ The data location is pointed to by the Z (16 bits) Pointer Register in the Register File. Memory access is limited
+ to the current data segment of 64KB. To access another data segment in devices with more than 64KB data
+ space, the RAMPZ in register in the I/O area has to be changed.
+ The Z-pointer Register can either be left unchanged by the operation, or it can be post-incremented or predecremented.
+ These features are especially suited for Stack Pointer usage of the Z-pointer Register, however
+ because the Z-pointer Register can be used for indirect subroutine calls, indirect jumps and table lookup, it is
+ often more convenient to use the X or Y-pointer as a dedicated Stack Pointer. Note that only the low byte of the
+ Z-pointer is updated in devices with no more than 256 bytes data space. For such devices, the high byte of the
+ pointer is not used by this instruction and can be used for other purposes. The RAMPZ Register in the I/O area
+ is updated in parts with more than 64KB data space or more than 64KB Program memory, and the
+ increment/decrement/displacement is added to the entire 24-bit address on such devices.
+ Not all variants of this instruction is available in all devices. Refer to the device specific instruction set summary.
+ In the Reduced Core tinyAVR the LD instruction can be used to achieve the same operation as LPM since the
+ program memory is mapped to the data memory space.
+ For using the Z-pointer for table lookup in Program memory see the LPM and ELPM instructions.
+*/
+int avr_translate_LDZ2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDZ2_Rd(opcode)];
+ TCGv addr = gen_get_zaddr();
+
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ gen_set_zaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_LDZ3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDZ3_Rd(opcode)];
+ TCGv addr = gen_get_zaddr();
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ gen_set_zaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_LDDZ(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDDZ_Rd(opcode)];
+ TCGv addr = gen_get_zaddr();
+
+ tcg_gen_addi_tl(addr, addr, (LDDZ_hImm(opcode) << 5) | (LDDZ_mImm(opcode) << 2) | LDDZ_lImm(opcode));
+ /* addr = addr + q */
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Loads an 8 bit constant directly to register 16 to 31.
+*/
+int avr_translate_LDI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[16 + LDI_Rd(opcode)];
+ int imm = (LDI_hImm(opcode) << 4) | LDI_lImm(opcode);
+
+ tcg_gen_movi_tl(Rd, imm);
+
+ return BS_NONE;
+}
+
+/*
+ Loads one byte from the data space to a register. For parts with SRAM, the data space consists of the Register
+ File, I/O memory and internal SRAM (and external SRAM if applicable). For parts without SRAM, the data space
+ consists of the register file only. The EEPROM has a separate address space.
+ A 16-bit address must be supplied. Memory access is limited to the current data segment of 64KB. The LDS
+ instruction uses the RAMPD Register to access memory above 64KB. To access another data segment in
+ devices with more than 64KB data space, the RAMPD in register in the I/O area has to be changed.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_LDS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LDS_Rd(opcode)];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampD;
+
+ tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 16);
+ tcg_gen_ori_tl(addr, addr, LDS_Imm(opcode));
+
+ tcg_gen_qemu_ld8u(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Loads one byte pointed to by the Z-register into the destination register Rd. This instruction features a 100%
+ space effective constant initialization or constant data fetch. The Program memory is organized in 16-bit words
+ while the Z-pointer is a byte address. Thus, the least significant bit of the Z-pointer selects either low byte (ZLSB
+ = 0) or high byte (ZLSB = 1). This instruction can address the first 64KB (32K words) of Program memory. The Zpointer
+ Register can either be left unchanged by the operation, or it can be incremented. The incrementation
+ does not apply to the RAMPZ Register.
+ Devices with Self-Programming capability can use the LPM instruction to read the Fuse and Lock bit values.
+ Refer to the device documentation for a detailed description.
+ The LPM instruction is not available in all devices. Refer to the device specific instruction set summary
+*/
+int avr_translate_LPM1(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_LPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[0];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
+ tcg_gen_or_tl(addr, addr, L);
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* Rd = mem[addr] */
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_LPM2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_LPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[LPM2_Rd(opcode)];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
+ tcg_gen_or_tl(addr, addr, L);
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* Rd = mem[addr] */
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_LPMX(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_LPMX) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[LPMX_Rd(opcode)];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_r[31];
+ TCGv L = cpu_r[30];
+
+ tcg_gen_shli_tl(addr, H, 8); /* addr = H:L */
+ tcg_gen_or_tl(addr, addr, L);
+
+ tcg_gen_qemu_ld8u(Rd, addr, CODE_INDEX); /* Rd = mem[addr] */
+
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ tcg_gen_andi_tl(L, addr, 0xff);
+
+ tcg_gen_shri_tl(addr, addr, 8);
+ tcg_gen_andi_tl(H, addr, 0xff);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Shifts all bits in Rd one place to the right. Bit 7 is cleared. Bit 0 is loaded into the C Flag of the SREG. This
+ operation effectively divides an unsigned value by two. The C Flag can be used to round the result.
+*/
+int avr_translate_LSR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[LSR_Rd(opcode)];
+
+ tcg_gen_andi_tl(cpu_Cf, Rd, 1);
+
+ tcg_gen_shri_tl(Rd, Rd, 1);
+
+ gen_ZNSf(Rd);
+ tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf);
+ return BS_NONE;
+}
+
+/*
+ This instruction makes a copy of one register into another. The source register Rr is left unchanged, while the
+ destination register Rd is loaded with a copy of Rr.
+*/
+int avr_translate_MOV(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[MOV_Rd(opcode)];
+ TCGv Rr = cpu_r[(MOV_hRr(opcode) << 4) | (MOV_lRr(opcode))];
+
+ tcg_gen_mov_tl(Rd, Rr);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction makes a copy of one register pair into another register pair. The source register pair Rr+1:Rr is
+ left unchanged, while the destination register pair Rd+1:Rd is loaded with a copy of Rr + 1:Rr.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_MOVW(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MOVW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv RdL = cpu_r[MOVW_Rd(opcode) *2 + 0];
+ TCGv RdH = cpu_r[MOVW_Rd(opcode) *2 + 1];
+ TCGv RrL = cpu_r[MOVW_Rr(opcode) *2 + 0];
+ TCGv RrH = cpu_r[MOVW_Rr(opcode) *2 + 1];
+
+ tcg_gen_mov_tl(RdH, RrH);
+ tcg_gen_mov_tl(RdL, RrL);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction performs 8-bit x 8-bit -> 16-bit unsigned multiplication.
+*/
+int avr_translate_MUL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[MUL_Rd(opcode)];
+ TCGv Rr = cpu_r[(MUL_hRr(opcode) << 4) | MUL_lRr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd *Rr */
+
+ tcg_gen_mov_tl(R0, R);
+ tcg_gen_andi_tl(R0, R0, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_mov_tl(R1, R);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(16) */
+ tcg_gen_mov_tl(cpu_Zf, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction performs 8-bit x 8-bit -> 16-bit signed multiplication.
+*/
+int avr_translate_MULS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[16 + MULS_Rd(opcode)];
+ TCGv Rr = cpu_r[16 + MULS_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl(Rd, Rd); /* make Rd full 32 bit signed */
+ tcg_gen_ext8s_tl(Rr, Rr); /* make Rr full 32 bit signed */
+ tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd *Rr */
+
+ tcg_gen_mov_tl(R0, R);
+ tcg_gen_andi_tl(R0, R0, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_mov_tl(R1, R);
+ tcg_gen_andi_tl(R1, R0, 0xff);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 15); /* Cf = R(16) */
+ tcg_gen_mov_tl(cpu_Zf, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction performs 8-bit x 8-bit -> 16-bit multiplication of a signed and an unsigned number.
+*/
+int avr_translate_MULSU(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_MUL) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv R0 = cpu_r[0];
+ TCGv R1 = cpu_r[1];
+ TCGv Rd = cpu_r[16 + MULSU_Rd(opcode)];
+ TCGv Rr = cpu_r[16 + MULSU_Rr(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_ext8s_tl(Rd, Rd); /* make Rd full 32 bit signed */
+ tcg_gen_mul_tl(R, Rd, Rr); /* R = Rd *Rr */
+
+ tcg_gen_mov_tl(R0, R);
+ tcg_gen_andi_tl(R0, R0, 0xff);
+ tcg_gen_shri_tl(R, R, 8);
+ tcg_gen_mov_tl(R1, R);
+ tcg_gen_andi_tl(R1, R0, 0xff);
+
+ tcg_gen_shri_tl(cpu_Cf, R, 16); /* Cf = R(16) */
+ tcg_gen_mov_tl(cpu_Zf, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ Replaces the contents of register Rd with its two’s complement; the value $80 is left unchanged.
+*/
+int avr_translate_NEG(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[NEG_Rd(opcode)];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_neg_tl(R, Rd);
+
+ tcg_gen_setcondi_tl(TCG_COND_NE, cpu_Cf, R, 0x00); /* Cf = R != 0x00 */
+ tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_Vf, R, 0x80); /* Vf = R == 0x80 */
+ tcg_gen_not_tl(cpu_Hf, Rd); /* Hf = (~Rd | R)(3) */
+ tcg_gen_or_tl(cpu_Hf, cpu_Hf, R);
+ tcg_gen_shri_tl(cpu_Hf, cpu_Hf, 3);
+ tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1);
+ gen_ZNSf(R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction performs a single cycle No Operation.
+*/
+int avr_translate_NOP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+
+ /* NOP */
+
+ return BS_NONE;
+}
+
+/*
+ Performs the logical OR between the contents of register Rd and register Rr and places the result in the
+ destination register Rd.
+*/
+int avr_translate_OR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[OR_Rd(opcode)];
+ TCGv Rr = cpu_r[(OR_hRr(opcode) << 4) | (OR_lRr(opcode))];
+ TCGv R = tcg_temp_new_i32();
+
+ tcg_gen_or_tl(R, Rd, Rr);
+
+ tcg_gen_movi_tl(cpu_Vf, 0);
+ gen_ZNSf(R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ Performs the logical OR between the contents of register Rd and a constant and places the result in the
+ destination register Rd.
+*/
+int avr_translate_ORI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[ORI_Rd(opcode)];
+ int Imm = (ORI_hImm(opcode) << 4) | (ORI_lImm(opcode));
+
+ tcg_gen_ori_tl(Rd, Rd, Imm); /* Rd = Rd | Imm */
+
+ tcg_gen_movi_tl(cpu_Vf, 0x00); /* Vf = 0 */
+ gen_ZNSf(Rd);
+
+ return BS_NONE;
+}
+
+/*
+ Stores data from register Rr in the Register File to I/O Space (Ports, Timers, Configuration Registers, etc.). */
+int avr_translate_OUT(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[OUT_Rd(opcode)];
+ int Imm = (OUT_hImm(opcode) << 4) | OUT_lImm(opcode);
+ TCGv port= tcg_const_i32(Imm);
+ TCGv data= cpu_io[Imm];
+
+ tcg_gen_mov_tl(data, Rd);
+ gen_helper_outb(cpu_env, port, data);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction loads register Rd with a byte from the STACK. The Stack Pointer is pre-incremented by 1 before
+ the POP.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_POP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[POP_Rd(opcode)];
+
+ tcg_gen_addi_tl(cpu_sp, cpu_sp, 1);
+ tcg_gen_qemu_ld8u(
+ Rd, cpu_sp, DATA_INDEX);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction stores the contents of register Rr on the STACK. The Stack Pointer is post-decremented by 1
+ after the PUSH.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_PUSH(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[PUSH_Rd(opcode)];
+
+ tcg_gen_qemu_st8(
+ Rd, cpu_sp, DATA_INDEX);
+ tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
+
+ return BS_NONE;
+}
+
+/*
+ Relative call to an address within PC - 2K + 1 and PC + 2K (words). The return address (the instruction after the
+ RCALL) is stored onto the Stack. See also CALL. For AVR microcontrollers with Program memory not
+ exceeding 4K words (8KB) this instruction can address the entire memory from every address location. The
+ Stack Pointer uses a post-decrement scheme during RCALL.
+*/
+int avr_translate_RCALL(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ int ret = ctx->inst[0].npc;
+ int dst = ctx->inst[0].npc + sex(RCALL_Imm(opcode), 12);
+
+ gen_push_ret(env, ret);
+
+ gen_goto_tb(env, ctx, 0, dst);
+
+ return BS_BRANCH;
+}
+
+/*
+ Returns from subroutine. The return address is loaded from the STACK. The Stack Pointer uses a preincrement
+ scheme during RET.
+*/
+int avr_translate_RET(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ gen_pop_ret(env, cpu_pc);
+
+ tcg_gen_exit_tb(0);
+
+ return BS_BRANCH;
+}
+
+/*
+ Returns from interrupt. The return address is loaded from the STACK and the Global Interrupt Flag is set.
+ Note that the Status Register is not automatically stored when entering an interrupt routine, and it is not restored
+ when returning from an interrupt routine. This must be handled by the application program. The Stack Pointer
+ uses a pre-increment scheme during RETI.
+*/
+int avr_translate_RETI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ gen_pop_ret(env, cpu_pc);
+
+ tcg_gen_movi_tl(cpu_If, 1);
+
+ tcg_gen_exit_tb(0);
+
+ return BS_BRANCH;
+}
+
+/*
+ Relative jump to an address within PC - 2K +1 and PC + 2K (words). For AVR microcontrollers with Program
+ memory not exceeding 4K words (8KB) this instruction can address the entire memory from every address
+ location. See also JMP.
+*/
+int avr_translate_RJMP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ int dst = ctx->inst[0].npc + sex(RJMP_Imm(opcode), 12);
+
+ gen_goto_tb(env, ctx, 0, dst);
+
+ return BS_BRANCH;
+}
+
+/*
+ Shifts all bits in Rd one place to the right. The C Flag is shifted into bit 7 of Rd. Bit 0 is shifted into the C Flag.
+ This operation, combined with ASR, effectively divides multi-byte signed values by two. Combined with LSR it
+ effectively divides multi-byte unsigned values by two. The Carry Flag can be used to round the result.
+*/
+int avr_translate_ROR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[ROR_Rd(opcode)];
+ TCGv t0 = tcg_temp_new_i32();
+
+ tcg_gen_shli_tl(t0, cpu_Cf, 7);
+ tcg_gen_andi_tl(cpu_Cf, Rd, 0);
+ tcg_gen_shri_tl(Rd, Rd, 1);
+ tcg_gen_or_tl(Rd, Rd, t0);
+
+ gen_ZNSf(Rd);
+ tcg_gen_xor_tl(cpu_Vf, cpu_Nf, cpu_Cf);
+
+ tcg_temp_free_i32(t0);
+
+ return BS_NONE;
+}
+
+/*
+ Subtracts two registers and subtracts with the C Flag and places the result in the destination register Rd.
+*/
+int avr_translate_SBC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[SBC_Rd(opcode)];
+ TCGv Rr = cpu_r[(SBC_hRr(opcode) << 4) | (SBC_lRr(opcode))];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ 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 */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ SBCI – Subtract Immediate with Carry
+*/
+int avr_translate_SBCI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[SBCI_Rd(opcode)];
+ TCGv Rr = tcg_const_i32((SBCI_hImm(opcode) << 4) | SBCI_lImm(opcode));
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ 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 */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ Sets a specified bit in an I/O Register. This instruction operates on the lower 32 I/O Registers – addresses 0-31. */
+int avr_translate_SBI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv data = cpu_io[SBI_Imm(opcode)];
+ TCGv port = tcg_const_i32(SBI_Imm(opcode));
+
+ tcg_gen_ori_tl(data, data, 1 << SBI_Bit(opcode));
+ gen_helper_outb(cpu_env, port, data);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction tests a single bit in an I/O Register and skips the next instruction if the bit is cleared. This
+ instruction operates on the lower 32 I/O Registers – addresses 0-31. */
+int avr_translate_SBIC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv io = cpu_io[SBIC_Imm(opcode)];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGLabel *skip= gen_new_label();
+
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[1].npc); /* PC if next inst is skipped */
+ tcg_gen_andi_tl(t0, io, 1 << SBIC_Bit(opcode));
+ tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, skip);
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[0].npc); /* PC if next inst is not skipped */
+ gen_set_label(skip);
+
+ tcg_temp_free_i32(t0);
+
+ return BS_BRANCH;
+}
+
+/*
+ This instruction tests a single bit in an I/O Register and skips the next instruction if the bit is set. This instruction
+ operates on the lower 32 I/O Registers – addresses 0-31. */
+int avr_translate_SBIS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv io = cpu_io[SBIS_Imm(opcode)];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGLabel *skip= gen_new_label();
+
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[1].npc); /* PC if next inst is skipped */
+ tcg_gen_andi_tl(t0, io, 1 << SBIS_Bit(opcode));
+ tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, skip);
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[0].npc); /* PC if next inst is not skipped */
+ gen_set_label(skip);
+
+ tcg_temp_free_i32(t0);
+
+ return BS_BRANCH;
+}
+
+/*
+ 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.
+*/
+int avr_translate_SBIW(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_ADIW_SBIW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv RdL = cpu_r[24 + 2 * SBIW_Rd(opcode)];
+ TCGv RdH = cpu_r[25 + 2 * SBIW_Rd(opcode)];
+ int Imm = (SBIW_hImm(opcode) << 4) | (SBIW_lImm(opcode));
+ TCGv R = tcg_temp_new_i32();
+ TCGv Rd = tcg_temp_new_i32();
+ TCGv t0 = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_shli_tl(Rd, RdH, 8); /* R = ((H << 8) | L) - Imm */
+ tcg_gen_or_tl(Rd, RdL, Rd);
+ tcg_gen_subi_tl(R, Rd, Imm);
+ tcg_gen_andi_tl(R, R, 0xffff);/* make it 16 bits */
+
+ /* Cf */
+ tcg_gen_not_tl(t0, R); /* t0 = Rd & ~R */
+ tcg_gen_and_tl(t0, Rd, t0);
+ tcg_gen_shri_tl(cpu_Cf, t0, 15); /* Cf = t0(15) */
+
+ /* Vf */
+ tcg_gen_not_tl(t0, Rd); /* t0 = ~Rd & R */
+ tcg_gen_and_tl(t0, R, t0);
+
+ tcg_gen_shri_tl(cpu_Vf, t0, 15); /* Vf = t0(15) */
+
+ /* Zf */
+ tcg_gen_mov_tl(cpu_Zf, R); /* Zf = R */
+
+ /* Nf */
+ tcg_gen_shri_tl(cpu_Nf, R, 15); /* Nf = R(15) */
+
+ /* Sf */
+ tcg_gen_and_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf & Vf */
+
+ /* R */
+ tcg_gen_andi_tl(RdL, R, 0xff);
+ tcg_gen_shri_tl(RdH, R, 8);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(Rd);
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction tests a single bit in a register and skips the next instruction if the bit is cleared.
+*/
+int avr_translate_SBRC(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rr = cpu_r[SBRC_Rr(opcode)];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGLabel *skip= gen_new_label();
+
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[1].npc); /* PC if next inst is skipped */
+ tcg_gen_andi_tl(t0, Rr, 1 << SBRC_Bit(opcode));
+ tcg_gen_brcondi_i32(TCG_COND_EQ, t0, 0, skip);
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[0].npc); /* PC if next inst is not skipped */
+ gen_set_label(skip);
+
+ tcg_temp_free_i32(t0);
+
+ return BS_BRANCH;
+}
+
+/*
+ This instruction tests a single bit in a register and skips the next instruction if the bit is set.
+*/
+int avr_translate_SBRS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rr = cpu_r[SBRS_Rr(opcode)];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGLabel *skip= gen_new_label();
+
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[1].npc); /* PC if next inst is skipped */
+ tcg_gen_andi_tl(t0, Rr, 1 << SBRS_Bit(opcode));
+ tcg_gen_brcondi_i32(TCG_COND_NE, t0, 0, skip);
+ tcg_gen_movi_tl(cpu_pc, ctx->inst[0].npc); /* PC if next inst is not skipped */
+ gen_set_label(skip);
+
+ tcg_temp_free_i32(t0);
+
+ return BS_BRANCH;
+}
+
+/*
+ This instruction sets the circuit in sleep mode defined by the MCU Control Register.
+*/
+int avr_translate_SLEEP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ gen_helper_sleep(cpu_env);
+
+ return BS_EXCP;
+}
+
+/*
+ SPM can be used to erase a page in the Program memory, to write a page in the Program memory (that is
+ already erased), and to set Boot Loader Lock bits. In some devices, the Program memory can be written one
+ word at a time, in other devices an entire page can be programmed simultaneously after first filling a temporary
+ page buffer. In all cases, the Program memory must be erased one page at a time. When erasing the Program
+ memory, the RAMPZ and Z-register are used as page address. When writing the Program memory, the RAMPZ
+ and Z-register are used as page or word address, and the R1:R0 register pair is used as data(1). When setting
+ the Boot Loader Lock bits, the R1:R0 register pair is used as data. Refer to the device documentation for
+ detailed description of SPM usage. This instruction can address the entire Program memory.
+ The SPM instruction is not available in all devices. Refer to the device specific instruction set summary.
+ Note: 1. R1 determines the instruction high byte, and R0 determines the instruction low byte.
+*/
+int avr_translate_SPM(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_SPM) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ /* TODO: ??? */
+ return BS_NONE;
+}
+
+int avr_translate_SPMX(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_SPMX) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ /* TODO: ??? */
+ return BS_NONE;
+}
+
+int avr_translate_STX1(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STX1_Rr(opcode)];
+ TCGv addr= gen_get_xaddr();
+
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_STX2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STX2_Rr(opcode)];
+ TCGv addr= gen_get_xaddr();
+
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+ gen_set_xaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_STX3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STX3_Rr(opcode)];
+ TCGv addr= gen_get_xaddr();
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+ gen_set_xaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_STY2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STY2_Rd(opcode)];
+ TCGv addr= gen_get_yaddr();
+
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+ gen_set_yaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_STY3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STY3_Rd(opcode)];
+ TCGv addr= gen_get_yaddr();
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+ gen_set_yaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_STDY(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STDY_Rd(opcode)];
+ TCGv addr= gen_get_yaddr();
+
+ tcg_gen_addi_tl(addr, addr, (STDY_hImm(opcode) << 5) | (STDY_mImm(opcode) << 2) | STDY_lImm(opcode));
+ /* addr = addr + q */
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_STZ2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STZ2_Rd(opcode)];
+ TCGv addr = gen_get_zaddr();
+
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+ tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
+
+ gen_set_zaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_STZ3(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STZ3_Rd(opcode)];
+ TCGv addr = gen_get_zaddr();
+
+ tcg_gen_subi_tl(addr, addr, 1); /* addr = addr - 1 */
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ gen_set_zaddr(addr);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+int avr_translate_STDZ(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STDZ_Rd(opcode)];
+ TCGv addr = gen_get_zaddr();
+
+ tcg_gen_addi_tl(addr, addr, (STDZ_hImm(opcode) << 5) | (STDZ_mImm(opcode) << 2) | STDZ_lImm(opcode));
+ /* addr = addr + q */
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Stores one byte from a Register to the data space. For parts with SRAM, the data space consists of the Register
+ File, I/O memory and internal SRAM (and external SRAM if applicable). For parts without SRAM, the data space
+ consists of the Register File only. The EEPROM has a separate address space.
+ A 16-bit address must be supplied. Memory access is limited to the current data segment of 64KB. The STS
+ instruction uses the RAMPD Register to access memory above 64KB. To access another data segment in
+ devices with more than 64KB data space, the RAMPD in register in the I/O area has to be changed.
+ This instruction is not available in all devices. Refer to the device specific instruction set summary.
+*/
+int avr_translate_STS(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[STS_Rd(opcode)];
+ TCGv addr= tcg_temp_new_i32();
+ TCGv H = cpu_rampD;
+
+ tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
+ tcg_gen_shli_tl(addr, addr, 16);
+ tcg_gen_ori_tl(addr, addr, STS_Imm(opcode));
+
+ tcg_gen_qemu_st8(
+ Rd, addr, DATA_INDEX);
+
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
+/*
+ Subtracts two registers and places the result in the destination register Rd.
+*/
+int avr_translate_SUB(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[SUB_Rd(opcode)];
+ TCGv Rr = cpu_r[(SUB_hRr(opcode) << 4) | (SUB_lRr(opcode))];
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_sub_tl(R, Rd, Rr); /* R = Rd - Rr */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+
+ return BS_NONE;
+}
+
+/*
+ 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.
+*/
+int avr_translate_SUBI(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[SUBI_Rd(opcode)];
+ TCGv Rr = tcg_const_i32((SUBI_hImm(opcode) << 4) | SUBI_lImm(opcode));
+ TCGv R = tcg_temp_new_i32();
+
+ /* op */
+ tcg_gen_sub_tl(R, Rd, Rr);
+ /* R = Rd - Imm */
+ tcg_gen_andi_tl(R, R, 0xff); /* make it 8 bits */
+
+ gen_sub_CHf(R, Rd, Rr);
+ gen_sub_Vf(R, Rd, Rr);
+ gen_ZNSf(R);
+
+ /* R */
+ tcg_gen_mov_tl(Rd, R);
+
+ tcg_temp_free_i32(R);
+ tcg_temp_free_i32(Rr);
+
+ return BS_NONE;
+}
+
+/*
+ Swaps high and low nibbles in a register.
+*/
+int avr_translate_SWAP(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ TCGv Rd = cpu_r[SWAP_Rd(opcode)];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv t1 = tcg_temp_new_i32();
+
+ tcg_gen_andi_tl(t0, Rd, 0x0f);
+ tcg_gen_shli_tl(t0, t0, 4);
+ tcg_gen_andi_tl(t1, Rd, 0xf0);
+ tcg_gen_shri_tl(t1, t1, 4);
+ tcg_gen_or_tl(Rd, t0, t1);
+
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t0);
+
+ return BS_NONE;
+}
+
+/*
+ This instruction resets the Watchdog Timer. This instruction must be executed within a limited time given by the
+ WD prescaler. See the Watchdog Timer hardware specification.
+*/
+int avr_translate_WDR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+
+ gen_helper_wdr(cpu_env);
+
+ return BS_NONE;
+}
+
+/*
+ Exchanges one byte indirect between register and data space.
+ The data location is pointed to by the Z (16 bits) Pointer Register in the Register File. Memory access is limited
+ to the current data segment of 64KB. To access another data segment in devices with more than 64KB data
+ space, the RAMPZ in register in the I/O area has to be changed.
+ The Z-pointer Register is left unchanged by the operation. This instruction is especially suited for writing/reading
+ status bits stored in SRAM.
+*/
+int avr_translate_XCH(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
+{
+ if (avr_feature(env, AVR_FEATURE_RMW) == false) {
+ gen_helper_unsupported(cpu_env);
+
+ return BS_EXCP;
+ }
+
+ TCGv Rd = cpu_r[XCH_Rd(opcode)];
+ TCGv t0 = tcg_temp_new_i32();
+ TCGv addr = gen_get_zaddr();
+
+ tcg_gen_qemu_ld8u(
+ addr, t0, DATA_INDEX);
+ tcg_gen_qemu_st8(
+ addr, Rd, DATA_INDEX);
+ tcg_gen_mov_tl(Rd, t0);
+
+ tcg_temp_free_i32(t0);
+ tcg_temp_free_i32(addr);
+
+ return BS_NONE;
+}
+
diff --git a/target-avr/translate.h b/target-avr/translate.h
new file mode 100644
index 0000000..fa65406
--- /dev/null
+++ b/target-avr/translate.h
@@ -0,0 +1,123 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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/lgpl-2.1.html>
+ */
+
+#ifndef AVR_TRANSLATE_H_
+#define AVR_TRANSLATE_H_
+
+
+#include "qemu/osdep.h"
+
+#include "tcg/tcg.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
+#include "disas/disas.h"
+#include "tcg-op.h"
+#include "exec/cpu_ldst.h"
+
+#include "exec/helper-proto.h"
+#include "exec/helper-gen.h"
+#include "exec/log.h"
+#include "translate-inst.h"
+
+extern TCGv_env cpu_env;
+
+extern TCGv cpu_pc;
+
+extern TCGv cpu_Cf;
+extern TCGv cpu_Zf;
+extern TCGv cpu_Nf;
+extern TCGv cpu_Vf;
+extern TCGv cpu_Sf;
+extern TCGv cpu_Hf;
+extern TCGv cpu_Tf;
+extern TCGv cpu_If;
+
+extern TCGv cpu_rampD;
+extern TCGv cpu_rampX;
+extern TCGv cpu_rampY;
+extern TCGv cpu_rampZ;
+
+extern TCGv cpu_io[64];
+extern TCGv cpu_r[32];
+extern TCGv cpu_eind;
+extern TCGv cpu_sp;
+
+enum {
+ BS_NONE = 0, /* Nothing special (none of the below */
+ BS_STOP = 1, /* We want to stop translation for any reason */
+ BS_BRANCH = 2, /* A branch condition is reached */
+ BS_EXCP = 3, /* An exception condition is reached */
+};
+
+uint32_t get_opcode(uint8_t const *code, unsigned bitBase, unsigned bitSize);
+
+typedef struct DisasContext DisasContext;
+typedef struct InstInfo InstInfo;
+
+typedef int (*translate_function_t)(CPUAVRState *env, DisasContext *ctx, uint32_t opcode);
+struct InstInfo {
+ target_long cpc;
+ target_long npc;
+ uint32_t opcode;
+ translate_function_t translate;
+ unsigned length;
+};
+
+/*This is the state at translation time. */
+struct DisasContext {
+ struct TranslationBlock *tb;
+
+ InstInfo inst[2]; /* two consequitive instructions */
+
+ /*Routine used to access memory */
+ int memidx;
+ int bstate;
+ int singlestep;
+};
+
+uint32_t avr_decode(uint32_t pc, uint32_t *length, uint32_t opcode, translate_function_t *translate);
+
+static inline void gen_goto_tb(CPUAVRState *env,
+ DisasContext *ctx,
+ int n,
+ target_ulong dest)
+{
+ TranslationBlock *tb;
+
+ tb = ctx->tb;
+
+ if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)
+ && (ctx->singlestep == 0)) {
+ tcg_gen_goto_tb(n);
+ tcg_gen_movi_i32(cpu_pc, dest);
+ tcg_gen_exit_tb((uintptr_t)tb + n);
+ } else {
+ tcg_gen_movi_i32(cpu_pc, dest);
+
+ if (ctx->singlestep) {
+ gen_helper_debug(cpu_env);
+ }
+ tcg_gen_exit_tb(0);
+ }
+}
+
+
+#endif
+
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 09/10] target-avr: updating translate.c to use instructions translation
2016-06-02 20:03 [Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions Michael Rolnik
` (6 preceding siblings ...)
2016-06-02 20:04 ` [Qemu-devel] [PATCH 08/10] target-avr: adding instruction translation Michael Rolnik
@ 2016-06-02 20:04 ` Michael Rolnik
2016-06-02 20:04 ` [Qemu-devel] [PATCH 10/10] target-avr: fixing code style Michael Rolnik
8 siblings, 0 replies; 13+ messages in thread
From: Michael Rolnik @ 2016-06-02 20:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Rolnik, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/Makefile.objs | 4 +-
target-avr/translate.c | 148 ++++++++++++++++++++++-------------------------
2 files changed, 72 insertions(+), 80 deletions(-)
diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs
index c503546..8d06d54 100644
--- a/target-avr/Makefile.objs
+++ b/target-avr/Makefile.objs
@@ -1,3 +1,5 @@
-obj-y += translate.o cpu.o helper.o
+obj-y += translate.o helper.o cpu.o translate-inst.o
obj-y += gdbstub.o
obj-$(CONFIG_SOFTMMU) += machine.o
+
+obj-y += decode.o
diff --git a/target-avr/translate.c b/target-avr/translate.c
index e98aaef..0df0184 100644
--- a/target-avr/translate.c
+++ b/target-avr/translate.c
@@ -18,60 +18,31 @@
* <http://www.gnu.org/licenses/lgpl-2.1.html>
*/
-#include "qemu/osdep.h"
-
-#include "cpu.h"
-#include "exec/exec-all.h"
-#include "disas/disas.h"
-#include "tcg-op.h"
-#include "exec/cpu_ldst.h"
-
-#include "exec/helper-proto.h"
-#include "exec/helper-gen.h"
-#include "exec/log.h"
-
-typedef struct DisasContext DisasContext;
-typedef struct InstInfo InstInfo;
-
-/*This is the state at translation time. */
-struct DisasContext {
- struct TranslationBlock *tb;
-
- /*Routine used to access memory */
- int memidx;
- int bstate;
- int singlestep;
-};
-
-enum {
- BS_NONE = 0, /* Nothing special (none of the below */
- BS_STOP = 1, /* We want to stop translation for any reason */
- BS_BRANCH = 2, /* A branch condition is reached */
- BS_EXCP = 3, /* An exception condition is reached */
-};
-
-static TCGv_env cpu_env;
-
-static TCGv cpu_pc;
-
-static TCGv cpu_Cf;
-static TCGv cpu_Zf;
-static TCGv cpu_Nf;
-static TCGv cpu_Vf;
-static TCGv cpu_Sf;
-static TCGv cpu_Hf;
-static TCGv cpu_Tf;
-static TCGv cpu_If;
-
-static TCGv cpu_rampD;
-static TCGv cpu_rampX;
-static TCGv cpu_rampY;
-static TCGv cpu_rampZ;
-
-static TCGv cpu_io[64];
-static TCGv cpu_r[32];
-static TCGv cpu_eind;
-static TCGv cpu_sp;
+#include "translate.h"
+
+
+TCGv_env cpu_env;
+
+TCGv cpu_pc;
+
+TCGv cpu_Cf;
+TCGv cpu_Zf;
+TCGv cpu_Nf;
+TCGv cpu_Vf;
+TCGv cpu_Sf;
+TCGv cpu_Hf;
+TCGv cpu_Tf;
+TCGv cpu_If;
+
+TCGv cpu_rampD;
+TCGv cpu_rampX;
+TCGv cpu_rampY;
+TCGv cpu_rampZ;
+
+TCGv cpu_io[64];
+TCGv cpu_r[32];
+TCGv cpu_eind;
+TCGv cpu_sp;
#include "exec/gen-icount.h"
#define REG(x) (cpu_r[x])
@@ -120,30 +91,42 @@ void avr_translate_init(void)
done_init = 1;
}
-static inline void gen_goto_tb(CPUAVRState *env,
- DisasContext *ctx,
- int n,
- target_ulong dest)
+static void decode_opc(
+ AVRCPU *cpu,
+ DisasContext *ctx,
+ InstInfo *inst)
{
- TranslationBlock *tb;
+ CPUAVRState *env = &cpu->env;
- tb = ctx->tb;
+ inst->opcode = cpu_ldl_code(env, inst->cpc * 2); /* pc points to words */
+ inst->length = 16;
+ inst->translate = NULL;
- if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)
- && (ctx->singlestep == 0)) {
- tcg_gen_goto_tb(n);
- tcg_gen_movi_i32(cpu_pc, dest);
- tcg_gen_exit_tb((uintptr_t)tb + n);
- } else {
- tcg_gen_movi_i32(cpu_pc, dest);
+ /* the following function looks onto the opcode as a string of bytes */
+ avr_decode(inst->cpc, &inst->length, inst->opcode, &inst->translate);
- if (ctx->singlestep) {
- gen_helper_debug(cpu_env);
- }
- tcg_gen_exit_tb(0);
+ if (inst->length == 16) {
+ inst->npc = inst->cpc + 1;
+ /* get opcode as 16bit value */
+ inst->opcode = inst->opcode & 0x0000ffff;
+ }
+ if (inst->length == 32) {
+ inst->npc = inst->cpc + 2;
+ /* get opcode as 32bit value */
+ inst->opcode = (inst->opcode << 16)
+ | (inst->opcode >> 16);
}
}
+uint32_t get_opcode(
+ uint8_t const *code,
+ unsigned bitBase,
+ unsigned bitSize)
+{
+ return *(uint16_t *)code;
+}
+
+
/*generate intermediate code for basic block 'tb'. */
void gen_intermediate_code(
CPUAVRState *env,
@@ -176,18 +159,21 @@ void gen_intermediate_code(
gen_tb_start(tb);
/* decode first instruction */
- cpc = pc_start;
- npc = cpc + 1;
+ ctx.inst[0].cpc = pc_start;
+ decode_opc(cpu, &ctx, &ctx.inst[0]);
do {
- /* translate current instruction */
+ /* set curr/next PCs */
+ cpc = ctx.inst[0].cpc;
+ npc = ctx.inst[0].npc;
+
+ /* decode next instruction */
+ ctx.inst[1].cpc = ctx.inst[0].npc;
+ decode_opc(cpu, &ctx, &ctx.inst[1]);
+
+ /* translate current instruction */
tcg_gen_insn_start(cpc);
num_insns++;
- /* just skip to next instruction */
- cpc++;
- npc++;
- ctx.bstate = BS_NONE;
-
if (unlikely(cpu_breakpoint_test(cs, cpc * 2, BP_ANY))) {
tcg_gen_movi_i32(cpu_pc, cpc);
gen_helper_debug(cpu_env);
@@ -199,6 +185,8 @@ void gen_intermediate_code(
goto done_generating;
}
+ ctx.bstate = ctx.inst[0].translate(env, &ctx, ctx.inst[0].opcode);
+
if (num_insns >= max_insns) {
break; /* max translated instructions limit reached */
}
@@ -208,6 +196,8 @@ void gen_intermediate_code(
if ((cpc & (TARGET_PAGE_SIZE - 1)) == 0) {
break; /* page boundary */
}
+
+ ctx.inst[0] = ctx.inst[1]; /* make next inst curr */
} while (ctx.bstate == BS_NONE && !tcg_op_buf_full());
if (tb->cflags & CF_LAST_IO) {
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 10/10] target-avr: fixing code style
2016-06-02 20:03 [Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions Michael Rolnik
` (7 preceding siblings ...)
2016-06-02 20:04 ` [Qemu-devel] [PATCH 09/10] target-avr: updating translate.c to use instructions translation Michael Rolnik
@ 2016-06-02 20:04 ` Michael Rolnik
8 siblings, 0 replies; 13+ messages in thread
From: Michael Rolnik @ 2016-06-02 20:04 UTC (permalink / raw)
To: qemu-devel; +Cc: Michael Rolnik, Michael Rolnik
Signed-off-by: Michael Rolnik <mrolnik@gmail.com>
---
target-avr/cpu-qom.h | 38 +++++------------
target-avr/cpu.c | 100 +++++++++++++-------------------------------
target-avr/cpu.h | 74 ++++++++------------------------
target-avr/gdbstub.c | 10 +----
target-avr/helper.c | 52 ++++++-----------------
target-avr/translate-inst.c | 54 +++++++++++++++---------
target-avr/translate-inst.h | 20 +++++++++
target-avr/translate.c | 27 +++---------
target-avr/translate.h | 5 +--
9 files changed, 134 insertions(+), 246 deletions(-)
diff --git a/target-avr/cpu-qom.h b/target-avr/cpu-qom.h
index 76ca908..bb0fbd7 100644
--- a/target-avr/cpu-qom.h
+++ b/target-avr/cpu-qom.h
@@ -25,9 +25,9 @@
#define TYPE_AVR_CPU "avr"
-#define AVR_CPU_CLASS(klass) OBJECT_CLASS_CHECK(AVRCPUClass, (klass), TYPE_AVR_CPU)
-#define AVR_CPU(obj) OBJECT_CHECK(AVRCPU, (obj), TYPE_AVR_CPU)
-#define AVR_CPU_GET_CLASS(obj) OBJECT_GET_CLASS(AVRCPUClass, (obj), TYPE_AVR_CPU)
+#define AVR_CPU_CLASS(klass) OBJECT_CLASS_CHECK(AVRCPUClass, (klass), TYPE_AVR_CPU)
+#define AVR_CPU(obj) OBJECT_CHECK(AVRCPU, (obj), TYPE_AVR_CPU)
+#define AVR_CPU_GET_CLASS(obj) OBJECT_GET_CLASS(AVRCPUClass, (obj), TYPE_AVR_CPU)
/**
* AVRCPUClass:
@@ -58,40 +58,24 @@ typedef struct AVRCPU {
CPUAVRState env;
} AVRCPU;
-static inline AVRCPU *avr_env_get_cpu(CPUAVRState *env)
+static inline AVRCPU *avr_env_get_cpu(CPUAVRState *env)
{
return container_of(env, AVRCPU, env);
}
-#define ENV_GET_CPU(e) CPU(avr_env_get_cpu(e))
+#define ENV_GET_CPU(e) CPU(avr_env_get_cpu(e))
#define ENV_OFFSET offsetof(AVRCPU, env)
#ifndef CONFIG_USER_ONLY
extern const struct VMStateDescription vmstate_avr_cpu;
#endif
-void avr_cpu_do_interrupt(
- CPUState *cpu);
-bool avr_cpu_exec_interrupt(
- CPUState *cpu,
- int int_req);
-void avr_cpu_dump_state(
- CPUState *cs,
- FILE *f,
- fprintf_function cpu_fprintf,
- int flags);
+void avr_cpu_do_interrupt(CPUState *cpu);
+bool avr_cpu_exec_interrupt(CPUState *cpu, int int_req);
+void avr_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, int flags);
-hwaddr avr_cpu_get_phys_page_debug(
- CPUState *cpu,
- vaddr addr);
-
-int avr_cpu_gdb_read_register(
- CPUState *cpu,
- uint8_t *buf,
- int reg);
-int avr_cpu_gdb_write_register(
- CPUState *cpu,
- uint8_t *buf,
- int reg);
+hwaddr avr_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+int avr_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
+int avr_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
#endif
diff --git a/target-avr/cpu.c b/target-avr/cpu.c
index 9be0a1d..3c7fa07 100644
--- a/target-avr/cpu.c
+++ b/target-avr/cpu.c
@@ -25,17 +25,14 @@
#include "migration/vmstate.h"
#include "machine.h"
-static void avr_cpu_set_pc(
- CPUState *cs,
- vaddr value)
+static void avr_cpu_set_pc(CPUState *cs, vaddr value)
{
AVRCPU *cpu = AVR_CPU(cs);
cpu->env.pc = value / 2; /* internally PC points to words */
}
-static bool avr_cpu_has_work(
- CPUState *cs)
+static bool avr_cpu_has_work(CPUState *cs)
{
AVRCPU *cpu = AVR_CPU(cs);
CPUAVRState *env = &cpu->env;
@@ -45,9 +42,7 @@ static bool avr_cpu_has_work(
| CPU_INTERRUPT_RESET))
&& cpu_interrupts_enabled(env);
}
-static void avr_cpu_synchronize_from_tb(
- CPUState *cs,
- TranslationBlock *tb)
+static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *tb)
{
AVRCPU *cpu = AVR_CPU(cs);
CPUAVRState *env = &cpu->env;
@@ -55,8 +50,7 @@ static void avr_cpu_synchronize_from_tb(
env->pc = tb->pc / 2; /* internally PC points to words */
}
-static void avr_cpu_reset(
- CPUState *s)
+static void avr_cpu_reset(CPUState *s)
{
AVRCPU *cpu = AVR_CPU(s);
AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu);
@@ -73,17 +67,13 @@ static void avr_cpu_reset(
tlb_flush(s, 1);
}
-static void avr_cpu_disas_set_info(
- CPUState *cpu,
- disassemble_info *info)
+static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
{
info->mach = bfd_arch_avr;
info->print_insn = print_insn_avr;
}
-static void avr_cpu_realizefn(
- DeviceState *dev,
- Error **errp)
+static void avr_cpu_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev);
@@ -94,10 +84,7 @@ static void avr_cpu_realizefn(
mcc->parent_realize(dev, errp);
}
-static void avr_cpu_set_int(
- void *opaque,
- int irq,
- int level)
+static void avr_cpu_set_int(void *opaque, int irq, int level)
{
AVRCPU *cpu = opaque;
CPUAVRState *env = &cpu->env;
@@ -115,8 +102,7 @@ static void avr_cpu_set_int(
}
}
-static void avr_cpu_initfn(
- Object *obj)
+static void avr_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
AVRCPU *cpu = AVR_CPU(obj);
@@ -135,8 +121,7 @@ static void avr_cpu_initfn(
}
}
-static ObjectClass *avr_cpu_class_by_name(
- const char *cpu_model)
+static ObjectClass *avr_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
char *typename;
@@ -162,9 +147,7 @@ static ObjectClass *avr_cpu_class_by_name(
return oc;
}
-static void avr_cpu_class_init(
- ObjectClass *oc,
- void *data)
+static void avr_cpu_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
CPUClass *cc = CPU_CLASS(oc);
@@ -208,8 +191,7 @@ static void avr_cpu_class_init(
= true;
}
-static void avr_avr1_initfn(
- Object *obj)
+static void avr_avr1_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -218,8 +200,7 @@ static void avr_avr1_initfn(
avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
avr_set_feature(env, AVR_FEATURE_2_BYTE_PC);
}
-static void avr_avr2_initfn(
- Object *obj)
+static void avr_avr2_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -234,8 +215,7 @@ static void avr_avr2_initfn(
avr_set_feature(env, AVR_FEATURE_2_BYTE_SP);
}
-static void avr_avr25_initfn(
- Object *obj)
+static void avr_avr25_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -252,8 +232,7 @@ static void avr_avr25_initfn(
avr_set_feature(env, AVR_FEATURE_MOVW);
}
-static void avr_avr3_initfn(
- Object *obj)
+static void avr_avr3_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -269,8 +248,7 @@ static void avr_avr3_initfn(
avr_set_feature(env, AVR_FEATURE_JMP_CALL);
}
-static void avr_avr31_initfn(
- Object *obj)
+static void avr_avr31_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -288,8 +266,7 @@ static void avr_avr31_initfn(
avr_set_feature(env, AVR_FEATURE_JMP_CALL);
}
-static void avr_avr35_initfn(
- Object *obj)
+static void avr_avr35_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -307,8 +284,7 @@ static void avr_avr35_initfn(
avr_set_feature(env, AVR_FEATURE_MOVW);
}
-static void avr_avr4_initfn(
- Object *obj)
+static void avr_avr4_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -326,8 +302,7 @@ static void avr_avr4_initfn(
avr_set_feature(env, AVR_FEATURE_MUL);
}
-static void avr_avr5_initfn(
- Object *obj)
+static void avr_avr5_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -346,8 +321,7 @@ static void avr_avr5_initfn(
avr_set_feature(env, AVR_FEATURE_MUL);
}
-static void avr_avr51_initfn(
- Object *obj)
+static void avr_avr51_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -368,8 +342,7 @@ static void avr_avr51_initfn(
avr_set_feature(env, AVR_FEATURE_MOVW);
avr_set_feature(env, AVR_FEATURE_MUL);
}
-static void avr_avr6_initfn(
- Object *obj)
+static void avr_avr6_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -391,8 +364,7 @@ static void avr_avr6_initfn(
avr_set_feature(env, AVR_FEATURE_MOVW);
avr_set_feature(env, AVR_FEATURE_MUL);
}
-static void avr_xmega2_initfn(
- Object *obj)
+static void avr_xmega2_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -411,8 +383,7 @@ static void avr_xmega2_initfn(
avr_set_feature(env, AVR_FEATURE_MUL);
avr_set_feature(env, AVR_FEATURE_RMW);
}
-static void avr_xmega4_initfn(
- Object *obj)
+static void avr_xmega4_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -434,8 +405,7 @@ static void avr_xmega4_initfn(
avr_set_feature(env, AVR_FEATURE_MUL);
avr_set_feature(env, AVR_FEATURE_RMW);
}
-static void avr_xmega5_initfn(
- Object *obj)
+static void avr_xmega5_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -461,8 +431,7 @@ static void avr_xmega5_initfn(
avr_set_feature(env, AVR_FEATURE_RMW);
}
-static void avr_xmega6_initfn(
- Object *obj)
+static void avr_xmega6_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -485,8 +454,7 @@ static void avr_xmega6_initfn(
avr_set_feature(env, AVR_FEATURE_MUL);
avr_set_feature(env, AVR_FEATURE_RMW);
}
-static void avr_xmega7_initfn(
- Object *obj)
+static void avr_xmega7_initfn(Object *obj)
{
AVRCPU *cpu = AVR_CPU(obj);
CPUAVRState *env = &cpu->env;
@@ -513,8 +481,7 @@ static void avr_xmega7_initfn(
avr_set_feature(env, AVR_FEATURE_RMW);
}
-static void avr_any_initfn(
- Object *obj)
+static void avr_any_initfn(Object *obj)
{
/* Set cpu feature flags */
}
@@ -543,9 +510,7 @@ static const AVRCPUInfo avr_cpus[] = {
{ .name = "any", .initfn = avr_any_initfn },
};
-static gint avr_cpu_list_compare(
- gconstpointer a,
- gconstpointer b)
+static gint avr_cpu_list_compare(gconstpointer a, gconstpointer b)
{
ObjectClass *class_a = (ObjectClass *)a;
ObjectClass *class_b = (ObjectClass *)b;
@@ -563,9 +528,7 @@ static gint avr_cpu_list_compare(
}
}
-static void avr_cpu_list_entry(
- gpointer data,
- gpointer user_data)
+static void avr_cpu_list_entry(gpointer data, gpointer user_data)
{
ObjectClass *oc = data;
CPUListState *s = user_data;
@@ -578,9 +541,7 @@ static void avr_cpu_list_entry(
g_free(name);
}
-void avr_cpu_list(
- FILE *f,
- fprintf_function cpu_fprintf)
+void avr_cpu_list(FILE *f, fprintf_function cpu_fprintf)
{
CPUListState s = {
.file = f,
@@ -594,8 +555,7 @@ void avr_cpu_list(
g_slist_foreach(list, avr_cpu_list_entry, &s);
g_slist_free(list);
}
-AVRCPU *cpu_avr_init(
- const char *cpu_model)
+AVRCPU *cpu_avr_init(const char *cpu_model)
{
return AVR_CPU(cpu_generic_init(TYPE_AVR_CPU, cpu_model));
}
diff --git a/target-avr/cpu.h b/target-avr/cpu.h
index 2b67e89..e8985c9 100644
--- a/target-avr/cpu.h
+++ b/target-avr/cpu.h
@@ -41,7 +41,7 @@
#define DATA_INDEX 1
#define EXCP_RESET 1
-#define EXCP_INT(n) (EXCP_RESET + (n) + 1)
+#define EXCP_INT(n) (EXCP_RESET + (n) + 1)
#define PHYS_ADDR_MASK 0xfff00000
#define PHYS_CODE_BASE 0x00000000
@@ -117,25 +117,15 @@ struct CPUAVRState {
CPU_COMMON
};
-static inline int avr_feature(
- CPUAVRState *env,
- int feature)
+static inline int avr_feature(CPUAVRState *env, int feature)
{
return (env->features & (1UL << feature)) != 0;
}
-static inline void avr_set_feature(
- CPUAVRState *env,
- int feature)
+static inline void avr_set_feature(CPUAVRState *env, int feature)
{
env->features |= (1Ul << feature);
}
-static inline void avr_del_feature(
- CPUAVRState *env,
- int feature)
-{
- env->features &= ~(1Ul << feature);
-}
#define cpu_list avr_cpu_list
#define cpu_exec cpu_avr_exec
@@ -144,64 +134,34 @@ static inline void avr_del_feature(
#include "exec/cpu-all.h"
#include "cpu-qom.h"
-static inline int cpu_mmu_index(
- CPUAVRState *env,
- bool ifetch)
+static inline int cpu_mmu_index(CPUAVRState *env, bool ifetch)
{
return 0;
}
-void avr_translate_init(void);
-
-AVRCPU *cpu_avr_init(
- const char *cpu_model);
-
-#define cpu_init(cpu_model) CPU(cpu_avr_init(cpu_model))
-
-void avr_cpu_list(
- FILE *f,
- fprintf_function cpu_fprintf);
-int cpu_avr_exec(
- CPUState *cpu);
-int cpu_avr_signal_handler(
- int host_signum,
- void *pinfo,
- void *puc);
-int avr_cpu_handle_mmu_fault(
- CPUState *cpu,
- vaddr address,
- int rw,
- int mmu_idx);
-int avr_cpu_memory_rw_debug(
- CPUState *cs,
- vaddr address,
- uint8_t *buf,
- int len,
- bool is_write);
+void avr_translate_init(void);
+
+AVRCPU *cpu_avr_init(const char *cpu_model);
+#define cpu_init(cpu_model) CPU (cpu_avr_init(cpu_model))
+
+void avr_cpu_list(FILE *f, fprintf_function cpu_fprintf);
+int cpu_avr_exec(CPUState *cpu);
+int cpu_avr_signal_handler(int host_signum, void *pinfo, void *puc);
+int avr_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, int mmu_idx);
+int avr_cpu_memory_rw_debug(CPUState *cs, vaddr address, uint8_t *buf, int len, bool is_write);
#ifndef CONFIG_USER_ONLY
-QEMU_NORETURN void avr_cpu_unassigned_access(
- CPUState *cpu,
- hwaddr addr,
- bool is_write,
- bool is_exec,
- int unused,
- unsigned size);
+QEMU_NORETURN void avr_cpu_unassigned_access(CPUState *cpu, hwaddr addr, bool is_write, bool is_exec, int unused, unsigned size);
#endif
-static inline void cpu_get_tb_cpu_state(
- CPUAVRState *env,
- target_ulong *pc,
- target_ulong *cs_base,
- uint32_t *pflags)
+static inline void cpu_get_tb_cpu_state(CPUAVRState *env, target_ulong *pc, target_ulong *cs_base, uint32_t *pflags)
{
*pc = env->pc * 2;
*cs_base = 0;
*pflags = 0;
}
-static inline int cpu_interrupts_enabled(
- CPUAVRState *env1)
+static inline int cpu_interrupts_enabled(CPUAVRState *env1)
{
return env1->sregI != 0;
}
diff --git a/target-avr/gdbstub.c b/target-avr/gdbstub.c
index 5923f49..85a9f0d 100644
--- a/target-avr/gdbstub.c
+++ b/target-avr/gdbstub.c
@@ -22,10 +22,7 @@
#include "qemu-common.h"
#include "exec/gdbstub.h"
-int avr_cpu_gdb_read_register(
- CPUState *cs,
- uint8_t *mem_buf,
- int n)
+int avr_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
{
AVRCPU *cpu = AVR_CPU(cs);
CPUAVRState *env = &cpu->env;
@@ -63,10 +60,7 @@ int avr_cpu_gdb_read_register(
return 0;
}
-int avr_cpu_gdb_write_register(
- CPUState *cs,
- uint8_t *mem_buf,
- int n)
+int avr_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
{
AVRCPU *cpu = AVR_CPU(cs);
CPUAVRState *env = &cpu->env;
diff --git a/target-avr/helper.c b/target-avr/helper.c
index 450f598..ec683b6 100644
--- a/target-avr/helper.c
+++ b/target-avr/helper.c
@@ -29,9 +29,7 @@
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
-bool avr_cpu_exec_interrupt(
- CPUState *cs,
- int interrupt_request)
+bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
{
CPUClass *cc = CPU_GET_CLASS(cs);
AVRCPU *cpu = AVR_CPU(cs);
@@ -64,8 +62,7 @@ bool avr_cpu_exec_interrupt(
return ret;
}
-void avr_cpu_do_interrupt(
- CPUState *cs)
+void avr_cpu_do_interrupt(CPUState *cs)
{
AVRCPU *cpu = AVR_CPU(cs);
CPUAVRState *env = &cpu->env;
@@ -103,40 +100,24 @@ void avr_cpu_do_interrupt(
cs->exception_index = -1;
}
-int avr_cpu_memory_rw_debug(
- CPUState *cs,
- vaddr addr,
- uint8_t *buf,
- int len,
- bool is_write)
+int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, int len, bool is_write)
{
return cpu_memory_rw_debug(cs, addr, buf, len, is_write);
}
-hwaddr avr_cpu_get_phys_page_debug(
- CPUState *cs,
- vaddr addr)
+hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
{
return addr; /* I assume 1:1 address correspondance */
}
-int avr_cpu_handle_mmu_fault(
- CPUState *cs,
- vaddr address,
- int rw,
- int mmu_idx)
+int avr_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, int mmu_idx)
{
cs->exception_index = EXCP_DEBUG;
cpu_dump_state(cs, stderr, fprintf, 0);
return 1;
}
-void tlb_fill(
- CPUState *cs,
- target_ulong vaddr,
- int is_write,
- int mmu_idx,
- uintptr_t retaddr)
+void tlb_fill(CPUState *cs, target_ulong vaddr, int is_write, int mmu_idx, uintptr_t retaddr)
{
target_ulong page_size = TARGET_PAGE_SIZE;
int prot = 0;
@@ -155,16 +136,14 @@ void tlb_fill(
tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size);
}
-void helper_sleep(
- CPUAVRState *env)
+void helper_sleep(CPUAVRState *env)
{
CPUState *cs = CPU(avr_env_get_cpu(env));
cs->exception_index = EXCP_HLT;
cpu_loop_exit(cs);
}
-void helper_unsupported(
- CPUAVRState *env)
+void helper_unsupported(CPUAVRState *env)
{
CPUState *cs = CPU(avr_env_get_cpu(env));
@@ -173,8 +152,7 @@ void helper_unsupported(
cpu_loop_exit(cs);
}
-void helper_debug(
- CPUAVRState *env)
+void helper_debug(CPUAVRState *env)
{
CPUState *cs = CPU(avr_env_get_cpu(env));
@@ -182,8 +160,7 @@ void helper_debug(
cpu_loop_exit(cs);
}
-void helper_wdr(
- CPUAVRState *env)
+void helper_wdr(CPUAVRState *env)
{
CPUState *cs = CPU(avr_env_get_cpu(env));
@@ -191,9 +168,7 @@ void helper_wdr(
cpu_loop_exit(cs);
}
-target_ulong helper_inb(
- CPUAVRState *env,
- uint32_t port)
+target_ulong helper_inb(CPUAVRState *env, uint32_t port)
{
printf("in: io[%02x]\n", port);
@@ -223,10 +198,7 @@ target_ulong helper_inb(
return 0;
}
-void helper_outb(
- CPUAVRState *env,
- uint32_t port,
- uint32_t data)
+void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data)
{
printf("out:%02x -> io[%02x]\n", data, port);
diff --git a/target-avr/translate-inst.c b/target-avr/translate-inst.c
index fe9d9fc..c9b28aa 100644
--- a/target-avr/translate-inst.c
+++ b/target-avr/translate-inst.c
@@ -36,8 +36,8 @@ void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr);
void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr);
void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr);
void gen_ZNSf(TCGv R);
-void gen_push_ret(CPUAVRState *env, int ret);
-void gen_pop_ret(CPUAVRState *env, TCGv ret);
+void gen_push_ret(CPUAVRState *env, int ret);
+void gen_pop_ret(CPUAVRState *env, TCGv ret);
void gen_jmp_ez(void);
void gen_jmp_z(void);
@@ -75,7 +75,7 @@ void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr)
tcg_temp_free_i32(t1);
}
-void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
+void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
{
TCGv t1 = tcg_temp_new_i32();
TCGv t2 = tcg_temp_new_i32();
@@ -97,7 +97,7 @@ void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr)
tcg_temp_free_i32(t1);
}
-void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
+void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
{
TCGv t1 = tcg_temp_new_i32();
TCGv t2 = tcg_temp_new_i32();
@@ -118,7 +118,7 @@ void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr)
tcg_temp_free_i32(t1);
}
-void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
+void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr)
{
TCGv t1 = tcg_temp_new_i32();
TCGv t2 = tcg_temp_new_i32();
@@ -144,7 +144,7 @@ void gen_ZNSf(TCGv R)
tcg_gen_and_tl(cpu_Sf, cpu_Nf, cpu_Vf);/* Sf = Nf & Vf */
}
-void gen_push_ret(CPUAVRState *env, int ret)
+void gen_push_ret(CPUAVRState *env, int ret)
{
tcg_gen_qemu_st8(tcg_const_local_i32((ret & 0x0000ff)), cpu_sp, DATA_INDEX);
tcg_gen_subi_tl(cpu_sp, cpu_sp, 1);
@@ -161,7 +161,7 @@ void gen_push_ret(CPUAVRState *env, int ret)
}
}
-void gen_pop_ret(CPUAVRState *env, TCGv ret)
+void gen_pop_ret(CPUAVRState *env, TCGv ret)
{
TCGv t0 = tcg_const_i32(0);
TCGv t1 = tcg_const_i32(0);
@@ -239,7 +239,7 @@ void gen_set_zaddr(TCGv addr)
TCGv gen_get_addr(TCGv H, TCGv M, TCGv L)
{
- TCGv addr= tcg_temp_new_i32();
+ TCGv addr = tcg_temp_new_i32();
tcg_gen_mov_tl(addr, H); /* addr = H:M:L */
tcg_gen_shli_tl(addr, addr, 8);
@@ -466,15 +466,31 @@ int avr_translate_ASR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
*/
int avr_translate_BCLR(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
{
- switch(BCLR_Bit(opcode)) {
- case 0x00: tcg_gen_movi_tl(cpu_Cf, 0x00); break;
- case 0x01: tcg_gen_movi_tl(cpu_Zf, 0x01); break;
- case 0x02: tcg_gen_movi_tl(cpu_Nf, 0x00); break;
- case 0x03: tcg_gen_movi_tl(cpu_Vf, 0x00); break;
- case 0x04: tcg_gen_movi_tl(cpu_Sf, 0x00); break;
- case 0x05: tcg_gen_movi_tl(cpu_Hf, 0x00); break;
- case 0x06: tcg_gen_movi_tl(cpu_Tf, 0x00); break;
- case 0x07: tcg_gen_movi_tl(cpu_If, 0x00); break;
+ switch (BCLR_Bit(opcode)) {
+ case 0x00:
+ tcg_gen_movi_tl(cpu_Cf, 0x00);
+ break;
+ case 0x01:
+ tcg_gen_movi_tl(cpu_Zf, 0x01);
+ break;
+ case 0x02:
+ tcg_gen_movi_tl(cpu_Nf, 0x00);
+ break;
+ case 0x03:
+ tcg_gen_movi_tl(cpu_Vf, 0x00);
+ break;
+ case 0x04:
+ tcg_gen_movi_tl(cpu_Sf, 0x00);
+ break;
+ case 0x05:
+ tcg_gen_movi_tl(cpu_Hf, 0x00);
+ break;
+ case 0x06:
+ tcg_gen_movi_tl(cpu_Tf, 0x00);
+ break;
+ case 0x07:
+ tcg_gen_movi_tl(cpu_If, 0x00);
+ break;
}
return BS_NONE;
@@ -1269,7 +1285,7 @@ int avr_translate_LDX2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
tcg_gen_qemu_ld8u(
Rd, addr, DATA_INDEX);
tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
-
+
gen_set_xaddr(addr);
tcg_temp_free_i32(addr);
@@ -2257,7 +2273,7 @@ int avr_translate_STZ2(CPUAVRState *env, DisasContext *ctx, uint32_t opcode)
tcg_gen_qemu_st8(
Rd, addr, DATA_INDEX);
tcg_gen_addi_tl(addr, addr, 1); /* addr = addr + 1 */
-
+
gen_set_zaddr(addr);
tcg_temp_free_i32(addr);
diff --git a/target-avr/translate-inst.h b/target-avr/translate-inst.h
index 6bd180d..106f5f4 100644
--- a/target-avr/translate-inst.h
+++ b/target-avr/translate-inst.h
@@ -1,3 +1,23 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2016 Michael Rolnik
+ *
+ * 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/lgpl-2.1.html>
+ */
+
#ifndef AVR_TRANSLATE_INST_H_
#define AVR_TRANSLATE_INST_H_
diff --git a/target-avr/translate.c b/target-avr/translate.c
index 0df0184..5b0363a 100644
--- a/target-avr/translate.c
+++ b/target-avr/translate.c
@@ -47,7 +47,7 @@ TCGv cpu_sp;
#include "exec/gen-icount.h"
#define REG(x) (cpu_r[x])
-void avr_translate_init(void)
+void avr_translate_init(void)
{
int i;
static int done_init;
@@ -91,10 +91,7 @@ void avr_translate_init(void)
done_init = 1;
}
-static void decode_opc(
- AVRCPU *cpu,
- DisasContext *ctx,
- InstInfo *inst)
+static void decode_opc(AVRCPU *cpu, DisasContext *ctx, InstInfo *inst)
{
CPUAVRState *env = &cpu->env;
@@ -118,19 +115,14 @@ static void decode_opc(
}
}
-uint32_t get_opcode(
- uint8_t const *code,
- unsigned bitBase,
- unsigned bitSize)
+uint32_t get_opcode(uint8_t const *code, unsigned bitBase, unsigned bitSize)
{
return *(uint16_t *)code;
}
/*generate intermediate code for basic block 'tb'. */
-void gen_intermediate_code(
- CPUAVRState *env,
- struct TranslationBlock *tb)
+void gen_intermediate_code(CPUAVRState *env, struct TranslationBlock *tb)
{
AVRCPU *cpu = avr_env_get_cpu(env);
CPUState *cs = CPU(cpu);
@@ -231,19 +223,12 @@ done_generating:
tb->icount = num_insns;
}
-void restore_state_to_opc(
- CPUAVRState *env,
- TranslationBlock *tb,
- target_ulong *data)
+void restore_state_to_opc(CPUAVRState *env, TranslationBlock *tb, target_ulong *data)
{
env->pc = data[0];
}
-void avr_cpu_dump_state(
- CPUState *cs,
- FILE *f,
- fprintf_function cpu_fprintf,
- int flags)
+void avr_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, int flags)
{
AVRCPU *cpu = AVR_CPU(cs);
CPUAVRState *env = &cpu->env;
diff --git a/target-avr/translate.h b/target-avr/translate.h
index fa65406..9062412 100644
--- a/target-avr/translate.h
+++ b/target-avr/translate.h
@@ -94,10 +94,7 @@ struct DisasContext {
uint32_t avr_decode(uint32_t pc, uint32_t *length, uint32_t opcode, translate_function_t *translate);
-static inline void gen_goto_tb(CPUAVRState *env,
- DisasContext *ctx,
- int n,
- target_ulong dest)
+static inline void gen_goto_tb(CPUAVRState *env, DisasContext *ctx, int n, target_ulong dest)
{
TranslationBlock *tb;
--
2.4.9 (Apple Git-60)
^ permalink raw reply related [flat|nested] 13+ messages in thread