[Qemu-devel] [Bug 916720] Re: select fails on windows because a non-socket fd is in the rfds set
it seems that g_main_context_default creates a semaphore which is added into rfds passed to glib_select_fill function, that's why select fails. -- You received this bug notification because you are a member of qemu- devel-ml, which is subscribed to QEMU. https://bugs.launchpad.net/bugs/916720 Title: select fails on windows because a non-socket fd is in the rfds set Status in QEMU: New Bug description: The select call in file main_loop.c at line 460 fails on windows because a non-socket fd is in the rfds set. As a result, gdb remote connections will never be accepted by qemu. The select function returns with -1. WSAGetLastError returns code 10038 (WSAENOTSOCK). I start qemu as follows: qemu-system-arm -cpu cortex-m3 -M lm3s6965evb -nographic -monitor null -serial null -semihosting -kernel test1.elf -S -gdb tcp:127.0.0.1:2200 qemu is configure with: CFLAGS="-O4 -march=i686" configure --target-list="i386-softmmu arm-softmmu sparc-softmmu ppc-softmmu" --prefix=/home/qemu/install --cc=mingw32-gcc --host-cc=mingw32-gcc --audio-drv-list="dsound sdl" --audio-card-list="ac97 es1370 sb16 cs4231a adlib gus" To manage notifications about this bug go to: https://bugs.launchpad.net/qemu/+bug/916720/+subscriptions
[Qemu-devel] MMU address collision.
Hi all, I have a question regarding MMU. I've built SPARC based small embedded system. at this system addresses *0x-0x8000* (32KB) belong to ROM and *0x8000 - 0x80001000* to HW devices. the problem is that when a code from first ROM page accesses a HW device register there is an infinite loop. -- Best Regards, Michael Rolnik
Re: [Qemu-devel] MMU address collision.
Hi all, I have a question regarding MMU. I've built SPARC based small embedded system. at this system addresses *0x-0x8000* (32KB) belong to ROM and *0x8000 - 0x80001000* to HW devices. the problem is that when a code from first ROM page accesses a HW device register there is an infinite loop. - cpu_sparc_handle_mmu_fault is called to bring page 0 - cpu_sparc_handle_mmu_fault is called to bring 0x8000 and flushes 0x - cpu_sparc_handle_mmu_fault is called to bring 0x and flushes 0x8000 ... this can be fixed if I set CPU_TLB_BITS to be 20 bits. is there a better solution? Michael
[Qemu-devel] TLB collision
Hi all, I have a question regarding MMU. I've built a SPARC based small embedded system. at this system addresses 0x-0x8000 (32KB) belong to ROM and 0x8000 - 0x8001 to RAM. the problem is that when a code from first ROM page accesses a memory at the address 0x8000 there is an infinite loop. - cpu_sparc_handle_mmu_fault is called to bring addres 0x - cpu_sparc_handle_mmu_fault is called to bring 0x8000 and flushes 0x - cpu_sparc_handle_mmu_fault is called to bring 0x and flushes 0x8000 ... this can be fixed if I set CPU_TLB_BITS to be 20 bits (assuming page size of 4KB). is there a better solution? I was thinking about 2-way TLB so two virtual addresses sharing same TLB entry will be resident. in order not to degrade performance 1. *tcg_out_qemu_ld* and *tcg_out_qemu_st* should remain as it, which mean they will always look into way0. 2. *tlb_set_page* should copy way0 to way1 and program way0 with new values 3. all other routines dealing with TLB should search both ways. what do you think? -- Best Regards, Michael Rolnik
[Qemu-devel] [PATCH 5/9] adding AVR interrupt handling
Signed-off-by: Michael Rolnik --- 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 @@ boolavr_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; + +boolret = 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; } voidavr_cpu_do_interrupt( CPUState *cs) { +AVRCPU *cpu = AVR_CPU(cs); +CPUAVRState*env = &cpu->env; + +uint32_tret = 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 & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +stb_phys(cs->as, env->sp--, (ret & 0xff) >> 16); + +env->pc = base + vector * size; +} else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); + +env->pc = base + vector * size; +} else { +stb_phys(cs->as, env->sp--, (ret & 0xff)); + +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)
[Qemu-devel] [PATCH 1/9] AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions
Signed-off-by: Michael Rolnik --- arch_init.c | 2 + configure | 5 + default-configs/avr-softmmu.mak | 1 + disas/Makefile.objs | 1 + disas/avr.c | 10 ++ include/disas/bfd.h | 7 + include/sysemu/arch_init.h | 1 + target-avr/Makefile.objs| 3 + target-avr/cpu-qom.h| 97 + target-avr/cpu.c| 315 target-avr/cpu.h| 152 +++ target-avr/gdbstub.c| 105 ++ target-avr/helper.c | 105 ++ target-avr/helper.h | 21 +++ target-avr/machine.c| 54 +++ target-avr/machine.h| 21 +++ target-avr/translate.c | 300 ++ 17 files changed, 1200 insertions(+) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 disas/avr.c create mode 100644 target-avr/Makefile.objs create mode 100644 target-avr/cpu-qom.h create mode 100644 target-avr/cpu.c create mode 100644 target-avr/cpu.h create mode 100644 target-avr/gdbstub.c create mode 100644 target-avr/helper.c create mode 100644 target-avr/helper.h create mode 100644 target-avr/machine.c create mode 100644 target-avr/machine.h create mode 100644 target-avr/translate.c diff --git a/arch_init.c b/arch_init.c index fa05973..be6e6de 100644 --- a/arch_init.c +++ b/arch_init.c @@ -80,6 +80,8 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_TRICORE) #define QEMU_ARCH QEMU_ARCH_TRICORE +#elif defined(TARGET_AVR) +#define QEMU_ARCH QEMU_ARCH_AVR #endif const uint32_t arch_type = QEMU_ARCH; diff --git a/configure b/configure index b5aab72..90af399 100755 --- a/configure +++ b/configure @@ -5630,6 +5630,8 @@ case "$target_name" in x86_64) TARGET_BASE_ARCH=i386 ;; + avr) + ;; alpha) ;; arm|armeb) @@ -5826,6 +5828,9 @@ disas_config() { for i in $ARCH $TARGET_BASE_ARCH ; do case "$i" in + avr) +disas_config "AVR" + ;; alpha) disas_config "ALPHA" ;; diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak new file mode 100644 index 000..ca94aad --- /dev/null +++ b/default-configs/avr-softmmu.mak @@ -0,0 +1 @@ +# Default configuration for avr-softmmu diff --git a/disas/Makefile.objs b/disas/Makefile.objs index abeba84..218e434 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -21,6 +21,7 @@ common-obj-$(CONFIG_S390_DIS) += s390.o common-obj-$(CONFIG_SH4_DIS) += sh4.o common-obj-$(CONFIG_SPARC_DIS) += sparc.o common-obj-$(CONFIG_LM32_DIS) += lm32.o +common-obj-$(CONFIG_AVR_DIS) += avr.o # TODO: As long as the TCG interpreter and its generated code depend # on the QEMU target, we cannot compile the disassembler here. diff --git a/disas/avr.c b/disas/avr.c new file mode 100644 index 000..f916e72 --- /dev/null +++ b/disas/avr.c @@ -0,0 +1,10 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "disas/bfd.h" + +int print_insn_avr(bfd_vma addr, disassemble_info *info) +{ +int length = 0;; +/* TODO*/ +return length; +} diff --git a/include/disas/bfd.h b/include/disas/bfd.h index a112e9c..04e2201 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -213,6 +213,12 @@ enum bfd_architecture #define bfd_mach_m32r 0 /* backwards compatibility */ bfd_arch_mn10200,/* Matsushita MN10200 */ bfd_arch_mn10300,/* Matsushita MN10300 */ + bfd_arch_avr, /* Atmel AVR microcontrollers. */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr3 3 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 bfd_arch_cris, /* Axis CRIS */ #define bfd_mach_cris_v0_v10 255 #define bfd_mach_cris_v32 32 @@ -415,6 +421,7 @@ int print_insn_crisv10 (bfd_vma, disassemble_info*); int print_insn_microblaze (bfd_vma, disassemble_info*); int print_insn_ia64 (bfd_vma, disassemble_info*); int print_insn_lm32 (bfd_vma, disassemble_info*); +int print_insn_avr (bfd_vma, disassemble_info*); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index d690dfa..8c75777 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -23,6 +23,7 @@ enum { QEMU_ARCH_UNICORE32 = (1 << 14), QEMU_ARCH_MOXIE = (1 << 15), QEMU_ARCH_TRICORE = (1 << 16), +QEMU_ARCH_AVR = (1 << 17), }; extern const uint32_t arch_type; diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs new file mode 100644 index 000..c503546 --- /dev/null +++ b/target-avr/Makefile.objs @@ -0,0 +1,3 @@ +obj-y += translate.o cp
[Qemu-devel] [PATCH 4/9] adding instructions encodings for LE and BE compilers.
I am aware of bad portability of bit fields as compilers for LE and BE hosts lists bit fields in different order However they won't "parse" in target memory but a data prepared by me Signed-off-by: Michael Rolnik --- target-avr/inst-be.h | 1018 ++ target-avr/inst-le.h | 1018 ++ 2 files changed, 2036 insertions(+) create mode 100644 target-avr/inst-be.h create mode 100644 target-avr/inst-le.h diff --git a/target-avr/inst-be.h b/target-avr/inst-be.h new file mode 100644 index 000..99897c0 --- /dev/null +++ b/target-avr/inst-be.h @@ -0,0 +1,1018 @@ +/* + * 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> + */ + + +typedef struct DisasContextDisasContext; +typedef struct CPUAVRState CPUAVRState; + +typedef union avr_opcode_NOP_u { +uint16_topcode; +struct { +uint16_t:16; /* */ +}; +} avr_opcode_NOP_t; +int avr_translate_NOP(CPUAVRState *env, DisasContext *ctx, avr_opcode_NOP_t const *inst); + +typedef union avr_opcode_MOVW_u { +uint16_topcode; +struct { +uint16_t:8; /* 0001 */ +uint16_tRd:4; +uint16_tRr:4; +}; +} avr_opcode_MOVW_t; +int avr_translate_MOVW(CPUAVRState *env, DisasContext *ctx, avr_opcode_MOVW_t const *inst); + +typedef union avr_opcode_MULS_u { +uint16_topcode; +struct { +uint16_t:8; /* 0010 */ +uint16_tRd:4; +uint16_tRr:4; +}; +} avr_opcode_MULS_t; +int avr_translate_MULS(CPUAVRState *env, DisasContext *ctx, avr_opcode_MULS_t const *inst); + +typedef union avr_opcode_MULSU_u { +uint16_topcode; +struct { +uint16_t:9; /* 00110 */ +uint16_tRd:3; +uint16_t:1; /* 0 */ +uint16_tRr:3; +}; +} avr_opcode_MULSU_t; +int avr_translate_MULSU(CPUAVRState *env, DisasContext *ctx, avr_opcode_MULSU_t const *inst); + +typedef union avr_opcode_FMUL_u { +uint16_topcode; +struct { +uint16_t:9; /* 00110 */ +uint16_tRd:3; +uint16_t:1; /* 1 */ +uint16_tRr:3; +}; +} avr_opcode_FMUL_t; +int avr_translate_FMUL(CPUAVRState *env, DisasContext *ctx, avr_opcode_FMUL_t const *inst); + +typedef union avr_opcode_FMULS_u { +uint16_topcode; +struct { +uint16_t:9; /* 00111 */ +uint16_tRd:3; +uint16_t:1; /* 0 */ +uint16_tRr:3; +}; +} avr_opcode_FMULS_t; +int avr_translate_FMULS(CPUAVRState *env, DisasContext *ctx, avr_opcode_FMULS_t const *inst); + +typedef union avr_opcode_FMULSU_u { +uint16_topcode; +struct { +uint16_t:9; /* 00111 */ +uint16_tRd:3; +uint16_t:1; /* 1 */ +uint16_tRr:3; +}; +} avr_opcode_FMULSU_t; +int avr_translate_FMULSU(CPUAVRState *env, DisasContext *ctx, avr_opcode_FMULSU_t const *inst); + +typedef union avr_opcode_CPC_u { +uint16_topcode; +struct { +uint16_t:6; /* 01 */ +uint16_thRr:1; +uint16_tRd:5; +uint16_tlRr:4; +}; +} avr_opcode_CPC_t; +int avr_translate_CPC(CPUAVRState *env, DisasContext *ctx, avr_opcode_CPC_t const *inst); + +typedef union avr_opcode_SBC_u { +uint16_topcode; +struct { +uint16_t:6; /* 10 */ +uint16_thRr:1; +uint16_tRd:5; +uint16_tlRr:4; +}; +} avr_opcode_SBC_t; +int avr_translate_SBC(CPUAVRState *env, DisasContext *ctx, avr_opcode_SBC_t const *inst); + +typedef union avr_opcode_ADD_u { +uint16_topcode; +struct { +uint16_t:6; /* 11 */ +uint16_thRr:1; +uint16_tRd:5; +uint16_tlRr:4; +}; +} avr_opcode_ADD_t; +int avr_translate_ADD(CPUAVRState *env, DisasContext *ctx, avr_opcode_ADD_t const *inst); + +typedef union avr_opcode_AND_u { +uint16_topcode; +struct { +uint16_t:6; /* 001000 */ +uint16_thRr:1; +uint16_tRd:5; +uint16_tlRr:4; +}; +} avr_opcode_AND_t; +int avr_translate_AND(CPUAVRState *env, DisasContext *ctx, avr_opcode_AND_t const *inst); + +typedef union avr_opcode_
[Qemu-devel] [PATCH 6/9] adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
Signed-off-by: Michael Rolnik --- 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 @@ voidtlb_fill( tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size); } +voidhelper_sleep( +CPUAVRState*env) +{ +CPUState *cs = CPU(avr_env_get_cpu(env)); + +cs->exception_index = EXCP_HLT; +cpu_loop_exit(cs); +} +voidhelper_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); +} voidhelper_debug( CPUAVRState*env) @@ -165,3 +182,89 @@ voidhelper_debug( cpu_loop_exit(cs); } +voidhelper_wdr( +CPUAVRState*env) +{ +CPUState *cs = CPU(avr_env_get_cpu(env)); + +cs->exception_index = EXCP_DEBUG; +cpu_loop_exit(cs); +} + +target_ulonghelper_inb( +CPUAVRState*env, +uint32_tport) +{ +printf("in: io[%02x]\n", port); + +switch (port) { +case0x3b: { +return env->rampZ; /* RAMPZ */ +} +case0x3d: { /* SPL */ +return env->sp & 0x00ff; +} +case0x3e: { /* SPH */ +return env->sp >> 8; +} +case0x3f: { /* 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; +} + +voidhelper_outb( +CPUAVRState*env, +uint32_tport, +uint32_tdata) +{ +printf("out:%02x -> io[%02x]\n", data, port); + +data&= 0x00ff; + +switch (port) { +case0x04: { +qemu_irqirq; +CPUState *cpu = CPU(avr_env_get_cpu(env)); +irq = qdev_get_gpio_in(DEVICE(cpu), 3); +qemu_set_irq(irq, 1); +break; +} +case0x3b: { +env->rampZ = data & 0x01; /* RAMPZ */ +break; +} +case0x3d: { /* SPL */ +if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { +env->sp = (env->sp & 0xff00) | (data); +} +break; +} +case0x3e: { /* SPH */ +env->sp = (env->sp & 0x00ff) | (data << 8); +break; +} +case0x3f: { /* 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)
[Qemu-devel] [PATCH 9/9] updating gen_intermediate_code function to use prevously added decoder and translator
Signed-off-by: Michael Rolnik --- target-avr/Makefile.objs | 4 ++- target-avr/translate.c | 91 +++- 2 files changed, 86 insertions(+), 9 deletions(-) diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs index c503546..bbd2409 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 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..5a7436f 100644 --- a/target-avr/translate.c +++ b/target-avr/translate.c @@ -30,13 +30,32 @@ #include "exec/helper-gen.h" #include "exec/log.h" +uint32_tget_opcode( +uint8_t const *code, +unsignedbitBase, +unsignedbitSize); + typedef struct DisasContext DisasContext; typedef struct InstInfo InstInfo; +typedef int (*translate_function_t)( +CPUAVRState*env, +DisasContext *ctx, +uint8_t const *opcode); +struct InstInfo { +target_long cpc; +target_long npc; +uint32_topcode; +translate_function_ttranslate; +unsignedlength; +}; + /*This is the state at translation time. */ struct DisasContext { struct TranslationBlock*tb; +InstInfoinst[2];/* two consequitive instructions */ + /*Routine used to access memory */ int memidx; int bstate; @@ -144,6 +163,55 @@ static inline void gen_goto_tb(CPUAVRState*env, } } +#include "translate.c.inc" + +typedef int (*translate_function_t)( +CPUAVRState*env, +DisasContext *ctx, +uint8_t const *opcode); +voidavr_decode( +uint32_tpc, +uint32_t *length, +uint8_t const *code, +translate_function_t *translate); + + +static void decode_opc( +AVRCPU *cpu, +DisasContext *ctx, +InstInfo *inst) +{ +CPUAVRState*env = &cpu->env; + +inst->opcode= cpu_ldl_code(env, inst->cpc * 2); /* pc points to words*/ +inst->length= 16; +inst->translate = NULL; + +/* the following function looks onto the opcode as a string of bytes */ +avr_decode(inst->cpc, &inst->length, (uint8_t const *)&inst->opcode, &inst->translate); + +if (inst->length == 16) { +inst->npc= inst->cpc + 1; +/* get opcode as 16bit value */ +inst->opcode = inst->opcode & 0x; +} +if (inst->length == 32) { +inst->npc= inst->cpc + 2; +/* get opcode as 32bit value */ +inst->opcode = (inst->opcode << 16) + | (inst->opcode >> 16); +} +} + +uint32_tget_opcode( +uint8_t const *code, +unsignedbitBase, +unsignedbitSize) +{ +return *(uint16_t *)code; +} + + /*generate intermediate code for basic block 'tb'. */ voidgen_intermediate_code( CPUAVRState*env, @@ -176,18 +244,21 @@ voidgen_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 +270,8 @@ voidgen_inte
[Qemu-devel] [PATCH 3/9] adding a sample AVR board
Signed-off-by: Michael Rolnik --- 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 000..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 000..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_SIZE0x0020 +#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_BASE0x +#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 { +SysBusDeviceparent; + +MemoryRegioniomem; + +AVRCPU *cpu; + +uint8_t io[0x40]; +uint8_t exio[0xa0]; +} SAMPLEIOState; + +static uint64_t sample_io_read( +void *opaque, +hwaddr offset, +unsignedsize); +static void sample_io_write(void *opaque, +hwaddr offset, +uint64_tvalue, +unsignedsize); +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 +Propertysample_io_properties
[Qemu-devel] [PATCH 7/9] adding instruction decoder
Signed-off-by: Michael Rolnik --- target-avr/decode.c | 732 1 file changed, 732 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 000..f517045 --- /dev/null +++ b/target-avr/decode.c @@ -0,0 +1,732 @@ +/* + * 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 +#ifdef HOST_WORDS_BIGENDIAN +#include "inst-be.h" +#else +#include "inst-le.h" +#endif + + +typedef int (*translate_function_t)(CPUAVRState *env, DisasContext* ctx, uint8_t const *opcode); +uint32_tavr_decode(uint32_t pc, uint32_t *length, uint8_t *code, translate_function_t *translate); +uint32_tget_opcode(uint8_t const *code, unsigned bitBase, unsigned bitSsize); + +uint32_tavr_decode(uint32_t pc, uint32_t *length, uint8_t *code, translate_function_t *translate) +{ +uint32_topcode = get_opcode(code, 0, 16); +switch (opcode & 0xd000) { +case0x: { +uint32_topcode = get_opcode(code, 0, 16); +switch (opcode & 0x2c00) { +case0x: { +uint32_topcode = get_opcode(code, 0, 16); +switch (opcode & 0x0300) { +case0x: { +*length = 16; +*translate = (translate_function_t)&avr_translate_NOP; +break; +} +case0x0100: { +*length = 16; +*translate = (translate_function_t)&avr_translate_MOVW; +break; +} +case0x0200: { +*length = 16; +*translate = (translate_function_t)&avr_translate_MULS; +break; +} +case0x0300: { +uint32_topcode = get_opcode(code, 0, 16); +switch (opcode & 0x0088) { +case0x: { +*length = 16; +*translate = (translate_function_t)&avr_translate_MULSU; +break; +} +case0x0008: { +*length = 16; +*translate = (translate_function_t)&avr_translate_FMUL; +break; +} +case0x0080: { +*length = 16; +*translate = (translate_function_t)&avr_translate_FMULS; +break; +} +case0x0088: { +*length = 16; +*translate = (translate_function_t)&avr_translate_FMULSU; +break; +} +} +break; +} +} +break; +} +case0x0400: { +*length = 16; +*translate = (translate_function_t)&avr_translate_CPC; +break; +} +case0x0800: { +*length = 16; +*translate = (translate_function_t)&avr_translate_SBC; +break; +} +case0x0c00: { +*length = 16; +*translate = (translate_function_t)&avr_translate_ADD; +break; +} +case0x2000: { +*length = 16; +*translate = (translate_function_t)&a
[Qemu-devel] [PATCH 2/9] adding AVR CPU features/flavors
Signed-off-by: Michael Rolnik --- 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_tfeatures= 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);
[Qemu-devel] [PATCH 8/9] adding instruction translations
Signed-off-by: Michael Rolnik --- target-avr/translate.c.inc | 2546 1 file changed, 2546 insertions(+) create mode 100644 target-avr/translate.c.inc diff --git a/target-avr/translate.c.inc b/target-avr/translate.c.inc new file mode 100644 index 000..74b3c2c --- /dev/null +++ b/target-avr/translate.c.inc @@ -0,0 +1,2546 @@ +/* + * 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 +#include + +#ifdef HOST_WORDS_BIGENDIAN +#include "inst-be.h" +#else +#include "inst-le.h" +#endif + +/* +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 +*/ + +voidgen_add_CHf(TCGvR, TCGvRd, TCGvRr); +voidgen_add_Vf( TCGvR, TCGvRd, TCGvRr); +voidgen_sub_CHf(TCGvR, TCGvRd, TCGvRr); +voidgen_sub_Vf( TCGvR, TCGvRd, TCGvRr); +voidgen_ZNSf( TCGvR); +voidgen_push_ret( CPUAVRState *env, intret); +voidgen_pop_ret(CPUAVRState *env, TCGvret); +voidgen_jmp_ez( void); +voidgen_jmp_z( void); + +voidgen_set_addr( TCGv addr, TCGv H, TCGv M, TCGv l); /* H:M:L = addr */ +voidgen_set_xaddr( TCGv addr); +voidgen_set_yaddr( TCGv addr); +voidgen_set_zaddr( TCGv addr); + +TCGvgen_get_addr( TCGv H, TCGv M, TCGv L);/* addr = H:M:L */ +TCGvgen_get_xaddr( void); +TCGvgen_get_yaddr( void); +TCGvgen_get_zaddr( void); +int sex(int Imm, unsigned bits); + +voidgen_add_CHf(TCGvR, TCGvRd, TCGvRr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = tcg_temp_new_i32(); +TCGvt3 = 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); +} + +voidgen_add_Vf(TCGvR, TCGvRd, TCGvRr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = 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); +} + +voidgen_sub_CHf(TCGvR, TCGvRd, TCGvRr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = tcg_temp_new_i32(); +TCGvt3 = 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); +} + +voidgen_sub_Vf(TCGv
[Qemu-devel] heterogenous cores
Hi all, Is there a way to build a platform with two or more different cores e.g. PPC & ARM ? -- Best Regards, Michael Rolnik
Re: [Qemu-devel] heterogenous cores
as I understand it's not possible right off the shelf as some functions like gen_intermediate_code are global. so, the question is *is it a complex task to make a heterogenous setup possible*? On Thu, Jun 2, 2016 at 12:28 AM, Michael Rolnik wrote: > Hi all, > > Is there a way to build a platform with two or more different cores e.g. > PPC & ARM ? > > -- > Best Regards, > Michael Rolnik > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH 4/9] adding instructions encodings for LE and BE compilers.
I disagree. it's non portable as long as you don't know what compiler you are using. if bitfields are not acceptable at all, I will regenerate my code. thanks. On Thu, Jun 2, 2016 at 9:32 AM, Richard Henderson wrote: > On 05/29/2016 06:23 PM, Michael Rolnik wrote: > >> I am aware of bad portability of bit fields as compilers >> for LE and BE hosts lists bit fields in different order >> However they won't "parse" in target memory but a data prepared by me >> > > What data prepared by you? You're assigning to an int16_t and hoping that > specific bit fields map to specific bits. That's just non-portable. > > We don't want code that does that. The fact that you had to replicate > 1018 lines of code should have been a hint that you're doing it wrong. > > Take Peter's advice and use extract32. > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH 1/9] AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions
I ran checkpatch.pl on my patches and it was ok. I will fix it. On Thu, Jun 2, 2016 at 9:39 AM, Richard Henderson wrote: > On 05/29/2016 06:23 PM, Michael Rolnik wrote: > >> +static void avr_cpu_set_pc( >> +CPUState *cs, >> +vaddr value) >> > > The formatting throughout all of these patches is wrong. > You need to follow the instructions in CODING_STYLE. > You can use ./scripts/checkpatch.pl to catch mistakes. > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH 8/9] adding instruction translations
right. no reason. I can make it just a C file. when I started I was not sure what was the best way to do it as I generate some come code. thanks, I will fix it. On Thu, Jun 2, 2016 at 9:44 AM, Richard Henderson wrote: > On 05/29/2016 06:23 PM, Michael Rolnik wrote: > >> Signed-off-by: Michael Rolnik >> --- >> target-avr/translate.c.inc | 2546 >> >> 1 file changed, 2546 insertions(+) >> create mode 100644 target-avr/translate.c.inc >> > > Is there any good reason for you to pull out these functions into an > include file? I think this is simply confusing. > > > r~ > -- Best Regards, Michael Rolnik
[Qemu-devel] [PATCH 10/10] target-avr: fixing code style
Signed-off-by: Michael Rolnik --- 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 -voidavr_cpu_do_interrupt( -CPUState *cpu); -boolavr_cpu_exec_interrupt( -CPUState *cpu, -int int_req); -voidavr_cpu_dump_state( -CPUState *cs, -FILE *f, -fprintf_functioncpu_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*
[Qemu-devel] [PATCH 03/10] target-avr: adding a sample AVR board
Signed-off-by: Michael Rolnik --- 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 000..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 000..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_SIZE0x0020 +#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_BASE0x +#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 { +SysBusDeviceparent; + +MemoryRegioniomem; + +AVRCPU *cpu; + +uint8_t io[0x40]; +uint8_t exio[0xa0]; +} SAMPLEIOState; + +static uint64_t sample_io_read( +void *opaque, +hwaddr offset, +unsignedsize); +static void sample_io_write(void *opaque, +hwaddr offset, +uint64_tvalue, +unsignedsize); +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 +Propertysample_io_properties
[Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions
Signed-off-by: Michael Rolnik --- arch_init.c | 2 + configure | 5 + default-configs/avr-softmmu.mak | 1 + disas/Makefile.objs | 1 + disas/avr.c | 10 ++ include/disas/bfd.h | 7 + include/sysemu/arch_init.h | 1 + target-avr/Makefile.objs| 3 + target-avr/cpu-qom.h| 97 + target-avr/cpu.c| 315 target-avr/cpu.h| 152 +++ target-avr/gdbstub.c| 105 ++ target-avr/helper.c | 105 ++ target-avr/helper.h | 21 +++ target-avr/machine.c| 54 +++ target-avr/machine.h| 21 +++ target-avr/translate.c | 300 ++ 17 files changed, 1200 insertions(+) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 disas/avr.c create mode 100644 target-avr/Makefile.objs create mode 100644 target-avr/cpu-qom.h create mode 100644 target-avr/cpu.c create mode 100644 target-avr/cpu.h create mode 100644 target-avr/gdbstub.c create mode 100644 target-avr/helper.c create mode 100644 target-avr/helper.h create mode 100644 target-avr/machine.c create mode 100644 target-avr/machine.h create mode 100644 target-avr/translate.c diff --git a/arch_init.c b/arch_init.c index fa05973..be6e6de 100644 --- a/arch_init.c +++ b/arch_init.c @@ -80,6 +80,8 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_TRICORE) #define QEMU_ARCH QEMU_ARCH_TRICORE +#elif defined(TARGET_AVR) +#define QEMU_ARCH QEMU_ARCH_AVR #endif const uint32_t arch_type = QEMU_ARCH; diff --git a/configure b/configure index b5aab72..90af399 100755 --- a/configure +++ b/configure @@ -5630,6 +5630,8 @@ case "$target_name" in x86_64) TARGET_BASE_ARCH=i386 ;; + avr) + ;; alpha) ;; arm|armeb) @@ -5826,6 +5828,9 @@ disas_config() { for i in $ARCH $TARGET_BASE_ARCH ; do case "$i" in + avr) +disas_config "AVR" + ;; alpha) disas_config "ALPHA" ;; diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak new file mode 100644 index 000..ca94aad --- /dev/null +++ b/default-configs/avr-softmmu.mak @@ -0,0 +1 @@ +# Default configuration for avr-softmmu diff --git a/disas/Makefile.objs b/disas/Makefile.objs index abeba84..218e434 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -21,6 +21,7 @@ common-obj-$(CONFIG_S390_DIS) += s390.o common-obj-$(CONFIG_SH4_DIS) += sh4.o common-obj-$(CONFIG_SPARC_DIS) += sparc.o common-obj-$(CONFIG_LM32_DIS) += lm32.o +common-obj-$(CONFIG_AVR_DIS) += avr.o # TODO: As long as the TCG interpreter and its generated code depend # on the QEMU target, we cannot compile the disassembler here. diff --git a/disas/avr.c b/disas/avr.c new file mode 100644 index 000..f916e72 --- /dev/null +++ b/disas/avr.c @@ -0,0 +1,10 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "disas/bfd.h" + +int print_insn_avr(bfd_vma addr, disassemble_info *info) +{ +int length = 0;; +/* TODO*/ +return length; +} diff --git a/include/disas/bfd.h b/include/disas/bfd.h index a112e9c..04e2201 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -213,6 +213,12 @@ enum bfd_architecture #define bfd_mach_m32r 0 /* backwards compatibility */ bfd_arch_mn10200,/* Matsushita MN10200 */ bfd_arch_mn10300,/* Matsushita MN10300 */ + bfd_arch_avr, /* Atmel AVR microcontrollers. */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr3 3 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 bfd_arch_cris, /* Axis CRIS */ #define bfd_mach_cris_v0_v10 255 #define bfd_mach_cris_v32 32 @@ -415,6 +421,7 @@ int print_insn_crisv10 (bfd_vma, disassemble_info*); int print_insn_microblaze (bfd_vma, disassemble_info*); int print_insn_ia64 (bfd_vma, disassemble_info*); int print_insn_lm32 (bfd_vma, disassemble_info*); +int print_insn_avr (bfd_vma, disassemble_info*); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index d690dfa..8c75777 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -23,6 +23,7 @@ enum { QEMU_ARCH_UNICORE32 = (1 << 14), QEMU_ARCH_MOXIE = (1 << 15), QEMU_ARCH_TRICORE = (1 << 16), +QEMU_ARCH_AVR = (1 << 17), }; extern const uint32_t arch_type; diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs new file mode 100644 index 000..c503546 --- /dev/null +++ b/target-avr/Makefile.objs @@ -0,0 +1,3 @@ +obj-y += translate.o cp
[Qemu-devel] [PATCH 06/10] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
Signed-off-by: Michael Rolnik --- 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 @@ voidtlb_fill( tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size); } +voidhelper_sleep( +CPUAVRState*env) +{ +CPUState *cs = CPU(avr_env_get_cpu(env)); + +cs->exception_index = EXCP_HLT; +cpu_loop_exit(cs); +} +voidhelper_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); +} voidhelper_debug( CPUAVRState*env) @@ -165,3 +182,89 @@ voidhelper_debug( cpu_loop_exit(cs); } +voidhelper_wdr( +CPUAVRState*env) +{ +CPUState *cs = CPU(avr_env_get_cpu(env)); + +cs->exception_index = EXCP_DEBUG; +cpu_loop_exit(cs); +} + +target_ulonghelper_inb( +CPUAVRState*env, +uint32_tport) +{ +printf("in: io[%02x]\n", port); + +switch (port) { +case0x3b: { +return env->rampZ; /* RAMPZ */ +} +case0x3d: { /* SPL */ +return env->sp & 0x00ff; +} +case0x3e: { /* SPH */ +return env->sp >> 8; +} +case0x3f: { /* 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; +} + +voidhelper_outb( +CPUAVRState*env, +uint32_tport, +uint32_tdata) +{ +printf("out:%02x -> io[%02x]\n", data, port); + +data&= 0x00ff; + +switch (port) { +case0x04: { +qemu_irqirq; +CPUState *cpu = CPU(avr_env_get_cpu(env)); +irq = qdev_get_gpio_in(DEVICE(cpu), 3); +qemu_set_irq(irq, 1); +break; +} +case0x3b: { +env->rampZ = data & 0x01; /* RAMPZ */ +break; +} +case0x3d: { /* SPL */ +if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { +env->sp = (env->sp & 0xff00) | (data); +} +break; +} +case0x3e: { /* SPH */ +env->sp = (env->sp & 0x00ff) | (data << 8); +break; +} +case0x3f: { /* 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)
[Qemu-devel] [PATCH 09/10] target-avr: updating translate.c to use instructions translation
Signed-off-by: Michael Rolnik --- 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 @@ voidavr_translate_init(void) done_init = 1; } -static inline void gen_goto_tb(CPUAVRState*env, -DisasContext *ctx, -int n, -target_ulongdest) +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 & 0x; +} +if (inst->length == 32) { +inst->npc= inst->cpc + 2; +/* get opcode as 32bit value */ +inst->opcode = (inst->opcode << 16) + | (inst->opcode >> 16); } } +uint32_tget_opcode( +uint8_t const *code, +unsignedbitBase, +unsignedbitSize) +{ +return *(uint16_t *)code; +} + + /*generate intermediate code for basic block 'tb'. */ voidgen_intermediate_code( CPUAVRState
[Qemu-devel] [PATCH 04/10] target-avr: adding instructions encodings
Signed-off-by: Michael Rolnik --- 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 000..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 DisasContextDisasContext; + +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
[Qemu-devel] [PATCH 02/10] target-avr: adding AVR CPU features/flavors
Signed-off-by: Michael Rolnik --- 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_tfeatures= 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);
[Qemu-devel] [PATCH 07/10] target-avr: adding instruction decoder
Signed-off-by: Michael Rolnik --- 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 000..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 +#include "translate.h" + + +uint32_tavr_decode(uint32_t pc, uint32_t *length, uint32_t code, translate_function_t *translate) +{ +uint32_topcode = extract32(code, 0, 16); +switch (opcode & 0xd000) { +case0x: { +uint32_topcode = extract32(code, 0, 16); +switch (opcode & 0x2c00) { +case0x: { +uint32_topcode = extract32(code, 0, 16); +switch (opcode & 0x0300) { +case0x: { +*length = 16; +*translate = (translate_function_t)&avr_translate_NOP; +break; +} +case0x0100: { +*length = 16; +*translate = (translate_function_t)&avr_translate_MOVW; +break; +} +case0x0200: { +*length = 16; +*translate = (translate_function_t)&avr_translate_MULS; +break; +} +case0x0300: { +uint32_topcode = extract32(code, 0, 16); +switch (opcode & 0x0088) { +case0x: { +*length = 16; +*translate = (translate_function_t)&avr_translate_MULSU; +break; +} +case0x0008: { +*length = 16; +*translate = (translate_function_t)&avr_translate_FMUL; +break; +} +case0x0080: { +*length = 16; +*translate = (translate_function_t)&avr_translate_FMULS; +break; +} +case0x0088: { +*length = 16; +*translate = (translate_function_t)&avr_translate_FMULSU; +break; +} +} +break; +} +} +break; +} +case0x0400: { +*length = 16; +*translate = (translate_function_t)&avr_translate_CPC; +break; +} +case0x0800: { +*length = 16; +*translate = (translate_function_t)&avr_translate_SBC; +break; +} +case0x0c00: { +*length = 16; +*translate = (translate_function_t)&avr_translate_ADD; +break; +} +case0x2000: { +*length = 16; +*translate = (translate_function_t)&avr_translate_AND; +break; +} +case0x2400: { +*length = 16; +*translate = (translate_function_t)&avr_translate_EOR; +break; +} +case0x2800: { +*length = 16; +
[Qemu-devel] [PATCH 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions
Signed-off-by: Michael Rolnik --- arch_init.c | 2 + configure | 5 + default-configs/avr-softmmu.mak | 1 + disas/Makefile.objs | 1 + disas/avr.c | 10 ++ include/disas/bfd.h | 7 + include/sysemu/arch_init.h | 1 + target-avr/Makefile.objs| 3 + target-avr/cpu-qom.h| 97 + target-avr/cpu.c| 315 target-avr/cpu.h| 152 +++ target-avr/gdbstub.c| 105 ++ target-avr/helper.c | 105 ++ target-avr/helper.h | 21 +++ target-avr/machine.c| 54 +++ target-avr/machine.h| 21 +++ target-avr/translate.c | 300 ++ 17 files changed, 1200 insertions(+) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 disas/avr.c create mode 100644 target-avr/Makefile.objs create mode 100644 target-avr/cpu-qom.h create mode 100644 target-avr/cpu.c create mode 100644 target-avr/cpu.h create mode 100644 target-avr/gdbstub.c create mode 100644 target-avr/helper.c create mode 100644 target-avr/helper.h create mode 100644 target-avr/machine.c create mode 100644 target-avr/machine.h create mode 100644 target-avr/translate.c diff --git a/arch_init.c b/arch_init.c index fa05973..be6e6de 100644 --- a/arch_init.c +++ b/arch_init.c @@ -80,6 +80,8 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_TRICORE) #define QEMU_ARCH QEMU_ARCH_TRICORE +#elif defined(TARGET_AVR) +#define QEMU_ARCH QEMU_ARCH_AVR #endif const uint32_t arch_type = QEMU_ARCH; diff --git a/configure b/configure index b5aab72..90af399 100755 --- a/configure +++ b/configure @@ -5630,6 +5630,8 @@ case "$target_name" in x86_64) TARGET_BASE_ARCH=i386 ;; + avr) + ;; alpha) ;; arm|armeb) @@ -5826,6 +5828,9 @@ disas_config() { for i in $ARCH $TARGET_BASE_ARCH ; do case "$i" in + avr) +disas_config "AVR" + ;; alpha) disas_config "ALPHA" ;; diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak new file mode 100644 index 000..ca94aad --- /dev/null +++ b/default-configs/avr-softmmu.mak @@ -0,0 +1 @@ +# Default configuration for avr-softmmu diff --git a/disas/Makefile.objs b/disas/Makefile.objs index abeba84..218e434 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -21,6 +21,7 @@ common-obj-$(CONFIG_S390_DIS) += s390.o common-obj-$(CONFIG_SH4_DIS) += sh4.o common-obj-$(CONFIG_SPARC_DIS) += sparc.o common-obj-$(CONFIG_LM32_DIS) += lm32.o +common-obj-$(CONFIG_AVR_DIS) += avr.o # TODO: As long as the TCG interpreter and its generated code depend # on the QEMU target, we cannot compile the disassembler here. diff --git a/disas/avr.c b/disas/avr.c new file mode 100644 index 000..f916e72 --- /dev/null +++ b/disas/avr.c @@ -0,0 +1,10 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "disas/bfd.h" + +int print_insn_avr(bfd_vma addr, disassemble_info *info) +{ +int length = 0;; +/* TODO*/ +return length; +} diff --git a/include/disas/bfd.h b/include/disas/bfd.h index a112e9c..04e2201 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -213,6 +213,12 @@ enum bfd_architecture #define bfd_mach_m32r 0 /* backwards compatibility */ bfd_arch_mn10200,/* Matsushita MN10200 */ bfd_arch_mn10300,/* Matsushita MN10300 */ + bfd_arch_avr, /* Atmel AVR microcontrollers. */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr3 3 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 bfd_arch_cris, /* Axis CRIS */ #define bfd_mach_cris_v0_v10 255 #define bfd_mach_cris_v32 32 @@ -415,6 +421,7 @@ int print_insn_crisv10 (bfd_vma, disassemble_info*); int print_insn_microblaze (bfd_vma, disassemble_info*); int print_insn_ia64 (bfd_vma, disassemble_info*); int print_insn_lm32 (bfd_vma, disassemble_info*); +int print_insn_avr (bfd_vma, disassemble_info*); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index d690dfa..8c75777 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -23,6 +23,7 @@ enum { QEMU_ARCH_UNICORE32 = (1 << 14), QEMU_ARCH_MOXIE = (1 << 15), QEMU_ARCH_TRICORE = (1 << 16), +QEMU_ARCH_AVR = (1 << 17), }; extern const uint32_t arch_type; diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs new file mode 100644 index 000..c503546 --- /dev/null +++ b/target-avr/Makefile.objs @@ -0,0 +1,3 @@ +obj-y += translate.o cp
[Qemu-devel] [PATCH 08/10] target-avr: adding instruction translation
Signed-off-by: Michael Rolnik --- 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 000..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 +*/ + +voidgen_add_CHf(TCGv R, TCGv Rd, TCGv Rr); +voidgen_add_Vf(TCGv R, TCGv Rd, TCGv Rr); +voidgen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr); +voidgen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr); +voidgen_ZNSf(TCGv R); +voidgen_push_ret(CPUAVRState *env, intret); +voidgen_pop_ret(CPUAVRState *env, TCGvret); +voidgen_jmp_ez(void); +voidgen_jmp_z(void); + +voidgen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv l); /* H:M:L = addr */ +voidgen_set_xaddr(TCGv addr); +voidgen_set_yaddr(TCGv addr); +voidgen_set_zaddr(TCGv addr); + +TCGvgen_get_addr(TCGv H, TCGv M, TCGv L);/* addr = H:M:L*/ +TCGvgen_get_xaddr(void); +TCGvgen_get_yaddr(void); +TCGvgen_get_zaddr(void); +int sex(int Imm, unsigned bits); + +voidgen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = tcg_temp_new_i32(); +TCGvt3 = 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); +} + +voidgen_add_Vf(TCGvR, TCGvRd, TCGvRr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = 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); +} + +voidgen_sub_CHf(TCGvR, TCGvRd, TCGvRr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = tcg_temp_new_i32(); +TCGvt3 = 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); +} + +voidgen_sub_Vf(TCGvR, TCGvRd, TCGvRr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = 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);
[Qemu-devel] [PATCH 05/10] target-avr: adding AVR interrupt handling
Signed-off-by: Michael Rolnik --- 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 @@ boolavr_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; + +boolret = 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; } voidavr_cpu_do_interrupt( CPUState *cs) { +AVRCPU *cpu = AVR_CPU(cs); +CPUAVRState*env = &cpu->env; + +uint32_tret = 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 & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +stb_phys(cs->as, env->sp--, (ret & 0xff) >> 16); + +env->pc = base + vector * size; +} else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); + +env->pc = base + vector * size; +} else { +stb_phys(cs->as, env->sp--, (ret & 0xff)); + +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)
[Qemu-devel] [PATCH 06/10] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
Signed-off-by: Michael Rolnik --- 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 @@ voidtlb_fill( tlb_set_page_with_attrs(cs, vaddr, paddr, attrs, prot, mmu_idx, page_size); } +voidhelper_sleep( +CPUAVRState*env) +{ +CPUState *cs = CPU(avr_env_get_cpu(env)); + +cs->exception_index = EXCP_HLT; +cpu_loop_exit(cs); +} +voidhelper_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); +} voidhelper_debug( CPUAVRState*env) @@ -165,3 +182,89 @@ voidhelper_debug( cpu_loop_exit(cs); } +voidhelper_wdr( +CPUAVRState*env) +{ +CPUState *cs = CPU(avr_env_get_cpu(env)); + +cs->exception_index = EXCP_DEBUG; +cpu_loop_exit(cs); +} + +target_ulonghelper_inb( +CPUAVRState*env, +uint32_tport) +{ +printf("in: io[%02x]\n", port); + +switch (port) { +case0x3b: { +return env->rampZ; /* RAMPZ */ +} +case0x3d: { /* SPL */ +return env->sp & 0x00ff; +} +case0x3e: { /* SPH */ +return env->sp >> 8; +} +case0x3f: { /* 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; +} + +voidhelper_outb( +CPUAVRState*env, +uint32_tport, +uint32_tdata) +{ +printf("out:%02x -> io[%02x]\n", data, port); + +data&= 0x00ff; + +switch (port) { +case0x04: { +qemu_irqirq; +CPUState *cpu = CPU(avr_env_get_cpu(env)); +irq = qdev_get_gpio_in(DEVICE(cpu), 3); +qemu_set_irq(irq, 1); +break; +} +case0x3b: { +env->rampZ = data & 0x01; /* RAMPZ */ +break; +} +case0x3d: { /* SPL */ +if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { +env->sp = (env->sp & 0xff00) | (data); +} +break; +} +case0x3e: { /* SPH */ +env->sp = (env->sp & 0x00ff) | (data << 8); +break; +} +case0x3f: { /* 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)
[Qemu-devel] [PATCH 02/10] target-avr: adding AVR CPU features/flavors
Signed-off-by: Michael Rolnik --- 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_tfeatures= 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);
[Qemu-devel] [PATCH 10/10] target-avr: fixing code style
Signed-off-by: Michael Rolnik --- 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 -voidavr_cpu_do_interrupt( -CPUState *cpu); -boolavr_cpu_exec_interrupt( -CPUState *cpu, -int int_req); -voidavr_cpu_dump_state( -CPUState *cs, -FILE *f, -fprintf_functioncpu_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*
[Qemu-devel] [PATCH 07/10] target-avr: adding instruction decoder
Signed-off-by: Michael Rolnik --- 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 000..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 +#include "translate.h" + + +uint32_tavr_decode(uint32_t pc, uint32_t *length, uint32_t code, translate_function_t *translate) +{ +uint32_topcode = extract32(code, 0, 16); +switch (opcode & 0xd000) { +case0x: { +uint32_topcode = extract32(code, 0, 16); +switch (opcode & 0x2c00) { +case0x: { +uint32_topcode = extract32(code, 0, 16); +switch (opcode & 0x0300) { +case0x: { +*length = 16; +*translate = (translate_function_t)&avr_translate_NOP; +break; +} +case0x0100: { +*length = 16; +*translate = (translate_function_t)&avr_translate_MOVW; +break; +} +case0x0200: { +*length = 16; +*translate = (translate_function_t)&avr_translate_MULS; +break; +} +case0x0300: { +uint32_topcode = extract32(code, 0, 16); +switch (opcode & 0x0088) { +case0x: { +*length = 16; +*translate = (translate_function_t)&avr_translate_MULSU; +break; +} +case0x0008: { +*length = 16; +*translate = (translate_function_t)&avr_translate_FMUL; +break; +} +case0x0080: { +*length = 16; +*translate = (translate_function_t)&avr_translate_FMULS; +break; +} +case0x0088: { +*length = 16; +*translate = (translate_function_t)&avr_translate_FMULSU; +break; +} +} +break; +} +} +break; +} +case0x0400: { +*length = 16; +*translate = (translate_function_t)&avr_translate_CPC; +break; +} +case0x0800: { +*length = 16; +*translate = (translate_function_t)&avr_translate_SBC; +break; +} +case0x0c00: { +*length = 16; +*translate = (translate_function_t)&avr_translate_ADD; +break; +} +case0x2000: { +*length = 16; +*translate = (translate_function_t)&avr_translate_AND; +break; +} +case0x2400: { +*length = 16; +*translate = (translate_function_t)&avr_translate_EOR; +break; +} +case0x2800: { +*length = 16; +
[Qemu-devel] [PATCH 03/10] target-avr: adding a sample AVR board
Signed-off-by: Michael Rolnik --- 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 000..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 000..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_SIZE0x0020 +#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_BASE0x +#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 { +SysBusDeviceparent; + +MemoryRegioniomem; + +AVRCPU *cpu; + +uint8_t io[0x40]; +uint8_t exio[0xa0]; +} SAMPLEIOState; + +static uint64_t sample_io_read( +void *opaque, +hwaddr offset, +unsignedsize); +static void sample_io_write(void *opaque, +hwaddr offset, +uint64_tvalue, +unsignedsize); +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 +Propertysample_io_properties
[Qemu-devel] [PATCH 09/10] target-avr: updating translate.c to use instructions translation
Signed-off-by: Michael Rolnik --- 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 @@ voidavr_translate_init(void) done_init = 1; } -static inline void gen_goto_tb(CPUAVRState*env, -DisasContext *ctx, -int n, -target_ulongdest) +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 & 0x; +} +if (inst->length == 32) { +inst->npc= inst->cpc + 2; +/* get opcode as 32bit value */ +inst->opcode = (inst->opcode << 16) + | (inst->opcode >> 16); } } +uint32_tget_opcode( +uint8_t const *code, +unsignedbitBase, +unsignedbitSize) +{ +return *(uint16_t *)code; +} + + /*generate intermediate code for basic block 'tb'. */ voidgen_intermediate_code( CPUAVRState
[Qemu-devel] [PATCH 04/10] target-avr: adding instructions encodings
Signed-off-by: Michael Rolnik --- 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 000..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 DisasContextDisasContext; + +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
[Qemu-devel] [PATCH 08/10] target-avr: adding instruction translation
Signed-off-by: Michael Rolnik --- 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 000..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 +*/ + +voidgen_add_CHf(TCGv R, TCGv Rd, TCGv Rr); +voidgen_add_Vf(TCGv R, TCGv Rd, TCGv Rr); +voidgen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr); +voidgen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr); +voidgen_ZNSf(TCGv R); +voidgen_push_ret(CPUAVRState *env, intret); +voidgen_pop_ret(CPUAVRState *env, TCGvret); +voidgen_jmp_ez(void); +voidgen_jmp_z(void); + +voidgen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv l); /* H:M:L = addr */ +voidgen_set_xaddr(TCGv addr); +voidgen_set_yaddr(TCGv addr); +voidgen_set_zaddr(TCGv addr); + +TCGvgen_get_addr(TCGv H, TCGv M, TCGv L);/* addr = H:M:L*/ +TCGvgen_get_xaddr(void); +TCGvgen_get_yaddr(void); +TCGvgen_get_zaddr(void); +int sex(int Imm, unsigned bits); + +voidgen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = tcg_temp_new_i32(); +TCGvt3 = 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); +} + +voidgen_add_Vf(TCGvR, TCGvRd, TCGvRr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = 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); +} + +voidgen_sub_CHf(TCGvR, TCGvRd, TCGvRr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = tcg_temp_new_i32(); +TCGvt3 = 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); +} + +voidgen_sub_Vf(TCGvR, TCGvRd, TCGvRr) +{ +TCGvt1 = tcg_temp_new_i32(); +TCGvt2 = 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);
[Qemu-devel] [PATCH 05/10] target-avr: adding AVR interrupt handling
Signed-off-by: Michael Rolnik --- 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 @@ boolavr_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; + +boolret = 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; } voidavr_cpu_do_interrupt( CPUState *cs) { +AVRCPU *cpu = AVR_CPU(cs); +CPUAVRState*env = &cpu->env; + +uint32_tret = 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 & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +stb_phys(cs->as, env->sp--, (ret & 0xff) >> 16); + +env->pc = base + vector * size; +} else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); + +env->pc = base + vector * size; +} else { +stb_phys(cs->as, env->sp--, (ret & 0xff)); + +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)
[Qemu-devel] AVR cores
This series of patches adds 8bit AVR cores to QEMU. All instruction, except BREAK/DES/SPM/SPMX, are implemented. Not fully tested yet. However I was able to execute simple code with functions. e.g fibonacci calculation. This series of patches include a non real, sample board. No fuses support yet. PC is set to 0 at reset. the patches include the following 1. just a basic 8bit AVR CPU, without instruction decoding or translation 2. CPU features which allow define the following 8bit AVR cores avr1 avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 xmega2 xmega4 xmega5 xmega6 xmega7 3. a difinition of sample machine with SRAM, FLASH and CPU which allows to execute simple code 4. encoding for all AVR instructions 5. interrupt handling 6. helpers for IN, OUT, SLEEP, WBR & unsupported instructions 7. a decoder which given an opcode decides what istruction it is 8. translation of AVR instruction into TCG 9. all features together
[Qemu-devel] [PATCH 2/9] target-avr: adding AVR CPU features/flavors
Signed-off-by: Michael Rolnik --- target-avr/cpu.c | 311 ++- target-avr/cpu.h | 59 +++ 2 files changed, 368 insertions(+), 2 deletions(-) diff --git a/target-avr/cpu.c b/target-avr/cpu.c index cfc1aee..97653c5 100644 --- a/target-avr/cpu.c +++ b/target-avr/cpu.c @@ -29,7 +29,7 @@ static void avr_cpu_set_pc(CPUState *cs, vaddr value) { 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(CPUState *cs) @@ -47,7 +47,7 @@ static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *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(CPUState *s) @@ -55,12 +55,14 @@ static void avr_cpu_reset(CPUState *s) 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); } @@ -187,6 +189,296 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) dc->cannot_destroy_with_object_finalize_yet = 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
[Qemu-devel] [PATCH 6/9] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
Signed-off-by: Michael Rolnik --- target-avr/helper.c | 117 +++- target-avr/helper.h | 5 +++ 2 files changed, 111 insertions(+), 11 deletions(-) diff --git a/target-avr/helper.c b/target-avr/helper.c index bb47a87..b93589a 100644 --- a/target-avr/helper.c +++ b/target-avr/helper.c @@ -31,7 +31,7 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { -CPUClass*cc = CPU_GET_CLASS(cs); +CPUClass*cc = CPU_GET_CLASS(cs); AVRCPU *cpu = AVR_CPU(cs); CPUAVRState *env = &cpu->env; @@ -49,7 +49,7 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } if (interrupt_request & CPU_INTERRUPT_HARD) { if (cpu_interrupts_enabled(env) && env->intsrc != 0) { -int index = __builtin_ffs(env->intsrc) - 1; +int index = __builtin_ffs(env->intsrc) - 1; cs->exception_index = EXCP_INT(index); cc->do_interrupt(cs); @@ -64,18 +64,18 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) void avr_cpu_do_interrupt(CPUState *cs) { -AVRCPU *cpu = AVR_CPU(cs); -CPUAVRState*env = &cpu->env; +AVRCPU *cpu = AVR_CPU(cs); +CPUAVRState *env = &cpu->env; -uint32_tret = env->pc; -int vector; -int size= avr_feature(env, AVR_FEATURE_JMP_CALL) ? 2 : 1; -int base= 0;/* TODO: where to get it */ +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; +vector = 0; } else if (env->intsrc != 0) { -vector = __builtin_ffs(env->intsrc); +vector = __builtin_ffs(env->intsrc); } if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { @@ -95,7 +95,7 @@ void avr_cpu_do_interrupt(CPUState *cs) env->pc = base + vector * size; } -env->sregI = 0;/* clear Global Interrupt Flag */ +env->sregI = 0;/* clear Global Interrupt Flag */ cs->exception_index = -1; } @@ -136,6 +136,21 @@ void tlb_fill(CPUState *cs, target_ulong vaddr, int is_write, int mmu_idx, uintp 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) { @@ -145,3 +160,83 @@ void helper_debug(CPUAVRState *env) 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) { +case0x3b: { +return env->rampZ; /* RAMPZ */ +} +case0x3d: { /* SPL */ +return env->sp & 0x00ff; +} +case0x3e: { /* SPH */ +return env->sp >> 8; +} +case0x3f: { /* 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&= 0x00ff; + +switch (port) { +case0x04: { +qemu_irqirq; +CPUState *cpu = CPU(avr_env_get_cpu(env)); +irq = qdev_get_gpio_in(DEVICE(cpu), 3); +qemu_set_irq(irq, 1); +break; +} +case0x3b: { +env->rampZ = data & 0x01; /* RAMPZ */ +break; +} +case0x3d: { /* SPL */ +if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { +env->sp = (env->sp & 0xff00) | (data); +} +break; +} +case0x3e: {
[Qemu-devel] [PATCH 7/9] target-avr: adding instruction decoder
Signed-off-by: Michael Rolnik --- 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 000..b846f1d --- /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 +#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 & 0xd000) { +case0x: { +uint32_t opcode = extract32(code, 0, 16); +switch (opcode & 0x2c00) { +case0x: { +uint32_t opcode = extract32(code, 0, 16); +switch (opcode & 0x0300) { +case0x: { +*length = 16; +*translate = &avr_translate_NOP; +break; +} +case0x0100: { +*length = 16; +*translate = &avr_translate_MOVW; +break; +} +case0x0200: { +*length = 16; +*translate = &avr_translate_MULS; +break; +} +case0x0300: { +uint32_t opcode = extract32(code, 0, 16); +switch (opcode & 0x0088) { +case0x: { +*length = 16; +*translate = &avr_translate_MULSU; +break; +} +case0x0008: { +*length = 16; +*translate = &avr_translate_FMUL; +break; +} +case0x0080: { +*length = 16; +*translate = &avr_translate_FMULS; +break; +} +case0x0088: { +*length = 16; +*translate = &avr_translate_FMULSU; +break; +} +} +break; +} +} +break; +} +case0x0400: { +*length = 16; +*translate = &avr_translate_CPC; +break; +} +case0x0800: { +*length = 16; +*translate = &avr_translate_SBC; +break; +} +case0x0c00: { +*length = 16; +*translate = &avr_translate_ADD; +break; +} +case0x2000: { +*length = 16; +*translate = &avr_translate_AND; +break; +} +case0x2400: { +*length = 16; +*translate = &avr_translate_EOR; +break; +} +case0x2800: { +*length = 16; +*translate = &avr_translate_OR; +break; +} +case0x2c00: { +*length = 16; +*translate = &avr_translate_MOV; +break; +} +} +break;
[Qemu-devel] [PATCH 3/9] target-avr: adding a sample AVR board
Signed-off-by: Michael Rolnik --- hw/Makefile.objs | 1 + hw/avr/Makefile.objs | 1 + hw/avr/sample-io.c | 217 +++ hw/avr/sample.c | 118 4 files changed, 337 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 000..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 000..7bf5e48 --- /dev/null +++ b/hw/avr/sample-io.c @@ -0,0 +1,217 @@ +/* + * 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_SIZE0x0020 +#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_BASE0x +#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 { +SysBusDeviceparent; + +MemoryRegioniomem; + +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 +Propertysample_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_tsample_io_read(void *opaque, hwaddr offset, unsigned size) +{ +SAMPLEIOState *s = SAMPLEIO(opaque); +AVRCPU *cpu = s->cpu; +CPUAVRState *env = &cpu->env; +ui
[Qemu-devel] [PATCH 1/9] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions
Signed-off-by: Michael Rolnik --- arch_init.c | 2 + configure | 5 + default-configs/avr-softmmu.mak | 1 + disas/Makefile.objs | 1 + disas/avr.c | 10 ++ include/disas/bfd.h | 7 + include/sysemu/arch_init.h | 1 + target-avr/Makefile.objs| 3 + target-avr/cpu-qom.h| 80 +++ target-avr/cpu.c| 288 target-avr/cpu.h| 123 + target-avr/gdbstub.c| 99 ++ target-avr/helper.c | 85 target-avr/helper.h | 21 +++ target-avr/machine.c| 54 target-avr/machine.h| 21 +++ target-avr/translate.c | 288 17 files changed, 1089 insertions(+) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 disas/avr.c create mode 100644 target-avr/Makefile.objs create mode 100644 target-avr/cpu-qom.h create mode 100644 target-avr/cpu.c create mode 100644 target-avr/cpu.h create mode 100644 target-avr/gdbstub.c create mode 100644 target-avr/helper.c create mode 100644 target-avr/helper.h create mode 100644 target-avr/machine.c create mode 100644 target-avr/machine.h create mode 100644 target-avr/translate.c diff --git a/arch_init.c b/arch_init.c index fa05973..be6e6de 100644 --- a/arch_init.c +++ b/arch_init.c @@ -80,6 +80,8 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_TRICORE) #define QEMU_ARCH QEMU_ARCH_TRICORE +#elif defined(TARGET_AVR) +#define QEMU_ARCH QEMU_ARCH_AVR #endif const uint32_t arch_type = QEMU_ARCH; diff --git a/configure b/configure index b5aab72..90af399 100755 --- a/configure +++ b/configure @@ -5630,6 +5630,8 @@ case "$target_name" in x86_64) TARGET_BASE_ARCH=i386 ;; + avr) + ;; alpha) ;; arm|armeb) @@ -5826,6 +5828,9 @@ disas_config() { for i in $ARCH $TARGET_BASE_ARCH ; do case "$i" in + avr) +disas_config "AVR" + ;; alpha) disas_config "ALPHA" ;; diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak new file mode 100644 index 000..ca94aad --- /dev/null +++ b/default-configs/avr-softmmu.mak @@ -0,0 +1 @@ +# Default configuration for avr-softmmu diff --git a/disas/Makefile.objs b/disas/Makefile.objs index abeba84..218e434 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -21,6 +21,7 @@ common-obj-$(CONFIG_S390_DIS) += s390.o common-obj-$(CONFIG_SH4_DIS) += sh4.o common-obj-$(CONFIG_SPARC_DIS) += sparc.o common-obj-$(CONFIG_LM32_DIS) += lm32.o +common-obj-$(CONFIG_AVR_DIS) += avr.o # TODO: As long as the TCG interpreter and its generated code depend # on the QEMU target, we cannot compile the disassembler here. diff --git a/disas/avr.c b/disas/avr.c new file mode 100644 index 000..f916e72 --- /dev/null +++ b/disas/avr.c @@ -0,0 +1,10 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "disas/bfd.h" + +int print_insn_avr(bfd_vma addr, disassemble_info *info) +{ +int length = 0;; +/* TODO*/ +return length; +} diff --git a/include/disas/bfd.h b/include/disas/bfd.h index a112e9c..04e2201 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -213,6 +213,12 @@ enum bfd_architecture #define bfd_mach_m32r 0 /* backwards compatibility */ bfd_arch_mn10200,/* Matsushita MN10200 */ bfd_arch_mn10300,/* Matsushita MN10300 */ + bfd_arch_avr, /* Atmel AVR microcontrollers. */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr3 3 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 bfd_arch_cris, /* Axis CRIS */ #define bfd_mach_cris_v0_v10 255 #define bfd_mach_cris_v32 32 @@ -415,6 +421,7 @@ int print_insn_crisv10 (bfd_vma, disassemble_info*); int print_insn_microblaze (bfd_vma, disassemble_info*); int print_insn_ia64 (bfd_vma, disassemble_info*); int print_insn_lm32 (bfd_vma, disassemble_info*); +int print_insn_avr (bfd_vma, disassemble_info*); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index d690dfa..8c75777 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -23,6 +23,7 @@ enum { QEMU_ARCH_UNICORE32 = (1 << 14), QEMU_ARCH_MOXIE = (1 << 15), QEMU_ARCH_TRICORE = (1 << 16), +QEMU_ARCH_AVR = (1 << 17), }; extern const uint32_t arch_type; diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs new file mode 100644 index 000..c503546 --- /dev/null +++ b/target-avr/Makefile.objs @@ -0,0 +1,3 @@ +obj-y += translate.o cpu.o
[Qemu-devel] [PATCH 5/9] target-avr: adding AVR interrupt handling
Signed-off-by: Michael Rolnik --- 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 fbab91d..bb47a87 100644 --- a/target-avr/helper.c +++ b/target-avr/helper.c @@ -31,11 +31,73 @@ 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; + +boolret = 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_tret = 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 & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +stb_phys(cs->as, env->sp--, (ret & 0xff) >> 16); + +env->pc = base + vector * size; +} else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); + +env->pc = base + vector * size; +} else { +stb_phys(cs->as, env->sp--, (ret & 0xff)); + +env->pc = base + vector * size; +} + +env->sregI = 0;/* clear Global Interrupt Flag */ + +cs->exception_index = -1; } int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, int len, bool is_write) -- 2.4.9 (Apple Git-60)
[Qemu-devel] [PATCH 4/9] target-avr: adding instructions encodings
Signed-off-by: Michael Rolnik --- 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 000..0fad30f --- /dev/null +++ b/target-avr/translate-inst.h @@ -0,0 +1,838 @@ + +#ifndef AVR_TRANSLATE_INST_H_ +#define AVR_TRANSLATE_INST_H_ + +typedef struct DisasContextDisasContext; + +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
[Qemu-devel] [PATCH 9/9] target-avr: updating translate.c to use instructions translation
Signed-off-by: Michael Rolnik --- target-avr/Makefile.objs | 4 +- target-avr/translate.c | 132 --- 2 files changed, 59 insertions(+), 77 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 029cffa..228ee90 100644 --- a/target-avr/translate.c +++ b/target-avr/translate.c @@ -18,60 +18,30 @@ * <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,24 +90,27 @@ 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 & 0x; +} +if (inst->length == 32) { +inst->npc = inst->cpc + 2; +/* get opcode as 32bit value */ +inst->opcode = (inst->opcode << 16) + | (inst->opcode >> 16); } } @@ -171,18 +144,21 @@ void gen_intermediate_code(CPUAVRState *env, struct TranslationBlock *tb) 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++
[Qemu-devel] [PATCH 8/9] target-avr: adding instruction translation
Signed-off-by: Michael Rolnik --- target-avr/translate-inst.c | 2511 +++ target-avr/translate.h | 123 +++ 2 files changed, 2634 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 000..b890cd1 --- /dev/null +++ b/target-avr/translate-inst.c @@ -0,0 +1,2511 @@ +/* + * 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, TCGvRd, TCGvRr) +{ +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, TCGvRd, TCGvRr) +{ +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, TCGvRd, TCGvRr) +{ +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
Re: [Qemu-devel] [PATCH 10/10] target-avr: fixing code style
understood. but I am totally lost now. what should I do now. I've sent a set of patches last Friday, they should include all the fixes. Michael On Sat, Jun 4, 2016 at 8:41 PM, Richard Henderson wrote: > On 06/02/2016 04:10 PM, Peter Maydell wrote: > >> PS: it would be good if you could provide a cover letter when >> you send out the next round of these patches; that provides >> a handy way to deal with the series as a whole (for both >> automated tools and people), so we tend to prefer multi-patch >> sets to have one. >> > > In addition, use --subject-prefix="PATCH vN" so that we know which patch > set is newest. > > Also, do not send follow-up patch sets as replies to earlier patch sets. > Doing this means that patch sets get lost. > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH 04/10] target-avr: adding instructions encodings
1. The code was generated. Every instruction has its own extractors. there are several reasons 1. I don't have to think and gather the instructions into the group. 2. I don't have to remember what group an instruction is in 3. there is no performance penalty. 2. done. On Sun, Jun 5, 2016 at 1:17 AM, Richard Henderson wrote: > On 06/02/2016 01:06 PM, Michael Rolnik wrote: > >> Signed-off-by: Michael Rolnik >> --- >> 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 000..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 DisasContextDisasContext; >> + >> +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); >> +} >> > > Any particular reason you're replicating all this logic for every > instruction, as opposed to finding some commonalty between them? There > aren't *that* many different operand field types. > > Glancing through the binutils source, I count 13. Although I might have > missed a handful, it's still an order of magnitude less than your 159 > functions. > > +static inline uint32_t CPC_lRr(uint32_t opcode) >> +{ >> +return extract32(opcode, 0, 4); >> +} >> > ... > >> +static inline uint32_t CPC_hRr(uint32_t opcode) >> +{ >> +return extract32(opcode, 9, 1); >> +} >> > > Any reason you're not simplifying the logic elsewhere by extracting the > logical value, as opposed to the parts of the split value. I.e. > > (extract32(opcode, 9, 1) << 4) | extract32(opcode, 0, 4) > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH 06/10] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
switched to qemu_log. it will be removed after a while. On Sun, Jun 5, 2016 at 1:48 AM, Richard Henderson wrote: > On 06/02/2016 01:06 PM, Michael Rolnik wrote: > >> +voidhelper_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); >> +} >> > ... > >> +voidhelper_wdr( >> +CPUAVRState*env) >> +{ >> +CPUState *cs = CPU(avr_env_get_cpu(env)); >> + >> +cs->exception_index = EXCP_DEBUG; >> +cpu_loop_exit(cs); >> +} >> > > Surely EXCP_DEBUG isn't the right thing to be using for these. > > +target_ulonghelper_inb( >> +CPUAVRState*env, >> +uint32_tport) >> +{ >> +printf("in: io[%02x]\n", port); >> > > No printf. > > If you like you can use qemu_log, but for something like this, probably > the most useful is the tracing infrastructure. See the trace-events file. > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH 05/10] target-avr: adding AVR interrupt handling
fixed. On Sun, Jun 5, 2016 at 1:26 AM, Richard Henderson wrote: > On 06/02/2016 01:06 PM, Michael Rolnik wrote: > >> +} else if (env->intsrc != 0) { >> +vector = __builtin_ffs(env->intsrc); >> +} >> > > Use either ffs (no __builtin) or, preferably, ctz32 from qemu/host-utils.h. > > +env->pc = base + vector * size; >> +env->pc = base + vector * size; >> +env->pc = base + vector * size; >> > > No point replicating this 3 times. > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH 07/10] target-avr: adding instruction decoder
1. no more custings. 2. yes, it is generated code. I would like to commit the generator. however it is not very ripe yet. and it has a dependency on yaml-cpp and xsltproc. 3. the generator does not assume that same bits are extracted. it will be fixed later. 4. 0 is no longer returned. On Sun, Jun 5, 2016 at 2:00 AM, Richard Henderson wrote: > On 06/02/2016 01:06 PM, Michael Rolnik wrote: > >> +uint32_tavr_decode(uint32_t pc, uint32_t *length, uint32_t code, >> translate_function_t *translate) >> +{ >> +uint32_topcode = extract32(code, 0, 16); >> +switch (opcode & 0xd000) { >> +case0x: { >> +uint32_topcode = extract32(code, 0, 16); >> +switch (opcode & 0x2c00) { >> +case0x: { >> +uint32_topcode = extract32(code, 0, 16); >> > > Why do you keep extracting the same value into variables that shadow each > other? > > I can only assume that this is machine-generated code. Is there any > reason that you want to commit the quite unreadable generated code instead > of the original input and generator? > > +*translate = >> (translate_function_t)&avr_translate_NOP; >> > > The casts are, in this and other cases, unnecessary, and could easily mask > a real problem. > > +return 0; >> > > Since you only ever return 0, what's the point of the return value? > > > r~ > > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH 08/10] target-avr: adding instruction translation
please see my answer inside. On Sun, Jun 5, 2016 at 6:27 AM, Richard Henderson wrote: > On 06/02/2016 01:07 PM, Michael Rolnik wrote: > >> Signed-off-by: Michael Rolnik >> --- >> target-avr/translate-inst.c | 2443 >> +++ >> > > Is there a reason this code isn't going into translate.c? > You wouldn't need the declarations in translate-inst.h or translate.h. I see here two levels of logic a. instruction translation b. general flow of program translation. > > > +/* >> +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 >> +*/ >> > > This documentation belongs with the declarations in cpu.h. moved. > > > +voidgen_add_CHf(TCGv R, TCGv Rd, TCGv Rr); >> +voidgen_add_Vf(TCGv R, TCGv Rd, TCGv Rr); >> +voidgen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr); >> +voidgen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr); >> +voidgen_ZNSf(TCGv R); >> +voidgen_push_ret(CPUAVRState *env, intret); >> +voidgen_pop_ret(CPUAVRState *env, TCGvret); >> +voidgen_jmp_ez(void); >> +voidgen_jmp_z(void); >> + >> +voidgen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv l); /* H:M:L = >> addr */ >> +voidgen_set_xaddr(TCGv addr); >> +voidgen_set_yaddr(TCGv addr); >> +voidgen_set_zaddr(TCGv addr); >> + >> +TCGvgen_get_addr(TCGv H, TCGv M, TCGv L);/* addr = >> H:M:L*/ >> +TCGvgen_get_xaddr(void); >> +TCGvgen_get_yaddr(void); >> +TCGvgen_get_zaddr(void); >> +int sex(int Imm, unsigned bits); >> > > Order these functions properly and you don't need forward declarations. is it a requirements? this way it look cleaner. > > > + >> +voidgen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) >> +{ >> +TCGvt1 = tcg_temp_new_i32(); >> +TCGvt2 = tcg_temp_new_i32(); >> +TCGvt3 = 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_andc_tl. thanks > > > +tcg_gen_not_tl(t3, R); /* t3 = Rr *~R */ >> +tcg_gen_and_tl(t3, Rr, t3); >> > > Likewise. thanks > > > +tcg_gen_or_tl(t1, t1, t2);/* t1 = t1 | t2 | t3 */ >> +tcg_gen_or_tl(t1, t1, t3); >> > > While this is exactly the formula in the manual, it's also equal to > > ((Rd ^ Rr) ^ R) & 16 > Please explain. I don't see it. http://www.wolframalpha.com/input/?i=A+and+B+or+A+and+not+C+or+B+and+not+C,+A+xor+B+xor+C > > > where we examine the difference between the non-carry addition (Rd ^ Rr) > and the carry addition (R) to find the carry out of bit 3. This reduces > the operation count to 2 from 5. > > +tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */ >> > > Of course, Cf is also bit 8 of R, at least before you masked that off. > > +tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */ >> +tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); >> > > Consider leaving Hf in bit 3 (or 4, as above) instead of shifting and > masking to bit 0. This makes it (slightly) more complicated to read the > full SREG value, but it saves two instructions per arithmetic instruction. > This will add up quickly. > yes you are right. next version. > > One can make the same argument for most of the other flags. > > Compare how this is handled in target-arm for cpu_[NZCV]F. > > +voidgen_add_Vf(TCGvR, TCGvRd, TCGvRr) >> +{ >> +TCGvt1 = tcg_temp_new_i32(); >> +TCGvt2 = 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 */ >> > > While this is indeed the formula in the manual, a better expression is > > (R ^ Rd) & ~
Re: [Qemu-devel] [PATCH 09/10] target-avr: updating translate.c to use instructions translation
get_opcode no longer present. I use it for the sake of skip instruction. I do not know a priori the length of the next instruction as it can be either 16 or 32 bits. On Sun, Jun 5, 2016 at 6:33 AM, Richard Henderson wrote: > On 06/02/2016 01:07 PM, Michael Rolnik wrote: > >> +uint32_tget_opcode( >> +uint8_t const *code, >> +unsignedbitBase, >> +unsignedbitSize) >> +{ >> +return *(uint16_t *)code; >> +} >> > > Unused. And what was this supposed to do? > > +/* decode next instruction */ >> +ctx.inst[1].cpc = ctx.inst[0].npc; >> +decode_opc(cpu, &ctx, &ctx.inst[1]); >> > > Why are you decoding one instruction ahead? > > While I can see that this might be keen for some of the skip-next > instructions, I don't see that you're using that just now. So perhaps > delay this until it's actually used? > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH 08/10] target-avr: adding instruction translation
On Mon, Jun 6, 2016 at 2:34 AM, Richard Henderson wrote: > On 06/05/2016 02:47 PM, Michael Rolnik wrote: > >> Is there a reason this code isn't going into translate.c? >> You wouldn't need the declarations in translate-inst.h or translate.h. >> >> I see here two levels of logic >> a. instruction translation >> b. general flow of program translation. >> > > FWIW, static functions can be automatically inlined by the compiler, > whereas external function calls can't. In theory, the compiler could > auto-inline the entire translator into a single function. these functions are called through pointer so there is no way for these functions to be inlined. > > > Order these functions properly and you don't need forward declarations. >> >> is it a requirements? this way it look cleaner. >> > > Does it? In my experience it just means you've got to edit two places > when one changes things. It still one place because it's either instruction translation or a program translation. from my point of view translate.c will have almost no bugs in very close feature whereas translate-inst.c will hove bug fixes and modification. having it in two files will isolate translate.c from erroneous modifications. > > > While this is exactly the formula in the manual, it's also equal to >> >> ((Rd ^ Rr) ^ R) & 16 >> >> Please explain. I don't see it. >> >> >> http://www.wolframalpha.com/input/?i=A+and+B+or+A+and+not+C+or+B+and+not+C,+A+xor+B+xor+C >> > > I did explain: truth table shows that these computations are different. > > > where we examine the difference between the non-carry addition (Rd ^ >> Rr) >> and the carry addition (R) to find the carry out of bit 3. This >> reduces >> the operation count to 2 from 5. >> > > It's not a manipulation of the original expression, but a different way of > looking at the problem. > > You want to compute carry-out of bit 3. Given the *result* of the > addition, it's easier to examine bit 4, into which carry-in has happened, > rather than examine bit 3 and re-compute the carry-out. > > The AVR hardware probably computes it exactly as described in the manual, > because that can be done in parallel with the addition, and has a lower > total gate latency. This is fairly common in the industry, where the > documentation follows the implementation more closely than it perhaps > should. you can't look onto 4th bit because 4th bits in the input were not 0s. > > > Note that carry and borrow are related, and thus this is *also* >> computable >> via ((Rd ^ Rr) ^ R) on bit 4. >> >> please explain, I don't see it >> >> http://www.wolframalpha.com/input/?i=not+A+and+B+or+not+A+and+C+or++C+and+B,+A+xor+B+xor+C >> > > As above, given the *result* of the subtraction, examining bit 4 into > which borrow-in has happened. > > Once you accept that, you'll note that the same expression can be used to > re-create both carry-in and borrow-in. > > I'll also note that the piece-wise store is big-endian, so you could >> perform this in 1 store for 2_BYTE and 2 stores for 3_BYTE. >> >> I got an expression that the platform is little endian. >> > > Then you've got the order of the stores wrong. Your code pushes the LSB > before pushing the MSB, which results in the MSB at the lower address, > which means big-endian. this is right. However as far as I understand AVR is neither little nor big endian because there it's 8 bit architecture (see here http://www.avrfreaks.net/forum/endian-issue). for time being I defined the platform to be little endian with ret address exception > > > Wow. Um... Surely it would be better to store X and Y internally as >> whole >> 24-bit quantities, and Z as a 16-bit quantity (to be extended with >> rampz, >> rampd, or eind as needed). >> >> rampX/Y/Z are represented now as 0x00ff. >> X/Y/Z can be represented as 16 bits registers, however I do not know if >> and >> when r26-r31 are used as 8 bits, so if X/Y/Z are represented as 16 bits it >> would be hard to use r26-r31 in arithmetics >> > > You would use a setup like the following, and use these functions instead > of other direct accesses to the cpu registers. This setup requires similar > functions in cpu.h for use by e.g. gdbstub.c. > I will have to think about it. > > > TCGv cpu_rb[24]; > TCGv cpu_rw[4]; > > TCGv read_byte(unsigned rb) > { > TCGv byte = tcg_temp_new(); > if (rb < 24) { > tcg_
[Qemu-devel] [PATCH v4 0/9] 8bit AVR cores
This series of patches adds 8bit AVR cores to QEMU. All instruction, except BREAK/DES/SPM/SPMX, are implemented. Not fully tested yet. However I was able to execute simple code with functions. e.g fibonacci calculation. This series of patches include a non real, sample board. No fuses support yet. PC is set to 0 at reset. the patches include the following 1. just a basic 8bit AVR CPU, without instruction decoding or translation 2. CPU features which allow define the following 8bit AVR cores avr1 avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 xmega2 xmega4 xmega5 xmega6 xmega7 3. a definition of sample machine with SRAM, FLASH and CPU which allows to execute simple code 4. encoding for all AVR instructions 5. interrupt handling 6. helpers for IN, OUT, SLEEP, WBR & unsupported instructions 7. a decoder which given an opcode decides what istruction it is 8. translation of AVR instruction into TCG 9. all features together changes since v3 1. rampD/X/Y/Z registers are encoded as 0x00ff and not 0x00ff for faster address manipulaton 2. ffs changed to ctz32 3. duplicate code removed at avr_cpu_do_interrupt 4. using andc instead of not + and 5. fixing V flag calculation in varios instructions 6. freeing local variables in PUSH 7. tcg_const_local_i32 -> tcg_const_i32 8. using sextract32 instead of my implementation 9. fixing BLD instruction 10.xor(r) instead of 0xff - r at COM 11.fixing MULS/MULSU not to modify inputs' content 12.using SUB for NEG 13.fixing tcg_gen_qemu_ld/st call in XCH A big thanks to Richard Henderson for the review. Michael Rolnik (9): target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions target-avr: adding AVR CPU features/flavors target-avr: adding a sample AVR board target-avr: adding instructions encodings target-avr: adding AVR interrupt handling target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions target-avr: adding instruction decoder target-avr: adding instruction translation target-avr: updating translate.c to use instructions translation arch_init.c |2 + configure |5 + default-configs/avr-softmmu.mak |1 + disas/Makefile.objs |1 + disas/avr.c | 10 + hw/Makefile.objs|1 + hw/avr/Makefile.objs|1 + hw/avr/sample-io.c | 217 hw/avr/sample.c | 118 ++ include/disas/bfd.h |7 + include/sysemu/arch_init.h |1 + target-avr/Makefile.objs|5 + target-avr/cpu-qom.h| 80 ++ target-avr/cpu.c| 595 ++ target-avr/cpu.h| 193 +++ target-avr/decode.c | 724 target-avr/gdbstub.c| 99 ++ target-avr/helper.c | 273 + target-avr/helper.h | 26 + target-avr/machine.c| 54 + target-avr/machine.h| 21 + target-avr/translate-inst.c | 2499 +++ target-avr/translate-inst.h | 730 target-avr/translate.c | 268 + target-avr/translate.h | 120 ++ 25 files changed, 6051 insertions(+) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 disas/avr.c create mode 100644 hw/avr/Makefile.objs create mode 100644 hw/avr/sample-io.c create mode 100644 hw/avr/sample.c create mode 100644 target-avr/Makefile.objs create mode 100644 target-avr/cpu-qom.h create mode 100644 target-avr/cpu.c create mode 100644 target-avr/cpu.h create mode 100644 target-avr/decode.c create mode 100644 target-avr/gdbstub.c create mode 100644 target-avr/helper.c create mode 100644 target-avr/helper.h create mode 100644 target-avr/machine.c create mode 100644 target-avr/machine.h create mode 100644 target-avr/translate-inst.c create mode 100644 target-avr/translate-inst.h create mode 100644 target-avr/translate.c create mode 100644 target-avr/translate.h -- 2.4.9 (Apple Git-60)
[Qemu-devel] [PATCH v4 1/9] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions
Signed-off-by: Michael Rolnik --- arch_init.c | 2 + configure | 5 + default-configs/avr-softmmu.mak | 1 + disas/Makefile.objs | 1 + disas/avr.c | 10 ++ include/disas/bfd.h | 7 + include/sysemu/arch_init.h | 1 + target-avr/Makefile.objs| 3 + target-avr/cpu-qom.h| 80 +++ target-avr/cpu.c| 288 target-avr/cpu.h| 134 +++ target-avr/gdbstub.c| 99 ++ target-avr/helper.c | 85 target-avr/helper.h | 21 +++ target-avr/machine.c| 54 target-avr/machine.h| 21 +++ target-avr/translate.c | 288 17 files changed, 1100 insertions(+) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 disas/avr.c create mode 100644 target-avr/Makefile.objs create mode 100644 target-avr/cpu-qom.h create mode 100644 target-avr/cpu.c create mode 100644 target-avr/cpu.h create mode 100644 target-avr/gdbstub.c create mode 100644 target-avr/helper.c create mode 100644 target-avr/helper.h create mode 100644 target-avr/machine.c create mode 100644 target-avr/machine.h create mode 100644 target-avr/translate.c diff --git a/arch_init.c b/arch_init.c index fa05973..be6e6de 100644 --- a/arch_init.c +++ b/arch_init.c @@ -80,6 +80,8 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_TRICORE) #define QEMU_ARCH QEMU_ARCH_TRICORE +#elif defined(TARGET_AVR) +#define QEMU_ARCH QEMU_ARCH_AVR #endif const uint32_t arch_type = QEMU_ARCH; diff --git a/configure b/configure index b5aab72..90af399 100755 --- a/configure +++ b/configure @@ -5630,6 +5630,8 @@ case "$target_name" in x86_64) TARGET_BASE_ARCH=i386 ;; + avr) + ;; alpha) ;; arm|armeb) @@ -5826,6 +5828,9 @@ disas_config() { for i in $ARCH $TARGET_BASE_ARCH ; do case "$i" in + avr) +disas_config "AVR" + ;; alpha) disas_config "ALPHA" ;; diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak new file mode 100644 index 000..ca94aad --- /dev/null +++ b/default-configs/avr-softmmu.mak @@ -0,0 +1 @@ +# Default configuration for avr-softmmu diff --git a/disas/Makefile.objs b/disas/Makefile.objs index abeba84..218e434 100644 --- a/disas/Makefile.objs +++ b/disas/Makefile.objs @@ -21,6 +21,7 @@ common-obj-$(CONFIG_S390_DIS) += s390.o common-obj-$(CONFIG_SH4_DIS) += sh4.o common-obj-$(CONFIG_SPARC_DIS) += sparc.o common-obj-$(CONFIG_LM32_DIS) += lm32.o +common-obj-$(CONFIG_AVR_DIS) += avr.o # TODO: As long as the TCG interpreter and its generated code depend # on the QEMU target, we cannot compile the disassembler here. diff --git a/disas/avr.c b/disas/avr.c new file mode 100644 index 000..f916e72 --- /dev/null +++ b/disas/avr.c @@ -0,0 +1,10 @@ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "disas/bfd.h" + +int print_insn_avr(bfd_vma addr, disassemble_info *info) +{ +int length = 0;; +/* TODO*/ +return length; +} diff --git a/include/disas/bfd.h b/include/disas/bfd.h index a112e9c..04e2201 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -213,6 +213,12 @@ enum bfd_architecture #define bfd_mach_m32r 0 /* backwards compatibility */ bfd_arch_mn10200,/* Matsushita MN10200 */ bfd_arch_mn10300,/* Matsushita MN10300 */ + bfd_arch_avr, /* Atmel AVR microcontrollers. */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr3 3 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 bfd_arch_cris, /* Axis CRIS */ #define bfd_mach_cris_v0_v10 255 #define bfd_mach_cris_v32 32 @@ -415,6 +421,7 @@ int print_insn_crisv10 (bfd_vma, disassemble_info*); int print_insn_microblaze (bfd_vma, disassemble_info*); int print_insn_ia64 (bfd_vma, disassemble_info*); int print_insn_lm32 (bfd_vma, disassemble_info*); +int print_insn_avr (bfd_vma, disassemble_info*); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index d690dfa..8c75777 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -23,6 +23,7 @@ enum { QEMU_ARCH_UNICORE32 = (1 << 14), QEMU_ARCH_MOXIE = (1 << 15), QEMU_ARCH_TRICORE = (1 << 16), +QEMU_ARCH_AVR = (1 << 17), }; extern const uint32_t arch_type; diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs new file mode 100644 index 000..c503546 --- /dev/null +++ b/target-avr/Makefile.objs @@ -0,0 +1,3 @@ +obj-y += translate.o cp
[Qemu-devel] [PATCH v4 2/9] target-avr: adding AVR CPU features/flavors
Signed-off-by: Michael Rolnik --- target-avr/cpu.c | 311 ++- target-avr/cpu.h | 59 +++ 2 files changed, 368 insertions(+), 2 deletions(-) diff --git a/target-avr/cpu.c b/target-avr/cpu.c index cfc1aee..97653c5 100644 --- a/target-avr/cpu.c +++ b/target-avr/cpu.c @@ -29,7 +29,7 @@ static void avr_cpu_set_pc(CPUState *cs, vaddr value) { 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(CPUState *cs) @@ -47,7 +47,7 @@ static void avr_cpu_synchronize_from_tb(CPUState *cs, TranslationBlock *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(CPUState *s) @@ -55,12 +55,14 @@ static void avr_cpu_reset(CPUState *s) 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); } @@ -187,6 +189,296 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) dc->cannot_destroy_with_object_finalize_yet = 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
[Qemu-devel] [PATCH v4 3/9] target-avr: adding a sample AVR board
Signed-off-by: Michael Rolnik --- hw/Makefile.objs | 1 + hw/avr/Makefile.objs | 1 + hw/avr/sample-io.c | 217 +++ hw/avr/sample.c | 118 4 files changed, 337 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 000..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 000..7bf5e48 --- /dev/null +++ b/hw/avr/sample-io.c @@ -0,0 +1,217 @@ +/* + * 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_SIZE0x0020 +#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_BASE0x +#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 { +SysBusDeviceparent; + +MemoryRegioniomem; + +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 +Propertysample_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_tsample_io_read(void *opaque, hwaddr offset, unsigned size) +{ +SAMPLEIOState *s = SAMPLEIO(opaque); +AVRCPU *cpu = s->cpu; +CPUAVRState *env = &cpu->env; +ui
[Qemu-devel] [PATCH v4 5/9] target-avr: adding AVR interrupt handling
Signed-off-by: Michael Rolnik --- target-avr/helper.c | 59 - 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/target-avr/helper.c b/target-avr/helper.c index fbab91d..e798dd9 100644 --- a/target-avr/helper.c +++ b/target-avr/helper.c @@ -31,11 +31,68 @@ 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; + +boolret = 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 = ctz32(env->intsrc); +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_tret = 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 = ctz32(env->intsrc) + 1; +} + +if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +stb_phys(cs->as, env->sp--, (ret & 0xff) >> 16); +} else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +} else { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +} + +env->pc = base + vector * size; +env->sregI = 0;/* clear Global Interrupt Flag */ + +cs->exception_index = -1; } int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, int len, bool is_write) -- 2.4.9 (Apple Git-60)
[Qemu-devel] [PATCH v4 4/9] target-avr: adding instructions encodings
Signed-off-by: Michael Rolnik --- target-avr/translate-inst.h | 730 1 file changed, 730 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 000..985c124 --- /dev/null +++ b/target-avr/translate-inst.h @@ -0,0 +1,730 @@ +/* + * 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_ + +typedef struct DisasContextDisasContext; + +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_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t CPC_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | (extract32(opcode, 0, 4)); +} + +int avr_translate_SBC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t SBC_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t SBC_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | (extract32(opcode, 0, 4)); +} + +int avr_translate_ADD(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t ADD_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t ADD_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | (extract32(opcode, 0, 4)); +} + +int avr_translate_AND(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t AND_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t AND_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | (extract32(opcode, 0, 4)); +} + +int avr_translate_EOR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t EOR_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t EOR_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | (extract32(opcode, 0, 4)); +} + +int avr_translate_OR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t OR_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t OR_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | (extract32(opcode, 0, 4)); +} + +int avr_translate_MOV(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t MOV_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t MOV_Rr(uint32_t opco
[Qemu-devel] [PATCH v4 9/9] target-avr: updating translate.c to use instructions translation
Signed-off-by: Michael Rolnik --- target-avr/Makefile.objs | 4 +- target-avr/translate.c | 132 --- 2 files changed, 59 insertions(+), 77 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 029cffa..228ee90 100644 --- a/target-avr/translate.c +++ b/target-avr/translate.c @@ -18,60 +18,30 @@ * <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,24 +90,27 @@ 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 & 0x; +} +if (inst->length == 32) { +inst->npc = inst->cpc + 2; +/* get opcode as 32bit value */ +inst->opcode = (inst->opcode << 16) + | (inst->opcode >> 16); } } @@ -171,18 +144,21 @@ void gen_intermediate_code(CPUAVRState *env, struct TranslationBlock *tb) 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++
[Qemu-devel] [PATCH v4 7/9] target-avr: adding instruction decoder
Signed-off-by: Michael Rolnik --- 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 000..6fb7b83 --- /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 +#include "translate.h" + + +void avr_decode(uint32_t pc, uint32_t *length, uint32_t code, translate_function_t *translate) +{ +uint32_t opcode = extract32(code, 0, 16); + +switch (opcode & 0xd000) { +case0x: { +uint32_t opcode = extract32(code, 0, 16); +switch (opcode & 0x2c00) { +case0x: { +uint32_t opcode = extract32(code, 0, 16); +switch (opcode & 0x0300) { +case0x: { +*length = 16; +*translate = &avr_translate_NOP; +break; +} +case0x0100: { +*length = 16; +*translate = &avr_translate_MOVW; +break; +} +case0x0200: { +*length = 16; +*translate = &avr_translate_MULS; +break; +} +case0x0300: { +uint32_t opcode = extract32(code, 0, 16); +switch (opcode & 0x0088) { +case0x: { +*length = 16; +*translate = &avr_translate_MULSU; +break; +} +case0x0008: { +*length = 16; +*translate = &avr_translate_FMUL; +break; +} +case0x0080: { +*length = 16; +*translate = &avr_translate_FMULS; +break; +} +case0x0088: { +*length = 16; +*translate = &avr_translate_FMULSU; +break; +} +} +break; +} +} +break; +} +case0x0400: { +*length = 16; +*translate = &avr_translate_CPC; +break; +} +case0x0800: { +*length = 16; +*translate = &avr_translate_SBC; +break; +} +case0x0c00: { +*length = 16; +*translate = &avr_translate_ADD; +break; +} +case0x2000: { +*length = 16; +*translate = &avr_translate_AND; +break; +} +case0x2400: { +*length = 16; +*translate = &avr_translate_EOR; +break; +} +case0x2800: { +*length = 16; +*translate = &avr_translate_OR; +break; +} +case0x2c00: { +*length = 16; +*translate = &avr_translate_MOV; +break; +} +} +break;
[Qemu-devel] [PATCH v4 8/9] target-avr: adding instruction translation
Signed-off-by: Michael Rolnik --- target-avr/translate-inst.c | 2499 +++ target-avr/translate.h | 120 +++ 2 files changed, 2619 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 000..f2252be --- /dev/null +++ b/target-avr/translate-inst.c @@ -0,0 +1,2499 @@ +/* + * 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" +#include "qemu/bitops.h" + +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); + +/* +in the following 2 functions +H assumed to be in 0x00ff format +M assumed to be in 0x00ff format +L assumed to be in 0x00ff format +*/ +void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv l); /* H:M:L = addr */ +TCGv gen_get_addr(TCGv H, TCGv M, TCGv L);/* addr = H:M:L*/ + +void gen_set_xaddr(TCGv addr); +void gen_set_yaddr(TCGv addr); +void gen_set_zaddr(TCGv addr); + +TCGv gen_get_xaddr(void); +TCGv gen_get_yaddr(void); +TCGv gen_get_zaddr(void); + +void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ +TCGv t1 = tcg_temp_new_i32(); +TCGv t2 = tcg_temp_new_i32(); +TCGv t3 = tcg_temp_new_i32(); + +tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */ +tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */ +tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */ +tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */ +tcg_gen_or_tl(t1, t1, t3); + +tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */ +tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */ +tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + +tcg_temp_free_i32(t3); +tcg_temp_free_i32(t2); +tcg_temp_free_i32(t1); +} + +void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) +{ +TCGv t1 = tcg_temp_new_i32(); +TCGv t2 = tcg_temp_new_i32(); + +tcg_gen_xor_tl(t1, Rd, R); /* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R = (Rd ^ R) & ~(Rd ^ Rr) */ +tcg_gen_xor_tl(t2, Rd, Rr); +tcg_gen_andc_tl(t1, t1, t2); + +tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + +tcg_temp_free_i32(t2); +tcg_temp_free_i32(t1); +} + +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_xor_tl(t1, Rd, R); /* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R = (Rd ^ R) & (Rd ^ R)*/ +tcg_gen_xor_tl(t2, Rd, Rr); +tcg_gen_and_tl(t1, t1, t2); +tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + +tcg_temp_free_i32(t2); +tcg_temp_free_i32(t1); +} + +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_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +void gen_push_ret(CPUAVRState *env, int ret) +{ +TCGv t1 = tcg_const_i32((ret & 0xff)); +TCGv t2 = tcg_const_i32((ret & 0x00ff00) >> 8); +TCGv t3 = tcg_const_i32((ret & 0xff
Re: [Qemu-devel] [PATCH 08/10] target-avr: adding instruction translation
On Mon, Jun 6, 2016 at 10:17 PM, Richard Henderson wrote: > On 06/05/2016 11:52 PM, Michael Rolnik wrote: > >> truth table shows that these computations are different. >> > > You're not giving the right inputs to the truth table. > > you can't look onto 4th bit because 4th bits in the input were not 0s. >> > > What did you think the xor's do? They remove the non-zero input bits. > > #include > > static int orig(int r, int d, int s) > { > return (((d & s) | (d & ~r) | (s & ~r)) & 2) != 0; > } > > static int mine(int r, int d, int s) > { > return (((d ^ s) ^ r) & 4) != 0; > } > > int main() > { > int s, d; > for (s = 0; s < 8; ++s) > for (d = 0; d < 8; ++d) > { > int r = d + s; > int o = orig(r, d, s); > int m = mine(r, d, s); > > if (o != m) > printf("%2d = %d + %d (o=%d, m=%d)\n", r, d, s, o, m); > } > return 0; > } > > This performs tests on 3-bit inputs, testing for carry-out on bit 1, just > like Hf computes carry-out on bit 3. you are right I can look onto 4th bit, however I do the whole computation of C flag already. > > > > Then you've got the order of the stores wrong. Your code pushes the >> LSB >> before pushing the MSB, which results in the MSB at the lower address, >> which means big-endian. >> >> this is right. However as far as I understand AVR is neither little nor >> big >> endian because there it's 8 bit architecture (see >> here http://www.avrfreaks.net/forum/endian-issue). for time being I >> defined the >> platform to be little endian with ret address exception >> > > True, AVR is an 8-bit core, where endianness doesn't (normally) apply. > And you are right that ADIW does treat the registers as little-endian. > > But the only multi-byte store to memory is in big-endian order. So why > wouldn't you want to take advantage of that fact? I will. > > > You have swapped the overflow conditions for INC and DEC. >> > ... > >> this is how it's defined in the document. >> > > No, it isn't. Look again, you've swapped them. checking again. > > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH v4 0/9] 8bit AVR cores
please advise. I have the following warning. but all print_instn_XXX functions are declared this way. so, I am kind of confused. I can fix it, but the file won't look the same. WARNING: space prohibited between function name and open parenthesis '(' #132: FILE: include/disas/bfd.h:424: +int print_insn_avr (bfd_vma, disassemble_info*); On Mon, Jun 6, 2016 at 10:40 PM, Richard Henderson wrote: > On 06/06/2016 03:37 AM, Michael Rolnik wrote: > >> changes since v3 >> 1. rampD/X/Y/Z registers are encoded as 0x00ff and not 0x00ff for >> faster address manipulaton >> 2. ffs changed to ctz32 >> 3. duplicate code removed at avr_cpu_do_interrupt >> 4. using andc instead of not + and >> 5. fixing V flag calculation in varios instructions >> 6. freeing local variables in PUSH >> 7. tcg_const_local_i32 -> tcg_const_i32 >> 8. using sextract32 instead of my implementation >> 9. fixing BLD instruction >> 10.xor(r) instead of 0xff - r at COM >> 11.fixing MULS/MULSU not to modify inputs' content >> 12.using SUB for NEG >> 13.fixing tcg_gen_qemu_ld/st call in XCH >> > > I did mention the numerous checkpatch warnings: > > $ ./scripts/checkpatch.pl avr-patches-4/* | grep total: > total: 0 errors, 16 warnings, 1142 lines checked > total: 0 errors, 0 warnings, 422 lines checked > total: 0 errors, 3 warnings, 343 lines checked > total: 0 errors, 4 warnings, 730 lines checked > total: 0 errors, 1 warnings, 69 lines checked > total: 0 errors, 0 warnings, 199 lines checked > total: 0 errors, 18 warnings, 724 lines checked > total: 0 errors, 240 warnings, 2619 lines checked > total: 0 errors, 1 warnings, 176 lines checked > > $ ./scripts/checkpatch.pl avr-patches-4/* | grep WARNING: | sort -u > WARNING: architecture specific defines should be avoided > WARNING: externs should be avoided in .c files > WARNING: line over 80 characters > WARNING: space prohibited between function name and open parenthesis '(' > WARNING: struct MemoryRegionOps should normally be const > WARNING: struct VMStateDescription should normally be const > > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH v4 0/9] 8bit AVR cores
WARNING: architecture specific defines should be avoided #574: FILE: target-avr/cpu.h:32: +#if !defined(__CPU_AVR_H__) it was not my invention, I took it from either target-alpha or target-ppc. On Mon, Jun 6, 2016 at 10:49 PM, Michael Rolnik wrote: > please advise. > I have the following warning. but all print_instn_XXX functions are > declared this way. > so, I am kind of confused. I can fix it, but the file won't look the same. > > WARNING: space prohibited between function name and open parenthesis '(' > #132: FILE: include/disas/bfd.h:424: > +int print_insn_avr (bfd_vma, disassemble_info*); > > > On Mon, Jun 6, 2016 at 10:40 PM, Richard Henderson > wrote: > >> On 06/06/2016 03:37 AM, Michael Rolnik wrote: >> >>> changes since v3 >>> 1. rampD/X/Y/Z registers are encoded as 0x00ff and not 0x00ff >>> for faster address manipulaton >>> 2. ffs changed to ctz32 >>> 3. duplicate code removed at avr_cpu_do_interrupt >>> 4. using andc instead of not + and >>> 5. fixing V flag calculation in varios instructions >>> 6. freeing local variables in PUSH >>> 7. tcg_const_local_i32 -> tcg_const_i32 >>> 8. using sextract32 instead of my implementation >>> 9. fixing BLD instruction >>> 10.xor(r) instead of 0xff - r at COM >>> 11.fixing MULS/MULSU not to modify inputs' content >>> 12.using SUB for NEG >>> 13.fixing tcg_gen_qemu_ld/st call in XCH >>> >> >> I did mention the numerous checkpatch warnings: >> >> $ ./scripts/checkpatch.pl avr-patches-4/* | grep total: >> total: 0 errors, 16 warnings, 1142 lines checked >> total: 0 errors, 0 warnings, 422 lines checked >> total: 0 errors, 3 warnings, 343 lines checked >> total: 0 errors, 4 warnings, 730 lines checked >> total: 0 errors, 1 warnings, 69 lines checked >> total: 0 errors, 0 warnings, 199 lines checked >> total: 0 errors, 18 warnings, 724 lines checked >> total: 0 errors, 240 warnings, 2619 lines checked >> total: 0 errors, 1 warnings, 176 lines checked >> >> $ ./scripts/checkpatch.pl avr-patches-4/* | grep WARNING: | sort -u >> WARNING: architecture specific defines should be avoided >> WARNING: externs should be avoided in .c files >> WARNING: line over 80 characters >> WARNING: space prohibited between function name and open parenthesis '(' >> WARNING: struct MemoryRegionOps should normally be const >> WARNING: struct VMStateDescription should normally be const >> >> >> >> r~ >> > > > > -- > Best Regards, > Michael Rolnik > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH v4 1/9] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions
Hi Richard, *Consider making the vm save state reflect the actual hardware format. That way you can change the qemu internal format while retaining migration compatibility.* How it can be done? how can I modify a value passed to VMSTATE_UINT32? On Mon, Jun 6, 2016 at 11:15 PM, Richard Henderson wrote: > On 06/06/2016 03:37 AM, Michael Rolnik wrote: > >> +int print_insn_avr(bfd_vma addr, disassemble_info *info) >> +{ >> +int length = 0;; >> +/* TODO*/ >> +return length; >> +} >> > > Again, delete this file. This prohibits the default implementation from > working. > > +static void avr_cpu_reset(CPUState *s) >> +{ >> +AVRCPU *cpu = AVR_CPU(s); >> +AVRCPUClass *mcc = AVR_CPU_GET_CLASS(cpu); >> +CPUAVRState *env = &cpu->env; >> + >> +mcc->parent_reset(s); >> + >> +memset(env, 0, sizeof(CPUAVRState)); >> > > You didn't fix the memset issue I pointed out. > > +} >> +AVRCPU *cpu_avr_init(const char *cpu_model) >> > > Spacing. > > +/* >> +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 >> +*/ >> > > Don't put these at the top, put them next to the declarations of the > actual variables, where they're useful. > > +#define TARGET_IS_LIENDIAN 1 >> > > Didn't fix the typo, or really just delete this. > > In case you're wondering, this *doesn't* mean little-endian. > > TARGET_IS_BIENDIAN means that the target changes between big- and > little-endian at runtime. > > One selects the endian-ness of the target in configure. The default is > little; set target_bigendian to select big. > > > +uint32_tsregC; /* 0x0001 1 bits */ >> +uint32_tsregZ; /* 0x00ff 8 bits */ >> > > This isn't quite true; sregZ may contain 0x after adwi. > > +static inline int cpu_mmu_index(CPUAVRState *env, bool ifetch) >> +{ >> +return 0; >> +} >> > > This should be > > return ifetch ? CODE_INDEX : DATA_INDEX; > > +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; >> > > Didn't add the function I requested. > Plus, there's an error in handling of sregZ. > > +env->sregC = (tmp >> 0) & 0x01; >> +env->sregZ = (tmp >> 1) & 0x01; >> +env->sregN = (tmp >> 2) & 0x01; >> +env->sregV = (tmp >> 3) & 0x01; >> +env->sregS = (tmp >> 4) & 0x01; >> +env->sregH = (tmp >> 5) & 0x01; >> +env->sregT = (tmp >> 6) & 0x01; >> +env->sregI = (tmp >> 7) & 0x01; >> > > Likewise. > > +VMSTATE_UINT32_ARRAY(r, CPUAVRState, 32), >> + >> +VMSTATE_UINT32(sregC, CPUAVRState), >> +VMSTATE_UINT32(sregZ, CPUAVRState), >> +VMSTATE_UINT32(sregN, CPUAVRState), >> +VMSTATE_UINT32(sregV, CPUAVRState), >> +VMSTATE_UINT32(sregS, CPUAVRState), >> +VMSTATE_UINT32(sregH, CPUAVRState), >> +VMSTATE_UINT32(sregT, CPUAVRState), >> +VMSTATE_UINT32(sregI, CPUAVRState), >> + >> +VMSTATE_UINT32(rampD, CPUAVRState), >> +VMSTATE_UINT32(rampX, CPUAVRState), >> +VMSTATE_UINT32(rampY, CPUAVRState), >> +VMSTATE_UINT32(rampZ, CPUAVRState), >> + >> +VMSTATE_UINT32(eind,CPUAVRState), >> +VMSTATE_UINT32(sp, CPUAVRState), >> +VMSTATE_UINT32(pc, CPUAVRState), >> > > Consider making the vm save state reflect the actual hardware format. > That way you can change the qemu internal format while retaining migration > compatibility. > > +cpu_fprintf(f, "rampX: %02x\n", env->rampX); >> +cpu_fprintf(f, "rampY: %02x\n", env->rampY); >> +cpu_fprintf(f, "rampZ: %02x\n", env->rampZ); >> +cpu_fprintf(f, "rampD: %02x\n", env->rampD); >> +cpu_fprintf(f, "EIND: %02x\n", env->eind); >> > > This format probably isn't what you intended after shifting these values. > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH v4 1/9] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions
Hi Richard. how can I test it? On Tue, Jun 7, 2016 at 5:28 PM, Richard Henderson wrote: > On 06/06/2016 11:32 PM, Michael Rolnik wrote: > > Hi Richard, > > > > /Consider making the vm save state reflect the actual hardware format. > That > > way you can change the qemu internal format while retaining migration > > compatibility./ > > > > How it can be done? how can I modify a value passed to VMSTATE_UINT32? > > There are two different ways. You can see both of them in use in > target-i386. > > The first is to manually describe the field, using custom get and put > fields. > For example: > > static const VMStateInfo vmstate_fpreg = { > .name = "fpreg", > .get = get_fpreg, > .put = put_fpreg, > }; > > > The second is to reserve extra space for the external representation and > then > use the pre_save / post_load hooks. For i386, see the cpu_pre_save, where > we > take the fpus, fpstt, and fptags fields and store them into the > fpus_vmstate > field. It is then the vmstate field that is mentioned in vmstate_x86_cpu. > > I personally prefer the get/put fields, but I admit they can be tricky to > use. > > > r~ > -- Best Regards, Michael Rolnik
Re: [Qemu-devel] [PATCH v4 2/9] target-avr: adding AVR CPU features/flavors
Richard, do you want to delete all empty lines? On Mon, Jun 6, 2016 at 11:25 PM, Richard Henderson wrote: > On 06/06/2016 03:37 AM, Michael Rolnik wrote: > >> @@ -55,12 +55,14 @@ static void avr_cpu_reset(CPUState *s) >> 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; >> > > Didn't fix the memset issue I pointed out. > > +} >> +static void avr_avr6_initfn(Object *obj) >> > > Spacing. > > +} >> +static void avr_xmega2_initfn(Object *obj) >> > > Spacing. > > +} >> +static void avr_xmega4_initfn(Object *obj) >> > > Spacing. > > +} >> +static void avr_xmega5_initfn(Object *obj) >> > > Spacing. > > +} >> +static void avr_xmega7_initfn(Object *obj) >> > > Spacing. > > +static inline void avr_del_feature( >> +CPUAVRState*env, >> +int feature) >> +{ >> +env->features &= ~(1Ul << feature); >> +} >> > > Dead code. > > > r~ > > -- Best Regards, Michael Rolnik
[Qemu-devel] [PATCH v5 00/10] 8bit AVR cores
From: Michael Rolnik This series of patches adds 8bit AVR cores to QEMU. All instruction, except BREAK/DES/SPM/SPMX, are implemented. Not fully tested yet. However I was able to execute simple code with functions. e.g fibonacci calculation. This series of patches include a non real, sample board. No fuses support yet. PC is set to 0 at reset. the patches include the following 1. just a basic 8bit AVR CPU, without instruction decoding or translation 2. CPU features which allow define the following 8bit AVR cores avr1 avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 xmega2 xmega4 xmega5 xmega6 xmega7 3. a definition of sample machine with SRAM, FLASH and CPU which allows to execute simple code 4. encoding for all AVR instructions 5. interrupt handling 6. helpers for IN, OUT, SLEEP, WBR & unsupported instructions 7. a decoder which given an opcode decides what istruction it is 8. translation of AVR instruction into TCG 9. all features together changes since v3 1. rampD/X/Y/Z registers are encoded as 0x00ff (instead of 0x00ff) for faster address manipulaton 2. ffs changed to ctz32 3. duplicate code removed at avr_cpu_do_interrupt 4. using andc instead of not + and 5. fixing V flag calculation in varios instructions 6. freeing local variables in PUSH 7. tcg_const_local_i32 -> tcg_const_i32 8. using sextract32 instead of my implementation 9. fixing BLD instruction 10.xor(r) instead of 0xff - r at COM 11.fixing MULS/MULSU not to modify inputs' content 12.using SUB for NEG 13.fixing tcg_gen_qemu_ld/st call in XCH changes since v4 1. target is now defined as big endian in order to optimize push_ret/pop_ret 2. all style warnings are fixed 3. adding cpu_set/get_sreg functions 4. simplifying gen_goto_tb as there is no real paging 5. env->pc -> env->pc_w 6. making flag dump more compact 7. more spacing 8. renaming CODE/DATA_INDEX -> MMU_CODE/DATA_IDX 9. removing avr_set_feature 10. SPL/SPH set bug fix 11. switching stb_phys to cpu_stb_data 12. cleaning up avr_decode 13. saving sreg, rampD/X/Y/Z, eind in HW format (savevm) 14. saving CPU features (savevm) Michael Rolnik (10): target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions target-avr: adding AVR CPU features/flavors target-avr: adding a sample AVR board target-avr: adding instructions encodings target-avr: adding AVR interrupt handling target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions target-avr: adding instruction decoder target-avr: adding instruction translation target-avr: updating translate.c to use instructions translation target-avr: saving sreg, rampD, rampX, rampY, rampD, eind in HW representation saving cpu features arch_init.c |2 + configure |7 +- default-configs/avr-softmmu.mak | 21 + hw/Makefile.objs|1 + hw/avr/Makefile.objs| 21 + hw/avr/sample-io.c | 215 hw/avr/sample.c | 118 ++ include/disas/bfd.h |6 + include/sysemu/arch_init.h |1 + target-avr/Makefile.objs| 25 + target-avr/cpu-qom.h| 84 ++ target-avr/cpu.c| 609 + target-avr/cpu.h| 211 target-avr/decode.c | 693 +++ target-avr/gdbstub.c| 99 ++ target-avr/helper.c | 269 target-avr/helper.h | 26 + target-avr/machine.c| 117 ++ target-avr/machine.h| 21 + target-avr/translate-inst.c | 2624 +++ target-avr/translate-inst.h | 762 target-avr/translate.c | 274 target-avr/translate.h | 119 ++ 23 files changed, 6324 insertions(+), 1 deletion(-) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 hw/avr/Makefile.objs create mode 100644 hw/avr/sample-io.c create mode 100644 hw/avr/sample.c create mode 100644 target-avr/Makefile.objs create mode 100644 target-avr/cpu-qom.h create mode 100644 target-avr/cpu.c create mode 100644 target-avr/cpu.h create mode 100644 target-avr/decode.c create mode 100644 target-avr/gdbstub.c create mode 100644 target-avr/helper.c create mode 100644 target-avr/helper.h create mode 100644 target-avr/machine.c create mode 100644 target-avr/machine.h create mode 100644 target-avr/translate-inst.c create mode 100644 target-avr/translate-inst.h create mode 100644 target-avr/translate.c create mode 100644 target-avr/translate.h -- 2.4.9 (Apple Git-60)
[Qemu-devel] [PATCH v5 03/10] target-avr: adding a sample AVR board
From: Michael Rolnik From: Michael Rolnik Signed-off-by: Michael Rolnik --- hw/Makefile.objs | 1 + hw/avr/Makefile.objs | 21 + hw/avr/sample-io.c | 215 +++ hw/avr/sample.c | 118 4 files changed, 355 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 000..c080e4e --- /dev/null +++ b/hw/avr/Makefile.objs @@ -0,0 +1,21 @@ +# +# 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> +# + +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 000..e0fee77 --- /dev/null +++ b/hw/avr/sample-io.c @@ -0,0 +1,215 @@ +/* + * 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_SIZE0x0020 +#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_BASE0x +#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 { +SysBusDeviceparent; + +MemoryRegioniomem; + +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, +
[Qemu-devel] [PATCH v5 04/10] target-avr: adding instructions encodings
From: Michael Rolnik From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/translate-inst.h | 762 1 file changed, 762 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 000..0c082d3 --- /dev/null +++ b/target-avr/translate-inst.h @@ -0,0 +1,762 @@ +/* + * 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_ + +typedef struct DisasContextDisasContext; + +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_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t CPC_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_SBC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t SBC_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t SBC_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_ADD(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t ADD_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t ADD_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_AND(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t AND_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t AND_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_EOR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t EOR_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t EOR_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_OR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t OR_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t OR_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_MOV(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +sta
[Qemu-devel] [PATCH v5 02/10] target-avr: adding AVR CPU features/flavors
From: Michael Rolnik From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/cpu.c | 307 ++- target-avr/cpu.h | 53 ++ 2 files changed, 359 insertions(+), 1 deletion(-) diff --git a/target-avr/cpu.c b/target-avr/cpu.c index 99bd788..197f9ac 100644 --- a/target-avr/cpu.c +++ b/target-avr/cpu.c @@ -203,6 +203,296 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) dc->cannot_destroy_with_object_finalize_yet = 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_FE
[Qemu-devel] [PATCH v5 01/10] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions
From: Michael Rolnik From: Michael Rolnik Signed-off-by: Michael Rolnik --- arch_init.c | 2 + configure | 7 +- default-configs/avr-softmmu.mak | 21 +++ include/disas/bfd.h | 6 + include/sysemu/arch_init.h | 1 + target-avr/Makefile.objs| 23 +++ target-avr/cpu-qom.h| 84 +++ target-avr/cpu.c| 304 target-avr/cpu.h| 158 + target-avr/gdbstub.c| 99 + target-avr/helper.c | 87 target-avr/helper.h | 21 +++ target-avr/machine.c| 54 +++ target-avr/machine.h| 21 +++ target-avr/translate.c | 290 ++ 15 files changed, 1177 insertions(+), 1 deletion(-) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 target-avr/Makefile.objs create mode 100644 target-avr/cpu-qom.h create mode 100644 target-avr/cpu.c create mode 100644 target-avr/cpu.h create mode 100644 target-avr/gdbstub.c create mode 100644 target-avr/helper.c create mode 100644 target-avr/helper.h create mode 100644 target-avr/machine.c create mode 100644 target-avr/machine.h create mode 100644 target-avr/translate.c diff --git a/arch_init.c b/arch_init.c index fa05973..be6e6de 100644 --- a/arch_init.c +++ b/arch_init.c @@ -80,6 +80,8 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_TRICORE) #define QEMU_ARCH QEMU_ARCH_TRICORE +#elif defined(TARGET_AVR) +#define QEMU_ARCH QEMU_ARCH_AVR #endif const uint32_t arch_type = QEMU_ARCH; diff --git a/configure b/configure index 8c2f90b..41e550e 100755 --- a/configure +++ b/configure @@ -5603,7 +5603,7 @@ target_name=$(echo $target | cut -d '-' -f 1) target_bigendian="no" case "$target_name" in - armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) + avr|armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) target_bigendian=yes ;; esac @@ -5652,6 +5652,8 @@ case "$target_name" in x86_64) TARGET_BASE_ARCH=i386 ;; + avr) + ;; alpha) ;; arm|armeb) @@ -5848,6 +5850,9 @@ disas_config() { for i in $ARCH $TARGET_BASE_ARCH ; do case "$i" in + avr) +disas_config "AVR" + ;; alpha) disas_config "ALPHA" ;; diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak new file mode 100644 index 000..003465d --- /dev/null +++ b/default-configs/avr-softmmu.mak @@ -0,0 +1,21 @@ +# +# 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> +# + +# Default configuration for avr-softmmu diff --git a/include/disas/bfd.h b/include/disas/bfd.h index a112e9c..b13fc53 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -213,6 +213,12 @@ enum bfd_architecture #define bfd_mach_m32r 0 /* backwards compatibility */ bfd_arch_mn10200,/* Matsushita MN10200 */ bfd_arch_mn10300,/* Matsushita MN10300 */ + bfd_arch_avr, /* Atmel AVR microcontrollers. */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr3 3 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 bfd_arch_cris, /* Axis CRIS */ #define bfd_mach_cris_v0_v10 255 #define bfd_mach_cris_v32 32 diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index d690dfa..8c75777 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -23,6 +23,7 @@ enum { QEMU_ARCH_UNICORE32 = (1 << 14), QEMU_ARCH_MOXIE = (1 << 15), QEMU_ARCH_TRICORE = (1 << 16), +QEMU_ARCH_AVR = (1 << 17), }; extern const uint32_t arch_type; diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs new file mode 100644 index 000..2a10104 --- /dev/null +++ b/target-avr/Makefile.objs @@ -0,0 +1,23 @@ +# +# QEMU AVR CPU +# +# Copyright (c) 2016 Michael Rolnik +# +# This library is free software; you can redistribute it a
[Qemu-devel] [PATCH v5 07/10] target-avr: adding instruction decoder
From: Michael Rolnik From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/decode.c | 693 1 file changed, 693 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 000..44a5815 --- /dev/null +++ b/target-avr/decode.c @@ -0,0 +1,693 @@ +/* + * 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 +#include "translate.h" + +void avr_decode(uint32_t pc, uint32_t *l, uint32_t c, translate_function_t *t) +{ +uint32_t opc = extract32(c, 0, 16); +switch (opc & 0xd000) { +case 0x: { +switch (opc & 0x2c00) { +case 0x: { +switch (opc & 0x0300) { +case 0x: { +*l = 16; +*t = &avr_translate_NOP; +break; +} +case 0x0100: { +*l = 16; +*t = &avr_translate_MOVW; +break; +} +case 0x0200: { +*l = 16; +*t = &avr_translate_MULS; +break; +} +case 0x0300: { +switch (opc & 0x0088) { +case 0x: { +*l = 16; +*t = &avr_translate_MULSU; +break; +} +case 0x0008: { +*l = 16; +*t = &avr_translate_FMUL; +break; +} +case 0x0080: { +*l = 16; +*t = &avr_translate_FMULS; +break; +} +case 0x0088: { +*l = 16; +*t = &avr_translate_FMULSU; +break; +} +} +break; +} +} +break; +} +case 0x0400: { +*l = 16; +*t = &avr_translate_CPC; +break; +} +case 0x0800: { +*l = 16; +*t = &avr_translate_SBC; +break; +} +case 0x0c00: { +*l = 16; +*t = &avr_translate_ADD; +break; +} +case 0x2000: { +*l = 16; +*t = &avr_translate_AND; +break; +} +case 0x2400: { +*l = 16; +*t = &avr_translate_EOR; +break; +} +case 0x2800: { +*l = 16; +*t = &avr_translate_OR; +break; +} +case 0x2c00: { +*l = 16; +*t = &avr_translate_MOV; +break; +} +} +break; +} +case 0x1000: { +switch (opc & 0x2000) { +case 0x: { +switch (opc & 0x0c00) { +case 0x: { +*l = 16; +*t = &avr_translate_CPSE; +break; +} +case 0x0
[Qemu-devel] [PATCH v5 06/10] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
From: Michael Rolnik From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/helper.c | 145 target-avr/helper.h | 5 ++ 2 files changed, 140 insertions(+), 10 deletions(-) diff --git a/target-avr/helper.c b/target-avr/helper.c index f96fa27..9e2b52a 100644 --- a/target-avr/helper.c +++ b/target-avr/helper.c @@ -42,14 +42,14 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) cs->exception_index = EXCP_RESET; cc->do_interrupt(cs); -cs->interrupt_request &= ~CPU_INTERRUPT_RESET; +cs->interrupt_request &= ~CPU_INTERRUPT_RESET; ret = true; } } if (interrupt_request & CPU_INTERRUPT_HARD) { if (cpu_interrupts_enabled(env) && env->intsrc != 0) { -int index = ctz32(env->intsrc); +int index = ctz32(env->intsrc); cs->exception_index = EXCP_INT(index); cc->do_interrupt(cs); @@ -64,8 +64,8 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) void avr_cpu_do_interrupt(CPUState *cs) { -AVRCPU *cpu = AVR_CPU(cs); -CPUAVRState*env = &cpu->env; +AVRCPU *cpu = AVR_CPU(cs); +CPUAVRState *env = &cpu->env; uint32_t ret = env->pc_w; int vector = 0; @@ -79,14 +79,14 @@ void avr_cpu_do_interrupt(CPUState *cs) } if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { -stb_phys(cs->as, env->sp--, (ret & 0xff)); -stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); -stb_phys(cs->as, env->sp--, (ret & 0xff) >> 16); +cpu_stb_data(env, env->sp--, (ret & 0xff)); +cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); +cpu_stb_data(env, env->sp--, (ret & 0xff) >> 16); } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { -stb_phys(cs->as, env->sp--, (ret & 0xff)); -stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +cpu_stb_data(env, env->sp--, (ret & 0xff)); +cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); } else { -stb_phys(cs->as, env->sp--, (ret & 0xff)); +cpu_stb_data(env, env->sp--, (ret & 0xff)); } env->pc_w = base + vector * size; @@ -133,6 +133,28 @@ void tlb_fill(CPUState *cs, target_ulong vaddr, int is_write, 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)); + +/* +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, qemu_logfile, fprintf, 0); +} +cpu_loop_exit(cs); +} void helper_debug(CPUAVRState *env) { @@ -142,3 +164,106 @@ void helper_debug(CPUAVRState *env) cpu_loop_exit(cs); } +void helper_wdr(CPUAVRState *env) +{ +CPUState *cs = CPU(avr_env_get_cpu(env)); + +/* +WD is not implemented yet, placeholder +*/ +cs->exception_index = EXCP_DEBUG; +cpu_loop_exit(cs); +} + +target_ulong helper_inb(CPUAVRState *env, uint32_t port) +{ +qemu_log("in: io[%02x]\n", port); + +switch (port) { +case0x38: { +return 0xff & (env->rampD >> 16); /* RAMPD */ +} +case0x39: { +return 0xff & (env->rampX >> 16); /* RAMPX */ +} +case0x3a: { +return 0xff & (env->rampY >> 16); /* RAMPY */ +} +case0x3b: { +return 0xff & (env->rampZ >> 16); /* RAMPZ */ +} +case0x3c: { +return 0xff & (env->eind >> 16); /* EIND*/ +} +case0x3d: { /* SPL */ +return env->sp & 0x00ff; +} +case0x3e: { /* SPH */ +return env->sp >> 8; +} +case0x3f: { /* SREG*/ +return cpu_get_sreg(env); +} +} +return 0; +} + +void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) +{ +qemu_log("out:%02x -> io[%02x]\n", data, port); + +data&= 0x00ff; + +switch (port) { +case0x04: { +qemu_irqirq; +CPUState *cpu = CPU(avr_env_get_c
[Qemu-devel] [PATCH v5 08/10] target-avr: adding instruction translation
From: Michael Rolnik From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/translate-inst.c | 2624 +++ target-avr/translate.h | 119 ++ 2 files changed, 2743 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 000..c225743 --- /dev/null +++ b/target-avr/translate-inst.c @@ -0,0 +1,2624 @@ +/* + * 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" +#include "qemu/bitops.h" + +static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr); +static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr); +static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr); +static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr); +static void gen_ZNSf(TCGv R); +static void gen_push_ret(CPUAVRState *env, int ret); +static void gen_pop_ret(CPUAVRState *env, TCGv ret); +static void gen_jmp_ez(void); +static void gen_jmp_z(void); + +/* +in the following 2 functions +H assumed to be in 0x00ff format +M assumed to be in 0x00ff format +L assumed to be in 0x00ff format +*/ +static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv l); /* H:M:L = addr */ +static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L);/* addr = H:M:L */ + +static void gen_set_xaddr(TCGv addr); +static void gen_set_yaddr(TCGv addr); +static void gen_set_zaddr(TCGv addr); + +static TCGv gen_get_xaddr(void); +static TCGv gen_get_yaddr(void); +static TCGv gen_get_zaddr(void); + +void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ +TCGv t1 = tcg_temp_new_i32(); +TCGv t2 = tcg_temp_new_i32(); +TCGv t3 = tcg_temp_new_i32(); + +tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */ +tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */ +tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */ +tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */ +tcg_gen_or_tl(t1, t1, t3); + +tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */ +tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */ +tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + +tcg_temp_free_i32(t3); +tcg_temp_free_i32(t2); +tcg_temp_free_i32(t1); +} + +void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) +{ +TCGv t1 = tcg_temp_new_i32(); +TCGv t2 = tcg_temp_new_i32(); + +/* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R = (Rd ^ R) & ~(Rd ^ Rr) */ +tcg_gen_xor_tl(t1, Rd, R); +tcg_gen_xor_tl(t2, Rd, Rr); +tcg_gen_andc_tl(t1, t1, t2); + +tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + +tcg_temp_free_i32(t2); +tcg_temp_free_i32(t1); +} + +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 */ +/* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R = (Rd ^ R) & (Rd ^ R)*/ +tcg_gen_xor_tl(t1, Rd, R); +tcg_gen_xor_tl(t2, Rd, Rr); +tcg_gen_and_tl(t1, t1, t2); +tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + +tcg_temp_free_i32(t2); +tcg_temp_free_i32(t1); +} + +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_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +void gen_push_ret(CPUAVRState *env, in
[Qemu-devel] [PATCH v5 05/10] target-avr: adding AVR interrupt handling
From: Michael Rolnik From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/helper.c | 59 - 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/target-avr/helper.c b/target-avr/helper.c index ad8f83e..f96fa27 100644 --- a/target-avr/helper.c +++ b/target-avr/helper.c @@ -31,11 +31,68 @@ 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 = ctz32(env->intsrc); +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_w; +int vector = 0; +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 = ctz32(env->intsrc) + 1; +} + +if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +stb_phys(cs->as, env->sp--, (ret & 0xff) >> 16); +} else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +} else { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +} + +env->pc_w = base + vector * size; +env->sregI = 0;/* clear Global Interrupt Flag */ + +cs->exception_index = -1; } int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, -- 2.4.9 (Apple Git-60)
[Qemu-devel] [PATCH v5 09/10] target-avr: updating translate.c to use instructions translation
From: Michael Rolnik From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/Makefile.objs | 4 +- target-avr/translate.c | 148 +-- 2 files changed, 69 insertions(+), 83 deletions(-) diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs index 2a10104..9757721 100644 --- a/target-avr/Makefile.objs +++ b/target-avr/Makefile.objs @@ -18,6 +18,8 @@ # <http://www.gnu.org/licenses/lgpl-2.1.html> # -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 81ee44e..28babc9 100644 --- a/target-avr/translate.c +++ b/target-avr/translate.c @@ -18,60 +18,30 @@ * <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,25 +90,32 @@ 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; - -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); +CPUAVRState*env = &cpu->env; + +inst->opcode = cpu_ldl_code(env, inst->cpc * 2);/* pc points to words */ +/* target is defined as bigendian for push_ret/pop_ret +optimization. but my decode assumes instruction to be in little +endian format, hence bswap +*/ +inst->opcode = bswap32(inst->opcode); +inst->length = 16; +inst->translate = NULL; + +/* the following function looks onto the opcode as a string of bytes */ +avr_decode(inst->cpc, &inst->length, inst->opcode, &inst->translate); + +if (inst->length == 16) { +inst->npc = inst->cpc + 1; +/* get opcode as 16bit value */ +inst->opcode = inst->opcode & 0x; +} +if (inst->length == 32) { +inst->npc = inst->cpc + 2; +/* get opcode as 32bit value */ +inst->opcode = (inst->opcode << 16) + | (inst->opcode >> 16); } } @@ -172,18 +149,21 @@ void gen_intermediate_code(CPUAVRState *env, struct TranslationBlock *tb) 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/ne
[Qemu-devel] [PATCH v5 10/10] target-avr: saving sreg, rampD, rampX, rampY, rampD, eind in HW representation saving cpu features
From: Michael Rolnik From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/machine.c | 105 --- 1 file changed, 84 insertions(+), 21 deletions(-) diff --git a/target-avr/machine.c b/target-avr/machine.c index 39f1ee6..9659c04 100644 --- a/target-avr/machine.c +++ b/target-avr/machine.c @@ -23,31 +23,94 @@ #include "cpu.h" #include "hw/boards.h" #include "machine.h" +#include "migration/qemu-file.h" + +static int get_sreg(QEMUFile *f, void *opaque, size_t size) +{ +CPUAVRState* env = opaque; +uint8_t sreg; + +qemu_get_8s(f, &sreg); +cpu_set_sreg(env, sreg); +return 0; +} + +static void put_sreg(QEMUFile *f, void *opaque, size_t size) +{ +CPUAVRState* env = opaque; +uint8_t sreg = cpu_get_sreg(env); + +qemu_put_8s(f, &sreg); +} + +static const VMStateInfo vmstate_sreg = { +.name = "sreg", +.get = get_sreg, +.put = put_sreg, +}; + +static int get_segment(QEMUFile *f, void *opaque, size_t size) +{ +uint32_t *ramp = opaque; +uint8_t temp = *ramp >> 16; + +qemu_get_8s(f, &temp); +return 0; +} + +static void put_segment(QEMUFile *f, void *opaque, size_t size) +{ +uint32_t *ramp = opaque; +uint8_t temp; + +qemu_put_8s(f, &temp); +*ramp = ((uint32_t)temp) << 16; +} + +static const VMStateInfo vmstate_rampD = { +.name = "rampD", +.get = get_segment, +.put = put_segment, +}; +static const VMStateInfo vmstate_rampX = { +.name = "rampX", +.get = get_segment, +.put = put_segment, +}; +static const VMStateInfo vmstate_rampY = { +.name = "rampY", +.get = get_segment, +.put = put_segment, +}; +static const VMStateInfo vmstate_rampZ = { +.name = "rampZ", +.get = get_segment, +.put = put_segment, +}; +static const VMStateInfo vmstate_eind = { +.name = "eind", +.get = get_segment, +.put = put_segment, +}; const VMStateDescription vmstate_avr_cpu = { .name = "cpu", -.version_id = 1, -.minimum_version_id = 1, +.version_id = 0, +.minimum_version_id = 0, .fields = (VMStateField[]) { -VMSTATE_UINT32_ARRAY(r, CPUAVRState, 32), - -VMSTATE_UINT32(sregC, CPUAVRState), -VMSTATE_UINT32(sregZ, CPUAVRState), -VMSTATE_UINT32(sregN, CPUAVRState), -VMSTATE_UINT32(sregV, CPUAVRState), -VMSTATE_UINT32(sregS, CPUAVRState), -VMSTATE_UINT32(sregH, CPUAVRState), -VMSTATE_UINT32(sregT, CPUAVRState), -VMSTATE_UINT32(sregI, CPUAVRState), - -VMSTATE_UINT32(rampD, CPUAVRState), -VMSTATE_UINT32(rampX, CPUAVRState), -VMSTATE_UINT32(rampY, CPUAVRState), -VMSTATE_UINT32(rampZ, CPUAVRState), - -VMSTATE_UINT32(eind, CPUAVRState), -VMSTATE_UINT32(sp, CPUAVRState), -VMSTATE_UINT32(pc_w, CPUAVRState), +VMSTATE_UINT32(env.features, AVRCPU), +VMSTATE_UINT32(env.pc_w, AVRCPU), +VMSTATE_UINT32(env.sp, AVRCPU), + +VMSTATE_UINT32_ARRAY(env.r, AVRCPU, 32), +VMSTATE_UINT32_ARRAY(env.io, AVRCPU, 64), + +VMSTATE_SINGLE_TEST(env, AVRCPU, NULL, 0, vmstate_sreg, CPUAVRState), +VMSTATE_SINGLE_TEST(env.rampD, AVRCPU, NULL, 0, vmstate_rampD, uint32_t), +VMSTATE_SINGLE_TEST(env.rampX, AVRCPU, NULL, 0, vmstate_rampX, uint32_t), +VMSTATE_SINGLE_TEST(env.rampY, AVRCPU, NULL, 0, vmstate_rampY, uint32_t), +VMSTATE_SINGLE_TEST(env.rampZ, AVRCPU, NULL, 0, vmstate_rampZ, uint32_t), +VMSTATE_SINGLE_TEST(env.eind, AVRCPU, NULL, 0, vmstate_eind, uint32_t), VMSTATE_END_OF_LIST() } -- 2.4.9 (Apple Git-60)
Re: [Qemu-devel] [PATCH v4 4/9] target-avr: adding instructions encodings
I can send the sources, of my generator if you want. However I have not time to make it a part of AVR patch right now. let's finish with AVR cores and then when I have time I will be happy to QEMUify the generator. On Tue, Jun 7, 2016 at 1:06 AM, Peter Maydell wrote: > On 6 June 2016 at 22:38, Richard Henderson wrote: > > On 06/06/2016 03:37 AM, Michael Rolnik wrote: > >> > >> Signed-off-by: Michael Rolnik > >> --- > >> target-avr/translate-inst.h | 730 > >> > >> 1 file changed, 730 insertions(+) > >> create mode 100644 target-avr/translate-inst.h > > > > > > Reviewed-by: Richard Henderson > > > > Although of course it would be better to have the generator > > and source instead of the generated code. > > Yes, definitely. (Especially since the GPL wants the 'preferred form > of the work for making modifications'...) > > thanks > -- PMM > -- Best Regards, Michael Rolnik
[Qemu-devel] [PATCH v6 00/11] 8bit AVR cores
This series of patches adds 8bit AVR cores to QEMU. All instruction, except BREAK/DES/SPM/SPMX, are implemented. Not fully tested yet. However I was able to execute simple code with functions. e.g fibonacci calculation. This series of patches include a non real, sample board. No fuses support yet. PC is set to 0 at reset. the patches include the following 1. just a basic 8bit AVR CPU, without instruction decoding or translation 2. CPU features which allow define the following 8bit AVR cores avr1 avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 xmega2 xmega4 xmega5 xmega6 xmega7 3. a definition of sample machine with SRAM, FLASH and CPU which allows to execute simple code 4. encoding for all AVR instructions 5. interrupt handling 6. helpers for IN, OUT, SLEEP, WBR & unsupported instructions 7. a decoder which given an opcode decides what istruction it is 8. translation of AVR instruction into TCG 9. all features together changes since v3 1. rampD/X/Y/Z registers are encoded as 0x00ff (instead of 0x00ff) for faster address manipulaton 2. ffs changed to ctz32 3. duplicate code removed at avr_cpu_do_interrupt 4. using andc instead of not + and 5. fixing V flag calculation in varios instructions 6. freeing local variables in PUSH 7. tcg_const_local_i32 -> tcg_const_i32 8. using sextract32 instead of my implementation 9. fixing BLD instruction 10.xor(r) instead of 0xff - r at COM 11.fixing MULS/MULSU not to modify inputs' content 12.using SUB for NEG 13.fixing tcg_gen_qemu_ld/st call in XCH changes since v4 1. target is now defined as big endian in order to optimize push_ret/pop_ret 2. all style warnings are fixed 3. adding cpu_set/get_sreg functions 4. simplifying gen_goto_tb as there is no real paging 5. env->pc -> env->pc_w 6. making flag dump more compact 7. more spacing 8. renaming CODE/DATA_INDEX -> MMU_CODE/DATA_IDX 9. removing avr_set_feature 10. SPL/SPH set bug fix 11. switching stb_phys to cpu_stb_data 12. cleaning up avr_decode 13. saving sreg, rampD/X/Y/Z, eind in HW format (savevm) 14. saving CPU features (savevm) changes since v5 1. BLD bug fix 2. decoder generator is added Michael Rolnik (11): target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions target-avr: adding AVR CPU features/flavors target-avr: adding a sample AVR board target-avr: adding instructions encodings target-avr: adding AVR interrupt handling target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions target-avr: adding instruction decoder target-avr: adding instruction translation target-avr: updating translate.c to use instructions translation target-avr: saving sreg, rampD, rampX, rampY, rampD, eind in HW representation saving cpu features target-avr: decoder generator. currently not used by the build, can be used manually arch_init.c|2 + configure |7 +- default-configs/avr-softmmu.mak| 21 + hw/Makefile.objs |1 + hw/avr/Makefile.objs | 21 + hw/avr/sample-io.c | 215 +++ hw/avr/sample.c| 118 ++ include/disas/bfd.h|6 + include/sysemu/arch_init.h |1 + target-avr/Makefile.objs | 25 + target-avr/cpu-qom.h | 84 + target-avr/cpu.c | 609 +++ target-avr/cpu.h | 211 +++ target-avr/cpugen/CMakeLists.txt | 38 + target-avr/cpugen/README.md| 17 + target-avr/cpugen/cpu/avr.yaml | 218 +++ target-avr/cpugen/src/CMakeLists.txt | 62 + target-avr/cpugen/src/cpugen.cpp | 510 ++ target-avr/cpugen/src/utils.cpp| 27 + target-avr/cpugen/src/utils.h | 84 + target-avr/cpugen/xsl/decode.c.xsl | 103 ++ target-avr/cpugen/xsl/translate-inst.h.xsl | 118 ++ target-avr/cpugen/xsl/utils.xsl| 108 ++ target-avr/decode.c| 693 target-avr/gdbstub.c | 99 ++ target-avr/helper.c| 269 +++ target-avr/helper.h| 26 + target-avr/machine.c | 117 ++ target-avr/machine.h | 21 + target-avr/translate-inst.c| 2624 target-avr/translate-inst.h| 762 target-avr/translate.c | 274 +++ target-avr/translate.h | 119 ++ 33 files changed, 7609 insertions(+), 1 deletion(-) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 hw/avr/Makefile.objs create mode 100644 hw/avr/sample-io.c create mode 100644
[Qemu-devel] [PATCH v6 02/11] target-avr: adding AVR CPU features/flavors
From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/cpu.c | 307 ++- target-avr/cpu.h | 53 ++ 2 files changed, 359 insertions(+), 1 deletion(-) diff --git a/target-avr/cpu.c b/target-avr/cpu.c index 99bd788..197f9ac 100644 --- a/target-avr/cpu.c +++ b/target-avr/cpu.c @@ -203,6 +203,296 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) dc->cannot_destroy_with_object_finalize_yet = 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
[Qemu-devel] [PATCH v6 01/11] target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions
From: Michael Rolnik Signed-off-by: Michael Rolnik --- arch_init.c | 2 + configure | 7 +- default-configs/avr-softmmu.mak | 21 +++ include/disas/bfd.h | 6 + include/sysemu/arch_init.h | 1 + target-avr/Makefile.objs| 23 +++ target-avr/cpu-qom.h| 84 +++ target-avr/cpu.c| 304 target-avr/cpu.h| 158 + target-avr/gdbstub.c| 99 + target-avr/helper.c | 87 target-avr/helper.h | 21 +++ target-avr/machine.c| 54 +++ target-avr/machine.h| 21 +++ target-avr/translate.c | 290 ++ 15 files changed, 1177 insertions(+), 1 deletion(-) create mode 100644 default-configs/avr-softmmu.mak create mode 100644 target-avr/Makefile.objs create mode 100644 target-avr/cpu-qom.h create mode 100644 target-avr/cpu.c create mode 100644 target-avr/cpu.h create mode 100644 target-avr/gdbstub.c create mode 100644 target-avr/helper.c create mode 100644 target-avr/helper.h create mode 100644 target-avr/machine.c create mode 100644 target-avr/machine.h create mode 100644 target-avr/translate.c diff --git a/arch_init.c b/arch_init.c index fa05973..be6e6de 100644 --- a/arch_init.c +++ b/arch_init.c @@ -80,6 +80,8 @@ int graphic_depth = 32; #define QEMU_ARCH QEMU_ARCH_UNICORE32 #elif defined(TARGET_TRICORE) #define QEMU_ARCH QEMU_ARCH_TRICORE +#elif defined(TARGET_AVR) +#define QEMU_ARCH QEMU_ARCH_AVR #endif const uint32_t arch_type = QEMU_ARCH; diff --git a/configure b/configure index 8c2f90b..41e550e 100755 --- a/configure +++ b/configure @@ -5603,7 +5603,7 @@ target_name=$(echo $target | cut -d '-' -f 1) target_bigendian="no" case "$target_name" in - armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) + avr|armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb) target_bigendian=yes ;; esac @@ -5652,6 +5652,8 @@ case "$target_name" in x86_64) TARGET_BASE_ARCH=i386 ;; + avr) + ;; alpha) ;; arm|armeb) @@ -5848,6 +5850,9 @@ disas_config() { for i in $ARCH $TARGET_BASE_ARCH ; do case "$i" in + avr) +disas_config "AVR" + ;; alpha) disas_config "ALPHA" ;; diff --git a/default-configs/avr-softmmu.mak b/default-configs/avr-softmmu.mak new file mode 100644 index 000..003465d --- /dev/null +++ b/default-configs/avr-softmmu.mak @@ -0,0 +1,21 @@ +# +# 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> +# + +# Default configuration for avr-softmmu diff --git a/include/disas/bfd.h b/include/disas/bfd.h index a112e9c..b13fc53 100644 --- a/include/disas/bfd.h +++ b/include/disas/bfd.h @@ -213,6 +213,12 @@ enum bfd_architecture #define bfd_mach_m32r 0 /* backwards compatibility */ bfd_arch_mn10200,/* Matsushita MN10200 */ bfd_arch_mn10300,/* Matsushita MN10300 */ + bfd_arch_avr, /* Atmel AVR microcontrollers. */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr3 3 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 bfd_arch_cris, /* Axis CRIS */ #define bfd_mach_cris_v0_v10 255 #define bfd_mach_cris_v32 32 diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h index d690dfa..8c75777 100644 --- a/include/sysemu/arch_init.h +++ b/include/sysemu/arch_init.h @@ -23,6 +23,7 @@ enum { QEMU_ARCH_UNICORE32 = (1 << 14), QEMU_ARCH_MOXIE = (1 << 15), QEMU_ARCH_TRICORE = (1 << 16), +QEMU_ARCH_AVR = (1 << 17), }; extern const uint32_t arch_type; diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs new file mode 100644 index 000..2a10104 --- /dev/null +++ b/target-avr/Makefile.objs @@ -0,0 +1,23 @@ +# +# QEMU AVR CPU +# +# Copyright (c) 2016 Michael Rolnik +# +# This library is free software; you can redistribute it and/or +# modi
[Qemu-devel] [PATCH v6 05/11] target-avr: adding AVR interrupt handling
From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/helper.c | 59 - 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/target-avr/helper.c b/target-avr/helper.c index ad8f83e..f96fa27 100644 --- a/target-avr/helper.c +++ b/target-avr/helper.c @@ -31,11 +31,68 @@ 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 = ctz32(env->intsrc); +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_w; +int vector = 0; +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 = ctz32(env->intsrc) + 1; +} + +if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +stb_phys(cs->as, env->sp--, (ret & 0xff) >> 16); +} else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +} else { +stb_phys(cs->as, env->sp--, (ret & 0xff)); +} + +env->pc_w = base + vector * size; +env->sregI = 0;/* clear Global Interrupt Flag */ + +cs->exception_index = -1; } int avr_cpu_memory_rw_debug(CPUState *cs, vaddr addr, uint8_t *buf, -- 2.4.9 (Apple Git-60)
[Qemu-devel] [PATCH v6 03/11] target-avr: adding a sample AVR board
From: Michael Rolnik Signed-off-by: Michael Rolnik --- hw/Makefile.objs | 1 + hw/avr/Makefile.objs | 21 + hw/avr/sample-io.c | 215 +++ hw/avr/sample.c | 118 4 files changed, 355 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 000..c080e4e --- /dev/null +++ b/hw/avr/Makefile.objs @@ -0,0 +1,21 @@ +# +# 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> +# + +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 000..e0fee77 --- /dev/null +++ b/hw/avr/sample-io.c @@ -0,0 +1,215 @@ +/* + * 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_SIZE0x0020 +#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_BASE0x +#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 { +SysBusDeviceparent; + +MemoryRegioniomem; + +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, +
[Qemu-devel] [PATCH v6 04/11] target-avr: adding instructions encodings
From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/translate-inst.h | 762 1 file changed, 762 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 000..0c082d3 --- /dev/null +++ b/target-avr/translate-inst.h @@ -0,0 +1,762 @@ +/* + * 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_ + +typedef struct DisasContextDisasContext; + +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_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t CPC_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_SBC(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t SBC_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t SBC_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_ADD(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t ADD_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t ADD_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_AND(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t AND_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t AND_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_EOR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t EOR_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t EOR_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_OR(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t OR_Rd(uint32_t opcode) +{ +return extract32(opcode, 4, 5); +} +static inline uint32_t OR_Rr(uint32_t opcode) +{ +return (extract32(opcode, 9, 1) << 4) | +(extract32(opcode, 0, 4)); +} + +int avr_translate_MOV(CPUAVRState *env, DisasContext* ctx, uint32_t opcode); +static inline uint32_t MOV_Rd(uint32
[Qemu-devel] [PATCH v6 06/11] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/helper.c | 145 target-avr/helper.h | 5 ++ 2 files changed, 140 insertions(+), 10 deletions(-) diff --git a/target-avr/helper.c b/target-avr/helper.c index f96fa27..9e2b52a 100644 --- a/target-avr/helper.c +++ b/target-avr/helper.c @@ -42,14 +42,14 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) cs->exception_index = EXCP_RESET; cc->do_interrupt(cs); -cs->interrupt_request &= ~CPU_INTERRUPT_RESET; +cs->interrupt_request &= ~CPU_INTERRUPT_RESET; ret = true; } } if (interrupt_request & CPU_INTERRUPT_HARD) { if (cpu_interrupts_enabled(env) && env->intsrc != 0) { -int index = ctz32(env->intsrc); +int index = ctz32(env->intsrc); cs->exception_index = EXCP_INT(index); cc->do_interrupt(cs); @@ -64,8 +64,8 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) void avr_cpu_do_interrupt(CPUState *cs) { -AVRCPU *cpu = AVR_CPU(cs); -CPUAVRState*env = &cpu->env; +AVRCPU *cpu = AVR_CPU(cs); +CPUAVRState *env = &cpu->env; uint32_t ret = env->pc_w; int vector = 0; @@ -79,14 +79,14 @@ void avr_cpu_do_interrupt(CPUState *cs) } if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { -stb_phys(cs->as, env->sp--, (ret & 0xff)); -stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); -stb_phys(cs->as, env->sp--, (ret & 0xff) >> 16); +cpu_stb_data(env, env->sp--, (ret & 0xff)); +cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); +cpu_stb_data(env, env->sp--, (ret & 0xff) >> 16); } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { -stb_phys(cs->as, env->sp--, (ret & 0xff)); -stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +cpu_stb_data(env, env->sp--, (ret & 0xff)); +cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); } else { -stb_phys(cs->as, env->sp--, (ret & 0xff)); +cpu_stb_data(env, env->sp--, (ret & 0xff)); } env->pc_w = base + vector * size; @@ -133,6 +133,28 @@ void tlb_fill(CPUState *cs, target_ulong vaddr, int is_write, 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)); + +/* +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, qemu_logfile, fprintf, 0); +} +cpu_loop_exit(cs); +} void helper_debug(CPUAVRState *env) { @@ -142,3 +164,106 @@ void helper_debug(CPUAVRState *env) cpu_loop_exit(cs); } +void helper_wdr(CPUAVRState *env) +{ +CPUState *cs = CPU(avr_env_get_cpu(env)); + +/* +WD is not implemented yet, placeholder +*/ +cs->exception_index = EXCP_DEBUG; +cpu_loop_exit(cs); +} + +target_ulong helper_inb(CPUAVRState *env, uint32_t port) +{ +qemu_log("in: io[%02x]\n", port); + +switch (port) { +case0x38: { +return 0xff & (env->rampD >> 16); /* RAMPD */ +} +case0x39: { +return 0xff & (env->rampX >> 16); /* RAMPX */ +} +case0x3a: { +return 0xff & (env->rampY >> 16); /* RAMPY */ +} +case0x3b: { +return 0xff & (env->rampZ >> 16); /* RAMPZ */ +} +case0x3c: { +return 0xff & (env->eind >> 16); /* EIND*/ +} +case0x3d: { /* SPL */ +return env->sp & 0x00ff; +} +case0x3e: { /* SPH */ +return env->sp >> 8; +} +case0x3f: { /* SREG*/ +return cpu_get_sreg(env); +} +} +return 0; +} + +void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) +{ +qemu_log("out:%02x -> io[%02x]\n", data, port); + +data&= 0x00ff; + +switch (port) { +case0x04: { +qemu_irqirq; +CPUState *cpu = CPU(avr_env_get_cpu(env))
[Qemu-devel] [PATCH v6 09/11] target-avr: updating translate.c to use instructions translation
From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/Makefile.objs | 4 +- target-avr/translate.c | 148 +-- 2 files changed, 69 insertions(+), 83 deletions(-) diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs index 2a10104..9757721 100644 --- a/target-avr/Makefile.objs +++ b/target-avr/Makefile.objs @@ -18,6 +18,8 @@ # <http://www.gnu.org/licenses/lgpl-2.1.html> # -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 81ee44e..28babc9 100644 --- a/target-avr/translate.c +++ b/target-avr/translate.c @@ -18,60 +18,30 @@ * <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,25 +90,32 @@ 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; - -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); +CPUAVRState*env = &cpu->env; + +inst->opcode = cpu_ldl_code(env, inst->cpc * 2);/* pc points to words */ +/* target is defined as bigendian for push_ret/pop_ret +optimization. but my decode assumes instruction to be in little +endian format, hence bswap +*/ +inst->opcode = bswap32(inst->opcode); +inst->length = 16; +inst->translate = NULL; + +/* the following function looks onto the opcode as a string of bytes */ +avr_decode(inst->cpc, &inst->length, inst->opcode, &inst->translate); + +if (inst->length == 16) { +inst->npc = inst->cpc + 1; +/* get opcode as 16bit value */ +inst->opcode = inst->opcode & 0x; +} +if (inst->length == 32) { +inst->npc = inst->cpc + 2; +/* get opcode as 32bit value */ +inst->opcode = (inst->opcode << 16) + | (inst->opcode >> 16); } } @@ -172,18 +149,21 @@ void gen_intermediate_code(CPUAVRState *env, struct TranslationBlock *tb) 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/ne
[Qemu-devel] [PATCH v6 07/11] target-avr: adding instruction decoder
From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/decode.c | 693 1 file changed, 693 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 000..44a5815 --- /dev/null +++ b/target-avr/decode.c @@ -0,0 +1,693 @@ +/* + * 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 +#include "translate.h" + +void avr_decode(uint32_t pc, uint32_t *l, uint32_t c, translate_function_t *t) +{ +uint32_t opc = extract32(c, 0, 16); +switch (opc & 0xd000) { +case 0x: { +switch (opc & 0x2c00) { +case 0x: { +switch (opc & 0x0300) { +case 0x: { +*l = 16; +*t = &avr_translate_NOP; +break; +} +case 0x0100: { +*l = 16; +*t = &avr_translate_MOVW; +break; +} +case 0x0200: { +*l = 16; +*t = &avr_translate_MULS; +break; +} +case 0x0300: { +switch (opc & 0x0088) { +case 0x: { +*l = 16; +*t = &avr_translate_MULSU; +break; +} +case 0x0008: { +*l = 16; +*t = &avr_translate_FMUL; +break; +} +case 0x0080: { +*l = 16; +*t = &avr_translate_FMULS; +break; +} +case 0x0088: { +*l = 16; +*t = &avr_translate_FMULSU; +break; +} +} +break; +} +} +break; +} +case 0x0400: { +*l = 16; +*t = &avr_translate_CPC; +break; +} +case 0x0800: { +*l = 16; +*t = &avr_translate_SBC; +break; +} +case 0x0c00: { +*l = 16; +*t = &avr_translate_ADD; +break; +} +case 0x2000: { +*l = 16; +*t = &avr_translate_AND; +break; +} +case 0x2400: { +*l = 16; +*t = &avr_translate_EOR; +break; +} +case 0x2800: { +*l = 16; +*t = &avr_translate_OR; +break; +} +case 0x2c00: { +*l = 16; +*t = &avr_translate_MOV; +break; +} +} +break; +} +case 0x1000: { +switch (opc & 0x2000) { +case 0x: { +switch (opc & 0x0c00) { +case 0x: { +*l = 16; +*t = &avr_translate_CPSE; +break; +} +case 0x0
[Qemu-devel] [PATCH v6 11/11] target-avr: decoder generator. currently not used by the build, can be used manually
From: Michael Rolnik --- target-avr/cpugen/CMakeLists.txt | 38 +++ target-avr/cpugen/README.md| 17 + target-avr/cpugen/cpu/avr.yaml | 218 target-avr/cpugen/src/CMakeLists.txt | 62 target-avr/cpugen/src/cpugen.cpp | 510 + target-avr/cpugen/src/utils.cpp| 27 ++ target-avr/cpugen/src/utils.h | 84 + target-avr/cpugen/xsl/decode.c.xsl | 103 ++ target-avr/cpugen/xsl/translate-inst.h.xsl | 118 +++ target-avr/cpugen/xsl/utils.xsl| 108 ++ 10 files changed, 1285 insertions(+) create mode 100644 target-avr/cpugen/CMakeLists.txt create mode 100644 target-avr/cpugen/README.md create mode 100644 target-avr/cpugen/cpu/avr.yaml create mode 100644 target-avr/cpugen/src/CMakeLists.txt create mode 100644 target-avr/cpugen/src/cpugen.cpp create mode 100644 target-avr/cpugen/src/utils.cpp create mode 100644 target-avr/cpugen/src/utils.h create mode 100644 target-avr/cpugen/xsl/decode.c.xsl create mode 100644 target-avr/cpugen/xsl/translate-inst.h.xsl create mode 100644 target-avr/cpugen/xsl/utils.xsl diff --git a/target-avr/cpugen/CMakeLists.txt b/target-avr/cpugen/CMakeLists.txt new file mode 100644 index 000..eb7b754 --- /dev/null +++ b/target-avr/cpugen/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 2.8) + +project(cpugen) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb -g3") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + +set(Boost_USE_STATIC_LIBS ON) +find_package( +Boost 1.60.0 +REQUIRED +COMPONENTS +system +regex) +#set(BUILD_SHARED_LIBS OFF) +#set(BUILD_STATIC_LIBS ON) +add_subdirectory(tinyxml2) +add_subdirectory(yaml-cpp) + +include_directories( +${CMAKE_CURRENT_SOURCE_DIR} +${CMAKE_CURRENT_SOURCE_DIR}/.. +${CMAKE_CURRENT_SOURCE_DIR}/../yaml-cpp/include +${Boost_INCLUDE_DIRS} +) + +add_executable( +cpugen +src/cpugen.cpp +src/utils.cpp +) + +target_link_libraries( +cpugen +yaml-cpp +tinyxml2 +${Boost_LIBRARIES} +) diff --git a/target-avr/cpugen/README.md b/target-avr/cpugen/README.md new file mode 100644 index 000..dfa7d32 --- /dev/null +++ b/target-avr/cpugen/README.md @@ -0,0 +1,17 @@ +# CPUGEN +## How to build +within ```cpugen``` directory do +``` +git clone https://github.com/leethomason/tinyxml2 +git clone https://github.com/jbeder/yaml-cpp +mkdir build +cd build +cmake .. +make +``` +## How to use +``` +cpugen ../cpu/avr.yaml +xsltproc ../xsl/decode.c.xsl output.xml > ../../decode.c +xsltproc ../xsl/translate-inst.h.xsl output.xml > ../../translate-inst.h +``` diff --git a/target-avr/cpugen/cpu/avr.yaml b/target-avr/cpugen/cpu/avr.yaml new file mode 100644 index 000..adf209a --- /dev/null +++ b/target-avr/cpugen/cpu/avr.yaml @@ -0,0 +1,218 @@ +cpu: +name: avr +instructions: +- ADC: +opcode: 0001 11 hRr[1] Rd[5] lRr[4] +- ADD: +opcode: 11 hRr[1] Rd[5] lRr[4] +- ADIW: +opcode: 1001 0110 hImm[2] Rd[2] lImm[4] +- AND: +opcode: 0010 00 hRr[1] Rd[5] lRr[4] +- ANDI: +opcode: 0111 hImm[4] Rd[4] lImm[4] +- ASR: +opcode: 1001 010 Rd[5] 0101 +- BCLR: +opcode: 1001 0100 1 Bit[3] 1000 +- BLD: +opcode: 100 Rd[5] 0 Bit[3] +- BRBC: +opcode: 01 Imm[7] Bit[3] +- BRBS: +opcode: 00 Imm[7] Bit[3] +- BREAK: +opcode: 1001 0101 1001 1000 +- BSET: +opcode: 1001 0100 0 Bit[3] 1000 +- BST: +opcode: 101 Rd[5] 0 Bit[3] +- CALL: +opcode: 1001 010 hImm[5] 111 lImm[17] +- CBI: +opcode: 1001 1000 Imm[5] Bit[3] +- COM: +opcode: 1001 010 Rd[5] +- CP: +opcode: 0001 01 hRr[1] Rd[5] lRr[4] +- CPC: +opcode: 01 hRr[1] Rd[5] lRr[4] +- CPI: +opcode: 0011 hImm[4] Rd[4] lImm[4] +- CPSE: +opcode: 0001 00 hRr[1] Rd[5] lRr[4] +- DEC: +opcode: 1001 010 Rd[5] 1010 +- DES: +opcode: 1001 0100 Imm[4] 1011 +- EICALL: +opcode: 1001 0101 0001 1001 +- EIJMP: +opcode: 1001 0100 0001 1001 +- ELPM1: +opcode: 1001 0101 1101 1000 +- ELPM2: +opcode: 1001 000 Rd[5] 0110 +- ELPMX: +opcode: 1001 000 Rd[5] 0111 +- EOR: +opcode: 0010 01 hRr[1] Rd[5] lRr[4] +- FMUL: +opcode: 0011 0 Rd[3] 1 Rr[3] +- FMULS: +opcode: 0011 1 Rd[3] 0 Rr[3] +- FMULSU: +opcode: 0011 1 Rd[3] 1 Rr[3] +- ICALL: +o
[Qemu-devel] [PATCH v6 10/11] target-avr: saving sreg, rampD, rampX, rampY, rampD, eind in HW representation saving cpu features
From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/machine.c | 105 --- 1 file changed, 84 insertions(+), 21 deletions(-) diff --git a/target-avr/machine.c b/target-avr/machine.c index 39f1ee6..9659c04 100644 --- a/target-avr/machine.c +++ b/target-avr/machine.c @@ -23,31 +23,94 @@ #include "cpu.h" #include "hw/boards.h" #include "machine.h" +#include "migration/qemu-file.h" + +static int get_sreg(QEMUFile *f, void *opaque, size_t size) +{ +CPUAVRState* env = opaque; +uint8_t sreg; + +qemu_get_8s(f, &sreg); +cpu_set_sreg(env, sreg); +return 0; +} + +static void put_sreg(QEMUFile *f, void *opaque, size_t size) +{ +CPUAVRState* env = opaque; +uint8_t sreg = cpu_get_sreg(env); + +qemu_put_8s(f, &sreg); +} + +static const VMStateInfo vmstate_sreg = { +.name = "sreg", +.get = get_sreg, +.put = put_sreg, +}; + +static int get_segment(QEMUFile *f, void *opaque, size_t size) +{ +uint32_t *ramp = opaque; +uint8_t temp = *ramp >> 16; + +qemu_get_8s(f, &temp); +return 0; +} + +static void put_segment(QEMUFile *f, void *opaque, size_t size) +{ +uint32_t *ramp = opaque; +uint8_t temp; + +qemu_put_8s(f, &temp); +*ramp = ((uint32_t)temp) << 16; +} + +static const VMStateInfo vmstate_rampD = { +.name = "rampD", +.get = get_segment, +.put = put_segment, +}; +static const VMStateInfo vmstate_rampX = { +.name = "rampX", +.get = get_segment, +.put = put_segment, +}; +static const VMStateInfo vmstate_rampY = { +.name = "rampY", +.get = get_segment, +.put = put_segment, +}; +static const VMStateInfo vmstate_rampZ = { +.name = "rampZ", +.get = get_segment, +.put = put_segment, +}; +static const VMStateInfo vmstate_eind = { +.name = "eind", +.get = get_segment, +.put = put_segment, +}; const VMStateDescription vmstate_avr_cpu = { .name = "cpu", -.version_id = 1, -.minimum_version_id = 1, +.version_id = 0, +.minimum_version_id = 0, .fields = (VMStateField[]) { -VMSTATE_UINT32_ARRAY(r, CPUAVRState, 32), - -VMSTATE_UINT32(sregC, CPUAVRState), -VMSTATE_UINT32(sregZ, CPUAVRState), -VMSTATE_UINT32(sregN, CPUAVRState), -VMSTATE_UINT32(sregV, CPUAVRState), -VMSTATE_UINT32(sregS, CPUAVRState), -VMSTATE_UINT32(sregH, CPUAVRState), -VMSTATE_UINT32(sregT, CPUAVRState), -VMSTATE_UINT32(sregI, CPUAVRState), - -VMSTATE_UINT32(rampD, CPUAVRState), -VMSTATE_UINT32(rampX, CPUAVRState), -VMSTATE_UINT32(rampY, CPUAVRState), -VMSTATE_UINT32(rampZ, CPUAVRState), - -VMSTATE_UINT32(eind, CPUAVRState), -VMSTATE_UINT32(sp, CPUAVRState), -VMSTATE_UINT32(pc_w, CPUAVRState), +VMSTATE_UINT32(env.features, AVRCPU), +VMSTATE_UINT32(env.pc_w, AVRCPU), +VMSTATE_UINT32(env.sp, AVRCPU), + +VMSTATE_UINT32_ARRAY(env.r, AVRCPU, 32), +VMSTATE_UINT32_ARRAY(env.io, AVRCPU, 64), + +VMSTATE_SINGLE_TEST(env, AVRCPU, NULL, 0, vmstate_sreg, CPUAVRState), +VMSTATE_SINGLE_TEST(env.rampD, AVRCPU, NULL, 0, vmstate_rampD, uint32_t), +VMSTATE_SINGLE_TEST(env.rampX, AVRCPU, NULL, 0, vmstate_rampX, uint32_t), +VMSTATE_SINGLE_TEST(env.rampY, AVRCPU, NULL, 0, vmstate_rampY, uint32_t), +VMSTATE_SINGLE_TEST(env.rampZ, AVRCPU, NULL, 0, vmstate_rampZ, uint32_t), +VMSTATE_SINGLE_TEST(env.eind, AVRCPU, NULL, 0, vmstate_eind, uint32_t), VMSTATE_END_OF_LIST() } -- 2.4.9 (Apple Git-60)
[Qemu-devel] [PATCH v6 08/11] target-avr: adding instruction translation
From: Michael Rolnik Signed-off-by: Michael Rolnik --- target-avr/translate-inst.c | 2624 +++ target-avr/translate.h | 119 ++ 2 files changed, 2743 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 000..2e24335 --- /dev/null +++ b/target-avr/translate-inst.c @@ -0,0 +1,2624 @@ +/* + * 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" +#include "qemu/bitops.h" + +static void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr); +static void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr); +static void gen_sub_CHf(TCGv R, TCGv Rd, TCGv Rr); +static void gen_sub_Vf(TCGv R, TCGv Rd, TCGv Rr); +static void gen_ZNSf(TCGv R); +static void gen_push_ret(CPUAVRState *env, int ret); +static void gen_pop_ret(CPUAVRState *env, TCGv ret); +static void gen_jmp_ez(void); +static void gen_jmp_z(void); + +/* +in the following 2 functions +H assumed to be in 0x00ff format +M assumed to be in 0x00ff format +L assumed to be in 0x00ff format +*/ +static void gen_set_addr(TCGv addr, TCGv H, TCGv M, TCGv l); /* H:M:L = addr */ +static TCGv gen_get_addr(TCGv H, TCGv M, TCGv L);/* addr = H:M:L */ + +static void gen_set_xaddr(TCGv addr); +static void gen_set_yaddr(TCGv addr); +static void gen_set_zaddr(TCGv addr); + +static TCGv gen_get_xaddr(void); +static TCGv gen_get_yaddr(void); +static TCGv gen_get_zaddr(void); + +void gen_add_CHf(TCGv R, TCGv Rd, TCGv Rr) +{ +TCGv t1 = tcg_temp_new_i32(); +TCGv t2 = tcg_temp_new_i32(); +TCGv t3 = tcg_temp_new_i32(); + +tcg_gen_and_tl(t1, Rd, Rr); /* t1 = Rd & Rr */ +tcg_gen_andc_tl(t2, Rd, R); /* t2 = Rd & ~R */ +tcg_gen_andc_tl(t3, Rr, R); /* t3 = Rr & ~R */ +tcg_gen_or_tl(t1, t1, t2); /* t1 = t1 | t2 | t3 */ +tcg_gen_or_tl(t1, t1, t3); + +tcg_gen_shri_tl(cpu_Cf, t1, 7); /* Cf = t1(7) */ +tcg_gen_shri_tl(cpu_Hf, t1, 3); /* Hf = t1(3) */ +tcg_gen_andi_tl(cpu_Hf, cpu_Hf, 1); + +tcg_temp_free_i32(t3); +tcg_temp_free_i32(t2); +tcg_temp_free_i32(t1); +} + +void gen_add_Vf(TCGv R, TCGv Rd, TCGv Rr) +{ +TCGv t1 = tcg_temp_new_i32(); +TCGv t2 = tcg_temp_new_i32(); + +/* t1 = Rd & Rr & ~R | ~Rd & ~Rr & R = (Rd ^ R) & ~(Rd ^ Rr) */ +tcg_gen_xor_tl(t1, Rd, R); +tcg_gen_xor_tl(t2, Rd, Rr); +tcg_gen_andc_tl(t1, t1, t2); + +tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + +tcg_temp_free_i32(t2); +tcg_temp_free_i32(t1); +} + +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 */ +/* t1 = Rd & ~Rr & ~R | ~Rd & Rr & R = (Rd ^ R) & (Rd ^ R)*/ +tcg_gen_xor_tl(t1, Rd, R); +tcg_gen_xor_tl(t2, Rd, Rr); +tcg_gen_and_tl(t1, t1, t2); +tcg_gen_shri_tl(cpu_Vf, t1, 7); /* Vf = t1(7) */ + +tcg_temp_free_i32(t2); +tcg_temp_free_i32(t1); +} + +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_xor_tl(cpu_Sf, cpu_Nf, cpu_Vf); /* Sf = Nf ^ Vf */ +} + +void gen_push_ret(CPUAVRState *env, int ret) +{ +if (avr_feature(env, AVR_FE
Re: [Qemu-devel] [PATCH v6 08/11] target-avr: adding instruction translation
what is the difference between tcg_gen_qemu_st16 and tcg_gen_qemu_st_tl On Mon, Jun 13, 2016 at 7:06 PM, Richard Henderson wrote: > On 06/12/2016 12:01 PM, Michael Rolnik wrote: > >> +void gen_push_ret(CPUAVRState *env, int ret) >> +{ >> +if (avr_feature(env, AVR_FEATURE_1_BYTE_PC)) { >> + >> +TCGv t0 = tcg_const_i32((ret & 0xff)); >> + >> +tcg_gen_qemu_st8(t0, cpu_sp, MMU_DATA_IDX); >> +tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); >> + >> +tcg_temp_free_i32(t0); >> +} else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { >> + >> +TCGv t0 = tcg_const_i32((ret & 0x00)); >> + >> +tcg_gen_qemu_st16(t0, cpu_sp, MMU_DATA_IDX); >> +tcg_gen_subi_tl(cpu_sp, cpu_sp, 2); >> > > This stores to the wrong bytes. You need > > tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); > tcg_gen_qemu_st_tl(t0, cpu_sp, MMU_DATA_IDX, MO_BEUW); > tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); > > +} else if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { >> + >> +TCGv t0 = tcg_const_i32((ret & 0xff)); >> +TCGv t1 = tcg_const_i32((ret & 0x00) >> 8); >> + >> +tcg_gen_qemu_st8(t0, cpu_sp, MMU_DATA_IDX); >> +tcg_gen_subi_tl(cpu_sp, cpu_sp, 1); >> + >> +tcg_gen_qemu_st16(t1, cpu_sp, MMU_DATA_IDX); >> +tcg_gen_subi_tl(cpu_sp, cpu_sp, 2); >> > > Similarly. > > +void gen_pop_ret(CPUAVRState *env, TCGv ret) >> +{ >> +if (avr_feature(env, AVR_FEATURE_1_BYTE_PC)) { >> + >> +tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); >> +tcg_gen_qemu_ld8u(ret, cpu_sp, MMU_DATA_IDX); >> +} else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { >> + >> +tcg_gen_addi_tl(cpu_sp, cpu_sp, 2); >> +tcg_gen_qemu_ld16u(ret, cpu_sp, MMU_DATA_IDX); >> > > Similarly, > > tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); > tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW); > tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); > > > +} else if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { >> + >> +TCGv t0 = tcg_temp_new_i32(); >> + >> +tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); >> +tcg_gen_qemu_ld8u(ret, cpu_sp, MMU_DATA_IDX); >> + >> +tcg_gen_addi_tl(cpu_sp, cpu_sp, 2); >> +tcg_gen_qemu_ld16u(t0, cpu_sp, MMU_DATA_IDX); >> + >> +tcg_gen_shli_tl(t0, t0, 16); >> +tcg_gen_or_tl(ret, ret, t0); >> > > You're putting t0 at the wrong end. > > tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); > tcg_gen_qemu_ld_tl(t0, cpu_sp, MMU_DATA_IDX, MO_UB); > tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); > tcg_gen_qemu_ld_tl(ret, cpu_sp, MMU_DATA_IDX, MO_BEUW); > tcg_gen_addi_tl(cpu_sp, cpu_sp, 1); > tcg_gen_deposit_tl(ret, ret, t0, 16, 8); > > > > r~ > -- Best Regards, Michael Rolnik
[Qemu-devel] [PATCH v7 00/12] 8bit AVR cores
This series of patches adds 8bit AVR cores to QEMU. All instruction, except BREAK/DES/SPM/SPMX, are implemented. Not fully tested yet. However I was able to execute simple code with functions. e.g fibonacci calculation. This series of patches include a non real, sample board. No fuses support yet. PC is set to 0 at reset. the patches include the following 1. just a basic 8bit AVR CPU, without instruction decoding or translation 2. CPU features which allow define the following 8bit AVR cores avr1 avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 xmega2 xmega4 xmega5 xmega6 xmega7 3. a definition of sample machine with SRAM, FLASH and CPU which allows to execute simple code 4. encoding for all AVR instructions 5. interrupt handling 6. helpers for IN, OUT, SLEEP, WBR & unsupported instructions 7. a decoder which given an opcode decides what istruction it is 8. translation of AVR instruction into TCG 9. all features together changes since v3 1. rampD/X/Y/Z registers are encoded as 0x00ff (instead of 0x00ff) for faster address manipulaton 2. ffs changed to ctz32 3. duplicate code removed at avr_cpu_do_interrupt 4. using andc instead of not + and 5. fixing V flag calculation in varios instructions 6. freeing local variables in PUSH 7. tcg_const_local_i32 -> tcg_const_i32 8. using sextract32 instead of my implementation 9. fixing BLD instruction 10.xor(r) instead of 0xff - r at COM 11.fixing MULS/MULSU not to modify inputs' content 12.using SUB for NEG 13.fixing tcg_gen_qemu_ld/st call in XCH changes since v4 1. target is now defined as big endian in order to optimize push_ret/pop_ret 2. all style warnings are fixed 3. adding cpu_set/get_sreg functions 4. simplifying gen_goto_tb as there is no real paging 5. env->pc -> env->pc_w 6. making flag dump more compact 7. more spacing 8. renaming CODE/DATA_INDEX -> MMU_CODE/DATA_IDX 9. removing avr_set_feature 10. SPL/SPH set bug fix 11. switching stb_phys to cpu_stb_data 12. cleaning up avr_decode 13. saving sreg, rampD/X/Y/Z, eind in HW format (savevm) 14. saving CPU features (savevm) changes since v5 1. BLD bug fix 2. decoder generator is added chages since v6 1. using cpu_get_sreg/cpu_set_sreg in avr_cpu_gdb_read_register/avr_cpu_gdb_write_register 2. configure the target as little endian because otherwise GDB does not work 3. fixing and testing gen_push_ret/gen_pop_ret Michael Rolnik (12): target-avr: AVR cores support is added. 1. basic CPU structure 2. registers 3. no instructions target-avr: adding AVR CPU features/flavors target-avr: adding a sample AVR board target-avr: adding instructions encodings target-avr: adding AVR interrupt handling target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions target-avr: adding instruction decoder target-avr: adding instruction translation target-avr: updating translate.c to use instructions translation target-avr: saving sreg, rampD, rampX, rampY, rampD, eind in HW representation saving cpu features target-avr: decoder generator. currently not used by the build, can be used manually target-avr: 1. use cpu_get/set_sreg function at avr_cpu_gdb_read_register/avr_cpu_gdb_read_register 2. configuring target as little endian 3. fixing and testing gen_push_ret/gen_pop_ret arch_init.c|2 + configure |5 + default-configs/avr-softmmu.mak| 21 + hw/Makefile.objs |1 + hw/avr/Makefile.objs | 21 + hw/avr/sample-io.c | 215 +++ hw/avr/sample.c| 118 ++ include/disas/bfd.h|6 + include/sysemu/arch_init.h |1 + target-avr/Makefile.objs | 25 + target-avr/cpu-qom.h | 84 + target-avr/cpu.c | 609 +++ target-avr/cpu.h | 211 +++ target-avr/cpugen/CMakeLists.txt | 38 + target-avr/cpugen/README.md| 17 + target-avr/cpugen/cpu/avr.yaml | 214 +++ target-avr/cpugen/src/CMakeLists.txt | 62 + target-avr/cpugen/src/cpugen.cpp | 460 + target-avr/cpugen/src/utils.cpp| 27 + target-avr/cpugen/src/utils.h | 79 + target-avr/cpugen/xsl/decode.c.xsl | 103 ++ target-avr/cpugen/xsl/translate-inst.h.xsl | 118 ++ target-avr/cpugen/xsl/utils.xsl| 108 ++ target-avr/decode.c| 693 target-avr/gdbstub.c | 84 + target-avr/helper.c| 269 +++ target-avr/helper.h| 26 + target-avr/machine.c | 117 ++ target-avr/machine.h | 21 +
[Qemu-devel] [PATCH v7 06/12] target-avr: adding helpers for IN, OUT, SLEEP, WBR & unsupported instructions
Signed-off-by: Michael Rolnik --- target-avr/helper.c | 145 target-avr/helper.h | 5 ++ 2 files changed, 140 insertions(+), 10 deletions(-) diff --git a/target-avr/helper.c b/target-avr/helper.c index f96fa27..9e2b52a 100644 --- a/target-avr/helper.c +++ b/target-avr/helper.c @@ -42,14 +42,14 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) cs->exception_index = EXCP_RESET; cc->do_interrupt(cs); -cs->interrupt_request &= ~CPU_INTERRUPT_RESET; +cs->interrupt_request &= ~CPU_INTERRUPT_RESET; ret = true; } } if (interrupt_request & CPU_INTERRUPT_HARD) { if (cpu_interrupts_enabled(env) && env->intsrc != 0) { -int index = ctz32(env->intsrc); +int index = ctz32(env->intsrc); cs->exception_index = EXCP_INT(index); cc->do_interrupt(cs); @@ -64,8 +64,8 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) void avr_cpu_do_interrupt(CPUState *cs) { -AVRCPU *cpu = AVR_CPU(cs); -CPUAVRState*env = &cpu->env; +AVRCPU *cpu = AVR_CPU(cs); +CPUAVRState *env = &cpu->env; uint32_t ret = env->pc_w; int vector = 0; @@ -79,14 +79,14 @@ void avr_cpu_do_interrupt(CPUState *cs) } if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { -stb_phys(cs->as, env->sp--, (ret & 0xff)); -stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); -stb_phys(cs->as, env->sp--, (ret & 0xff) >> 16); +cpu_stb_data(env, env->sp--, (ret & 0xff)); +cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); +cpu_stb_data(env, env->sp--, (ret & 0xff) >> 16); } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { -stb_phys(cs->as, env->sp--, (ret & 0xff)); -stb_phys(cs->as, env->sp--, (ret & 0x00ff00) >> 8); +cpu_stb_data(env, env->sp--, (ret & 0xff)); +cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); } else { -stb_phys(cs->as, env->sp--, (ret & 0xff)); +cpu_stb_data(env, env->sp--, (ret & 0xff)); } env->pc_w = base + vector * size; @@ -133,6 +133,28 @@ void tlb_fill(CPUState *cs, target_ulong vaddr, int is_write, 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)); + +/* +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, qemu_logfile, fprintf, 0); +} +cpu_loop_exit(cs); +} void helper_debug(CPUAVRState *env) { @@ -142,3 +164,106 @@ void helper_debug(CPUAVRState *env) cpu_loop_exit(cs); } +void helper_wdr(CPUAVRState *env) +{ +CPUState *cs = CPU(avr_env_get_cpu(env)); + +/* +WD is not implemented yet, placeholder +*/ +cs->exception_index = EXCP_DEBUG; +cpu_loop_exit(cs); +} + +target_ulong helper_inb(CPUAVRState *env, uint32_t port) +{ +qemu_log("in: io[%02x]\n", port); + +switch (port) { +case0x38: { +return 0xff & (env->rampD >> 16); /* RAMPD */ +} +case0x39: { +return 0xff & (env->rampX >> 16); /* RAMPX */ +} +case0x3a: { +return 0xff & (env->rampY >> 16); /* RAMPY */ +} +case0x3b: { +return 0xff & (env->rampZ >> 16); /* RAMPZ */ +} +case0x3c: { +return 0xff & (env->eind >> 16); /* EIND*/ +} +case0x3d: { /* SPL */ +return env->sp & 0x00ff; +} +case0x3e: { /* SPH */ +return env->sp >> 8; +} +case0x3f: { /* SREG*/ +return cpu_get_sreg(env); +} +} +return 0; +} + +void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) +{ +qemu_log("out:%02x -> io[%02x]\n", data, port); + +data&= 0x00ff; + +switch (port) { +case0x04: { +qemu_irqirq; +CPUState *cpu = CPU(avr_env_get_cpu(env)); +irq = qdev_get_gpio_i
[Qemu-devel] [PATCH v7 02/12] target-avr: adding AVR CPU features/flavors
Signed-off-by: Michael Rolnik --- target-avr/cpu.c | 307 ++- target-avr/cpu.h | 53 ++ 2 files changed, 359 insertions(+), 1 deletion(-) diff --git a/target-avr/cpu.c b/target-avr/cpu.c index 99bd788..197f9ac 100644 --- a/target-avr/cpu.c +++ b/target-avr/cpu.c @@ -203,6 +203,296 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) dc->cannot_destroy_with_object_finalize_yet = 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,
[Qemu-devel] [PATCH v7 09/12] target-avr: updating translate.c to use instructions translation
Signed-off-by: Michael Rolnik --- target-avr/Makefile.objs | 4 +- target-avr/translate.c | 148 +-- 2 files changed, 69 insertions(+), 83 deletions(-) diff --git a/target-avr/Makefile.objs b/target-avr/Makefile.objs index 2a10104..9757721 100644 --- a/target-avr/Makefile.objs +++ b/target-avr/Makefile.objs @@ -18,6 +18,8 @@ # <http://www.gnu.org/licenses/lgpl-2.1.html> # -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 81ee44e..28babc9 100644 --- a/target-avr/translate.c +++ b/target-avr/translate.c @@ -18,60 +18,30 @@ * <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,25 +90,32 @@ 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; - -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); +CPUAVRState*env = &cpu->env; + +inst->opcode = cpu_ldl_code(env, inst->cpc * 2);/* pc points to words */ +/* target is defined as bigendian for push_ret/pop_ret +optimization. but my decode assumes instruction to be in little +endian format, hence bswap +*/ +inst->opcode = bswap32(inst->opcode); +inst->length = 16; +inst->translate = NULL; + +/* the following function looks onto the opcode as a string of bytes */ +avr_decode(inst->cpc, &inst->length, inst->opcode, &inst->translate); + +if (inst->length == 16) { +inst->npc = inst->cpc + 1; +/* get opcode as 16bit value */ +inst->opcode = inst->opcode & 0x; +} +if (inst->length == 32) { +inst->npc = inst->cpc + 2; +/* get opcode as 32bit value */ +inst->opcode = (inst->opcode << 16) + | (inst->opcode >> 16); } } @@ -172,18 +149,21 @@ void gen_intermediate_code(CPUAVRState *env, struct TranslationBlock *tb) 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