[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH rc5 09/32] target/avr: Add instruction helpers
From: |
Aleksandar Markovic |
Subject: |
[PATCH rc5 09/32] target/avr: Add instruction helpers |
Date: |
Fri, 7 Feb 2020 02:57:37 +0100 |
From: Michael Rolnik <address@hidden>
Add helpers for instructions that need to interact with QEMU. Also,
add stubs for unimplemented instructions. Instructions SPM and WDR
are left unimplemented because they require emulation of complex
peripherals. The implementation of instruction SLEEP is very limited
due to the lack of peripherals to generate wake interrupts. Memory
access instructions are implemented here because some address ranges
actually refer to CPU registers.
Signed-off-by: Michael Rolnik <address@hidden>
Signed-off-by: Richard Henderson <address@hidden>
Signed-off-by: Aleksandar Markovic <address@hidden>
Tested-by: Philippe Mathieu-Daudé <address@hidden>
Reviewed-by: Aleksandar Markovic <address@hidden>
---
target/avr/helper.h | 29 ++++++++
target/avr/helper.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++
MAINTAINERS | 1 +
3 files changed, 233 insertions(+)
create mode 100644 target/avr/helper.h
diff --git a/target/avr/helper.h b/target/avr/helper.h
new file mode 100644
index 0000000..bf08750
--- /dev/null
+++ b/target/avr/helper.h
@@ -0,0 +1,29 @@
+/*
+ * QEMU AVR CPU
+ *
+ * Copyright (c) 2019 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>
+ */
+
+DEF_HELPER_1(wdr, void, env)
+DEF_HELPER_1(debug, void, env)
+DEF_HELPER_1(break, 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)
+DEF_HELPER_3(fullwr, void, env, i32, i32)
+DEF_HELPER_2(fullrd, tl, env, i32)
diff --git a/target/avr/helper.c b/target/avr/helper.c
index 354def2..c582312 100644
--- a/target/avr/helper.c
+++ b/target/avr/helper.c
@@ -137,3 +137,206 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int
size,
return true;
}
+
+/*
+ * helpers
+ */
+
+void helper_sleep(CPUAVRState *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ cs->exception_index = EXCP_HLT;
+ cpu_loop_exit(cs);
+}
+
+void helper_unsupported(CPUAVRState *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ /*
+ * I count not find what happens on the real platform, so
+ * it's EXCP_DEBUG for meanwhile
+ */
+ cs->exception_index = EXCP_DEBUG;
+ if (qemu_loglevel_mask(LOG_UNIMP)) {
+ qemu_log("UNSUPPORTED\n");
+ cpu_dump_state(cs, stderr, 0);
+ }
+ cpu_loop_exit(cs);
+}
+
+void helper_debug(CPUAVRState *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ cs->exception_index = EXCP_DEBUG;
+ cpu_loop_exit(cs);
+}
+
+void helper_break(CPUAVRState *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ cs->exception_index = EXCP_DEBUG;
+ cpu_loop_exit(cs);
+}
+
+void helper_wdr(CPUAVRState *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ /* WD is not implemented yet, placeholder */
+ cs->exception_index = EXCP_DEBUG;
+ cpu_loop_exit(cs);
+}
+
+/*
+ * This function implements IN instruction
+ *
+ * It does the following
+ * a. if an IO register belongs to CPU, its value is read and returned
+ * b. otherwise io address is translated to mem address and physical memory
+ * is read.
+ * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation
+ *
+ */
+target_ulong helper_inb(CPUAVRState *env, uint32_t port)
+{
+ target_ulong data = 0;
+
+ switch (port) {
+ case 0x38: /* RAMPD */
+ data = 0xff & (env->rampD >> 16);
+ break;
+ case 0x39: /* RAMPX */
+ data = 0xff & (env->rampX >> 16);
+ break;
+ case 0x3a: /* RAMPY */
+ data = 0xff & (env->rampY >> 16);
+ break;
+ case 0x3b: /* RAMPZ */
+ data = 0xff & (env->rampZ >> 16);
+ break;
+ case 0x3c: /* EIND */
+ data = 0xff & (env->eind >> 16);
+ break;
+ case 0x3d: /* SPL */
+ data = env->sp & 0x00ff;
+ break;
+ case 0x3e: /* SPH */
+ data = env->sp >> 8;
+ break;
+ case 0x3f: /* SREG */
+ data = cpu_get_sreg(env);
+ break;
+ default:
+ /* not a special register, pass to normal memory access */
+ cpu_physical_memory_read(OFFSET_IO_REGISTERS + port, &data, 1);
+ }
+
+ return data;
+}
+
+/*
+ * This function implements OUT instruction
+ *
+ * It does the following
+ * a. if an IO register belongs to CPU, its value is written into the
register
+ * b. otherwise io address is translated to mem address and physical memory
+ * is written.
+ * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation
+ *
+ */
+void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data)
+{
+ data &= 0x000000ff;
+
+ switch (port) {
+ case 0x38: /* RAMPD */
+ if (avr_feature(env, AVR_FEATURE_RAMPD)) {
+ env->rampD = (data & 0xff) << 16;
+ }
+ break;
+ case 0x39: /* RAMPX */
+ if (avr_feature(env, AVR_FEATURE_RAMPX)) {
+ env->rampX = (data & 0xff) << 16;
+ }
+ break;
+ case 0x3a: /* RAMPY */
+ if (avr_feature(env, AVR_FEATURE_RAMPY)) {
+ env->rampY = (data & 0xff) << 16;
+ }
+ break;
+ case 0x3b: /* RAMPZ */
+ if (avr_feature(env, AVR_FEATURE_RAMPZ)) {
+ env->rampZ = (data & 0xff) << 16;
+ }
+ break;
+ case 0x3c: /* EIDN */
+ env->eind = (data & 0xff) << 16;
+ break;
+ case 0x3d: /* SPL */
+ env->sp = (env->sp & 0xff00) | (data);
+ break;
+ case 0x3e: /* SPH */
+ if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) {
+ env->sp = (env->sp & 0x00ff) | (data << 8);
+ }
+ break;
+ case 0x3f: /* SREG */
+ cpu_set_sreg(env, data);
+ break;
+ default:
+ /* not a special register, pass to normal memory access */
+ cpu_physical_memory_write(OFFSET_IO_REGISTERS + port, &data, 1);
+ }
+}
+
+/*
+ * this function implements LD instruction when there is a posibility to read
+ * from a CPU register
+ */
+target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr)
+{
+ uint8_t data;
+
+ env->fullacc = false;
+
+ if (addr < NUMBER_OF_CPU_REGISTERS) {
+ /* CPU registers */
+ data = env->r[addr];
+ } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) {
+ /* IO registers */
+ data = helper_inb(env, addr - NUMBER_OF_CPU_REGISTERS);
+ } else {
+ /* memory */
+ cpu_physical_memory_read(OFFSET_DATA + addr, &data, 1);
+ }
+ return data;
+}
+
+/*
+ * this function implements ST instruction when there is a posibility to write
+ * into a CPU register
+ */
+void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr)
+{
+ env->fullacc = false;
+
+ /* Following logic assumes this: */
+ assert(OFFSET_CPU_REGISTERS == OFFSET_DATA);
+ assert(OFFSET_IO_REGISTERS == OFFSET_CPU_REGISTERS +
+ NUMBER_OF_CPU_REGISTERS);
+
+ if (addr < NUMBER_OF_CPU_REGISTERS) {
+ /* CPU registers */
+ env->r[addr] = data;
+ } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) {
+ /* IO registers */
+ helper_outb(env, addr - NUMBER_OF_CPU_REGISTERS, data);
+ } else {
+ /* memory */
+ cpu_physical_memory_write(OFFSET_DATA + addr, &data, 1);
+ }
+}
diff --git a/MAINTAINERS b/MAINTAINERS
index ef7b51f..3d83ed0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -172,6 +172,7 @@ F: target/avr/cpu-param.h
F: target/avr/cpu-qom.h
F: target/avr/cpu.h
F: target/avr/cpu.c
+F: target/avr/helper.h
F: target/avr/helper.c
F: target/avr/gdbstub.c
F: target/avr/machine.c
--
2.7.4
- [PATCH rc5 30/32] .travis.yml: Run the AVR acceptance tests, (continued)
- [PATCH rc5 30/32] .travis.yml: Run the AVR acceptance tests, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 27/32] tests/machine-none: Add AVR support, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 23/32] hw/avr: Add support for loading ELF/raw binaries, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 25/32] hw/avr: Add limited support for some Arduino boards, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 22/32] target/avr: Register AVR support with the rest of QEMU, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 28/32] tests/boot-serial: Test some Arduino boards (AVR based), Aleksandar Markovic, 2020/02/06
- [PATCH rc5 32/32] target/avr: Add section into QEMU documentation, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 29/32] tests/acceptance: Test the Arduino MEGA2560 board, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 10/32] target/avr: Add instruction translation - Register definitions, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 31/32] target/avr: Simplify sections in MAINTAINERS file, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 09/32] target/avr: Add instruction helpers,
Aleksandar Markovic <=
- [PATCH rc5 21/32] hw/misc: avr: Add limited support for power reduction device, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 11/32] target/avr: Add instruction translation - Arithmetic and Logic Instructions, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 26/32] target/avr: Update build system, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 19/32] hw/char: avr: Add limited support for USART peripheral, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 24/32] hw/avr: Add some ATmega microcontrollers, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 13/32] target/avr: Add instruction translation - Data Transfer Instructions, Aleksandar Markovic, 2020/02/06
- [PATCH rc5 20/32] hw/timer: avr: Add limited support for 16-bit timer peripheral, Aleksandar Markovic, 2020/02/06