From: Michel Pollet Date: Wed, 23 Nov 2016 10:01:30 +0000 (+0000) Subject: jit: Add a AVR to host instruction translator X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=8c77029a89b7966d30cb78ad7bcb44010e6a42af;p=sx%2Fsimavr.git jit: Add a AVR to host instruction translator This adds a system that translates the whole AVR firmware into C, then compiles it using libtcc and runs it. This results in much much faster emulation, at the price of not being able to 'debug' using gdb (for the moment) Signed-off-by: Michel Pollet --- diff --git a/Makefile.common b/Makefile.common index 9b56e27..c176030 100644 --- a/Makefile.common +++ b/Makefile.common @@ -110,11 +110,20 @@ MKDIR ?= mkdir -p INSTALL ?= install SHELL := ${shell which bash} +LIBTCC := ${wildcard /usr/include/libtcc.*} +ifeq ($(LIBTCC),) +LIBTCC = 0 +else +LIBTCC = 1 +endif + OBJ := obj-${shell $(CC) -dumpmachine} LIBDIR := ${shell pwd}/${SIMAVR}/${OBJ} LDFLAGS += -L${LIBDIR} -lsimavr -lm - LDFLAGS += -lelf +ifeq ($(LIBTCC),1) +LDFLAGS += -ltcc -ldl +endif ifeq (${WIN}, Msys) LDFLAGS += -lws2_32 diff --git a/simavr/Makefile b/simavr/Makefile index f7eccca..6b94cd9 100644 --- a/simavr/Makefile +++ b/simavr/Makefile @@ -36,7 +36,14 @@ all: include ../Makefile.common cores := ${wildcard cores/*.c} -sim := ${wildcard sim/sim_*.c} ${wildcard sim/avr_*.c} +sim := ${wildcard sim/sim_*.c} ${wildcard sim/avr_*.c} + +# remove any JIT code +ifeq ($(LIBTCC),0) +jit := ${wildcard sim/*jit*.c} +sim := ${filter-out ${jit},${sim}} +endif + sim_o := ${patsubst sim/%.c, ${OBJ}/%.o, ${sim}} VPATH = cores @@ -161,6 +168,7 @@ sim_core_config.h ${OBJ}/cores.deps: $(cores) Makefile ( printf "// Autogenerated do not edit\n"; \ printf "#ifndef __SIM_CORE_CONFIG_H__\n#define __SIM_CORE_CONFIG_H__\n\n"; \ printf "#define CONFIG_SIMAVR_VERSION \"${SIMAVR_VERSION}\"\n"; \ + printf "#define CONFIG_SIMAVR_JIT ${LIBTCC}\n"; \ printf "$$conf\n"; \ printf "#endif\n"; \ ) >sim_core_config.h @@ -189,4 +197,7 @@ sim_core_decl.h: sim_core_config.h $(cores) Makefile printf "#endif\n"; \ ) >sim_core_decl.h +sim/sim_core_jit.h: sim/sim_core.c jit_emitter_generate.sh + ./jit_emitter_generate.sh + -include ${OBJ}/cores.deps diff --git a/simavr/jit_emitter_generate.sh b/simavr/jit_emitter_generate.sh new file mode 100755 index 0000000..46cc564 --- /dev/null +++ b/simavr/jit_emitter_generate.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +cat sim/sim_core.c | gawk ' +BEGIN { + spewing = 0; + print "/* THIS FILE IS AUTOGENERATED, DO NOT EDIT */"; + print "#ifndef __SIM_CORE_JIT_H__"; + print "#define __SIM_CORE_JIT_H__"; +} +END { + print "#endif /*__SIM_CORE_JIT_H__*/"; +} +function quote(line) { + gsub(/^[ \t]+/,"", line); + gsub(/\\/,"\\\\", line); + gsub(/["]/,"\\\"", line); + return line; +} +/JIT_EXTRACT_START/ { + spewing = 1; +} +/JIT_EXTRACT_END/ { + spewing = 0; +} +/[^_]emit[^a-z_]/ { + if (!match($0, "#define")) { + accum = ""; + spewing = 0; + sub(/emit/, ""); + print; next; + } +} +/emit_literal[^a-z_]/ { + if (!match($0, "#define")) { + gsub(/emit_literal/, "jit_generate_literal"); + print; + next; + } +} +/emit_literal_flush[^a-z_]/ { + if (!match($0, "#define")) { + gsub(/emit_literal_flush/, "jit_literal_flush"); + print; + next; + } +} +/avr->data/ { + gsub(/avr->data/, "avr_data"); +} +/avr->flash/ { + gsub(/avr->flash/, "avr_flash"); +} +/end_emit/ { + if (!match($0, "#define")) { + spewing = 1; + sub(/end_emit/, "break"); + print "jit_generate(opcode, " accum ");"; + } +} +{ + if (spewing) + print; + else { + $0 = quote($0); + accum = accum "\"" $0 "\\n\"" "\n"; + } +} +' >sim/sim_core_jit.h diff --git a/simavr/jit_wrapper.c b/simavr/jit_wrapper.c new file mode 100644 index 0000000..a226147 --- /dev/null +++ b/simavr/jit_wrapper.c @@ -0,0 +1,402 @@ + +/* + * Ignore this for now, this tests the minimal bits of C needed to compile the + * translated code. This file will eventually vanish + */ +#define NULL ((void*)0L) +#define T(w) w +//#define STATE(...) +#define STATE(_f, args...) printf("%04x: " _f, new_pc-2, ## args) +#define SREG() +#define STACK_FRAME_PUSH() +#define STACK_FRAME_POP() + +#define _avr_invalid_opcode(a) {} + +static const char * _sreg_bit_name = "cznvshti"; + +enum { + // SREG bit indexes + S_C = 0,S_Z,S_N,S_V,S_S,S_H,S_T,S_I, + + // 16 bits register pairs + R_XL = 0x1a, R_XH,R_YL,R_YH,R_ZL,R_ZH, + // stack pointer + R_SPL = 32+0x3d, R_SPH, + // real SREG + R_SREG = 32+0x3f, + + // maximum number of IO registers, on normal AVRs + MAX_IOs = 280, // Bigger AVRs need more than 256-32 (mega1280) +}; + + +#define SREG_BIT(_b) (avr_data[R_SREG] & (1 << (_b))) +#define SREG_SETBIT(_b, _v) avr_data[R_SREG] = (avr_data[R_SREG] & ~(1 << (_b))) | (!!(_v) << (_b)); + +/* + * Core states. + */ +enum { + cpu_Limbo = 0, // before initialization is finished + cpu_Stopped, // all is stopped, timers included + + cpu_Running, // we're free running + + cpu_Sleeping, // we're now sleeping until an interrupt + + cpu_Step, // run ONE instruction, then... + cpu_StepDone, // tell gdb it's all OK, and give it registers + cpu_Done, // avr software stopped gracefully + cpu_Crashed, // avr software crashed (watchdog fired) +}; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; +typedef short int16_t; +typedef char int8_t; + +typedef unsigned long avr_flashaddr_t; + +const char * avr_regname(uint8_t reg); +void _avr_set_r( + void * avr, + uint16_t r, + uint8_t v); +void +avr_core_watch_write( + void *avr, + uint16_t addr, + uint8_t v); +uint8_t +_avr_get_ram( + void * avr, + uint16_t addr); +int +avr_has_pending_interrupts( + void * avr); +void +avr_interrupt_reti( + void * avr); + +typedef struct jit_avr_t { + void * avr; + uint8_t * data; + uint8_t * flash; +} jit_avr_t, *jit_avr_p; + +static jit_avr_t * jit_avr = NULL; + +#define avr_data jit_avr->data +#define avr_flash jit_avr->flash +#define avr_state *state +#define avr jit_avr->avr + +static inline uint16_t +_avr_flash_read16le( + void * ignore, + avr_flashaddr_t addr) +{ + return (avr_flash[addr] | (avr_flash[addr + 1] << 8)); +} +static inline void +_avr_set_r16le( + void * ignore, + uint16_t r, + uint16_t v) +{ + _avr_set_r(avr, r, v); + _avr_set_r(avr, r + 1, v >> 8); +} + +static inline void +_avr_set_r16le_hl( + void * ignore, + uint16_t r, + uint16_t v) +{ + _avr_set_r(avr, r + 1, v >> 8); + _avr_set_r(avr, r , v); +} + + +inline uint16_t _avr_sp_get(void * ignore) +{ + return avr_data[R_SPL] | (avr_data[R_SPH] << 8); +} + +inline void _avr_sp_set(void * ignore, uint16_t sp) +{ + _avr_set_r16le(avr, R_SPL, sp); +} + +/* + * Set any address to a value; split between registers and SRAM + */ +static inline void _avr_set_ram(void * ignore, uint16_t addr, uint8_t v) +{ + if (addr < MAX_IOs + 31) + _avr_set_r(avr, addr, v); + else + avr_core_watch_write(avr, addr, v); +} + +#define avr_sreg_set(_ignore, flag, ival) \ + if (flag == S_I) { \ + if (ival) { \ + if (!SREG_BIT(S_I)) \ + *is = -2; \ + } else \ + *is = 0; \ + }\ + SREG_SETBIT(flag, ival); + +/* + * Stack push accessors. + */ +static inline void +_avr_push8( + void * ignore, + uint16_t v) +{ + uint16_t sp = _avr_sp_get(avr); + _avr_set_ram(avr, sp, v); + _avr_sp_set(avr, sp-1); +} + +static inline uint8_t +_avr_pop8( + void * ignore) +{ + uint16_t sp = _avr_sp_get(avr) + 1; + uint8_t res = _avr_get_ram(avr, sp); + _avr_sp_set(avr, sp); + return res; +} + +static avr_flashaddr_t +_avr_pop_addr( + void * ignore) +{ + uint16_t sp = _avr_sp_get(avr) + 1; + avr_flashaddr_t res = 0; + for (int i = 0; i < avr_address_size; i++, sp++) { + res = (res << 8) | _avr_get_ram(avr, sp); + } + res <<= 1; + _avr_sp_set(avr, sp -1); + return res; +} + +int +_avr_push_addr( + void * ignore, + avr_flashaddr_t addr) +{ + uint16_t sp = _avr_sp_get(avr); + addr >>= 1; + for (int i = 0; i < avr_address_size; i++, addr >>= 8, sp--) { + _avr_set_ram(avr, sp, addr); + } + _avr_sp_set(avr, sp); + return avr_address_size; +} + +/****************************************************************************\ + * + * Helper functions for calculating the status register bit values. + * See the Atmel data sheet for the instruction set for more info. + * +\****************************************************************************/ + +static void +_avr_flags_zns (void * ignore, uint8_t res) +{ + SREG_SETBIT(S_Z, res == 0); + SREG_SETBIT(S_N, (res >> 7) & 1); + SREG_SETBIT(S_S, SREG_BIT(S_N) ^ SREG_BIT(S_V)); +} + +static void +_avr_flags_zns16 (void * ignore, uint16_t res) +{ + SREG_SETBIT(S_Z, res == 0); + SREG_SETBIT(S_N, (res >> 15) & 1); + SREG_SETBIT(S_S, SREG_BIT(S_N) ^ SREG_BIT(S_V)); +} + +static void +_avr_flags_add_zns (void * ignore, uint8_t res, uint8_t rd, uint8_t rr) +{ + /* carry & half carry */ + uint8_t add_carry = (rd & rr) | (rr & ~res) | (~res & rd); + SREG_SETBIT(S_H, (add_carry >> 3) & 1); + SREG_SETBIT(S_C, (add_carry >> 7) & 1); + + /* overflow */ + SREG_SETBIT(S_V, (((rd & rr & ~res) | (~rd & ~rr & res)) >> 7) & 1); + + /* zns */ + _avr_flags_zns(avr, res); +} + + +static void +_avr_flags_sub_zns (void * ignore, uint8_t res, uint8_t rd, uint8_t rr) +{ + /* carry & half carry */ + uint8_t sub_carry = (~rd & rr) | (rr & res) | (res & ~rd); + SREG_SETBIT(S_H, (sub_carry >> 3) & 1); + SREG_SETBIT(S_C, (sub_carry >> 7) & 1); + + /* overflow */ + SREG_SETBIT(S_V, (((rd & ~rr & ~res) | (~rd & rr & res)) >> 7) & 1); + + /* zns */ + _avr_flags_zns(avr, res); +} + +static void +_avr_flags_Rzns (void * ignore, uint8_t res) +{ + if (res) + SREG_SETBIT(S_Z, 0); + SREG_SETBIT(S_N, (res >> 7) & 1); + SREG_SETBIT(S_S, SREG_BIT(S_N) ^ SREG_BIT(S_V)); +} + +static void +_avr_flags_sub_Rzns (void * ignore, uint8_t res, uint8_t rd, uint8_t rr) +{ + /* carry & half carry */ + uint8_t sub_carry = (~rd & rr) | (rr & res) | (res & ~rd); + SREG_SETBIT(S_H, (sub_carry >> 3) & 1); + SREG_SETBIT(S_C, (sub_carry >> 7) & 1); + /* overflow */ + SREG_SETBIT(S_V, (((rd & ~rr & ~res) | (~rd & rr & res)) >> 7) & 1); + _avr_flags_Rzns(avr, res); +} + +static void +_avr_flags_zcvs (void * ignore, uint8_t res, uint8_t vr) +{ + SREG_SETBIT(S_Z, res == 0); + SREG_SETBIT(S_C, vr & 1); + SREG_SETBIT(S_V, SREG_BIT(S_N) ^ SREG_BIT(S_C)); + SREG_SETBIT(S_S, SREG_BIT(S_N) ^ SREG_BIT(S_V)); +} + +static void +_avr_flags_zcnvs (void * ignore, uint8_t res, uint8_t vr) +{ + SREG_SETBIT(S_Z, res == 0); + SREG_SETBIT(S_C, vr & 1); + SREG_SETBIT(S_N, res >> 7); + SREG_SETBIT(S_V, SREG_BIT(S_N) ^ SREG_BIT(S_C)); + SREG_SETBIT(S_S, SREG_BIT(S_N) ^ SREG_BIT(S_V)); +} + +static void +_avr_flags_znv0s (void * ignore, uint8_t res) +{ + SREG_SETBIT(S_V, 0); + _avr_flags_zns(avr, res); +} + + +#define get_d5(o) \ + const uint8_t d = (o >> 4) & 0x1f + +#define get_vd5(o) \ + get_d5(o); \ + const uint8_t vd = avr_data[d] + +#define get_r5(o) \ + const uint8_t r = ((o >> 5) & 0x10) | (o & 0xf) + +#define get_d5_a6(o) \ + get_d5(o); \ + const uint8_t A = ((((o >> 9) & 3) << 4) | ((o) & 0xf)) + 32 + +#define get_vd5_s3(o) \ + get_vd5(o); \ + const uint8_t s = o & 7 + +#define get_vd5_s3_mask(o) \ + get_vd5_s3(o); \ + const uint8_t mask = 1 << s + +#define get_vd5_vr5(o) \ + get_r5(o); \ + get_d5(o); \ + const uint8_t vd = avr_data[d], vr = avr_data[r] + +#define get_d5_vr5(o) \ + get_d5(o); \ + get_r5(o); \ + const uint8_t vr = avr_data[r] + +#define get_h4_k8(o) \ + const uint8_t h = 16 + ((o >> 4) & 0xf); \ + const uint8_t k = ((o & 0x0f00) >> 4) | (o & 0xf) + +#define get_vh4_k8(o) \ + get_h4_k8(o); \ + const uint8_t vh = avr_data[h] + +#define get_d5_q6(o) \ + get_d5(o); \ + const uint8_t q = ((o & 0x2000) >> 8) | ((o & 0x0c00) >> 7) | (o & 0x7) + +#define get_io5(o) \ + const uint8_t io = ((o >> 3) & 0x1f) + 32 + +#define get_io5_b3(o) \ + get_io5(o); \ + const uint8_t b = o & 0x7 + +#define get_io5_b3mask(o) \ + get_io5(o); \ + const uint8_t mask = 1 << (o & 0x7) + +// const int16_t o = ((int16_t)(op << 4)) >> 3; // CLANG BUG! +#define get_o12(op) \ + const int16_t o = ((int16_t)((op << 4) & 0xffff)) >> 3 + +#define get_vp2_k6(o) \ + const uint8_t p = 24 + ((o >> 3) & 0x6); \ + const uint8_t k = ((o & 0x00c0) >> 2) | (o & 0xf); \ + const uint16_t vp = avr_data[p] | (avr_data[p + 1] << 8) + +#define get_sreg_bit(o) \ + const uint8_t b = (o >> 4) & 7 + +#define TRACE_JUMP() { \ + if (*is || cycle >= howLong) goto exit;\ + goto *jt[new_pc/2]; \ + } +#define CORE_SLEEP() goto exit + +avr_flashaddr_t +firmware( + jit_avr_t * _jit_avr, + avr_flashaddr_t pc, + int * state, + int8_t * is, + int * cycles, + int howLong ) +{ + uint16_t new_pc = pc; + int cycle = 0; + + jit_avr = _jit_avr; + +// printf("Hi There %p %p\n", avr_flash, avr_data); + +#include "jit_code.c" + +exit: + *cycles += cycle; + return new_pc; +} diff --git a/simavr/sim/run_avr.c b/simavr/sim/run_avr.c index c39d474..5c2214a 100644 --- a/simavr/sim/run_avr.c +++ b/simavr/sim/run_avr.c @@ -30,35 +30,33 @@ #include "sim_gdb.h" #include "sim_hex.h" #include "sim_vcd_file.h" - #include "sim_core_decl.h" +#if CONFIG_SIMAVR_JIT +#include "avr_flash.h" // for AVR_IOCTL_FLASH_SPM +#include "avr_watchdog.h" // for AVR_IOCTL_WATCHDOG_RESET +#include +#endif + static void display_usage( const char * app) { - printf("Usage: %s [...] \n", app); - printf( " [--freq|-f ] Sets the frequency for an .hex firmware\n" - " [--mcu|-m ] Sets the MCU type for an .hex firmware\n" - " [--list-cores] List all supported AVR cores and exit\n" - " [--help|-h] Display this usage message and exit\n" - " [--trace, -t] Run full scale decoder trace\n" - " [-ti ] Add traces for IRQ vector \n" - " [--gdb|-g] Listen for gdb connection on port 1234\n" - " [-ff <.hex file>] Load next .hex file as flash\n" - " [-ee <.hex file>] Load next .hex file as eeprom\n" - " [--input|-i ] A .vcd file to use as input signals\n" - " [-v] Raise verbosity level\n" - " (can be passed more than once)\n" - " A .hex or an ELF file. ELF files are\n" - " prefered, and can include debugging syms\n"); + printf("Usage: %s [--list-cores] [--help] [-t] [-g] [-v] [-m ] [-f ] firmware\n", app); + printf( " --list-cores List all supported AVR cores and exit\n" + " --help, -h Display this usage message and exit\n" + " -trace, -t Run full scale decoder trace\n" + " -ti Add trace vector at \n" + " -gdb, -g Listen for gdb connection on port 1234\n" + " -ff Load next .hex file as flash\n" + " -ee Load next .hex file as eeprom\n" + " -v Raise verbosity level (can be passed more than once)\n"); exit(1); } -static void -list_cores() -{ - printf( "Supported AVR cores:\n"); +void list_cores() { + printf( + " Supported AVR cores:\n"); for (int i = 0; avr_kind[i]; i++) { printf(" "); for (int ti = 0; ti < 4 && avr_kind[i]->names[ti]; ti++) @@ -80,6 +78,14 @@ sig_int( exit(0); } +typedef struct jit_avr_t { + void * avr; + uint8_t * data; + uint8_t * flash; +} jit_avr_t, *jit_avr_p; + +jit_avr_t g_avr; + int main( int argc, @@ -95,6 +101,7 @@ main( int trace_vectors[8] = {0}; int trace_vectors_count = 0; const char *vcd_input = NULL; + int translate = 0; if (argc == 1) display_usage(basename(argv[0])); @@ -104,6 +111,11 @@ main( list_cores(); } else if (!strcmp(argv[pi], "-h") || !strcmp(argv[pi], "--help")) { display_usage(basename(argv[0])); + } else if (!strcmp(argv[pi], "-j") || !strcmp(argv[pi], "--jit")) { + translate++; +#if CONFIG_SIMAVR_JIT == 0 + fprintf(stderr, "%s: - JIT was not compiled in this version.\n", argv[0]); +#endif } else if (!strcmp(argv[pi], "-m") || !strcmp(argv[pi], "--mcu")) { if (pi < argc-1) strncpy(name, argv[++pi], sizeof(name)); @@ -169,6 +181,9 @@ main( exit(1); } } + } else { + fprintf(stderr, "%s invalid option '%s'\n", argv[0], argv[pi]); + exit(1); } } @@ -211,7 +226,63 @@ main( signal(SIGINT, sig_int); signal(SIGTERM, sig_int); +#if CONFIG_SIMAVR_JIT + if (translate) { + avr_flashaddr_t avr_translate_firmware(avr_t * avr); + avr_translate_firmware(avr); + + static const jit_avr_t z_avr = {0}; + g_avr = z_avr; + g_avr.avr = avr; + g_avr.data = avr->data; + g_avr.flash = avr->flash; + TCCState * tcc = tcc_new(); + + void error(void *i, const char *msg) { + fprintf(stderr, "TCC: %s\n", msg); + } + tcc_set_error_func(tcc, NULL, error); + + char sym[32]; + sprintf(sym, "%d", avr->address_size); + tcc_define_symbol(tcc, "avr_address_size", sym); + sprintf(sym, "0x%x", avr->flashend); + tcc_define_symbol(tcc, "avr_flashend", sym); + sprintf(sym, "0x%x", avr->eind); + tcc_define_symbol(tcc, "avr_eind", sym); + sprintf(sym, "0x%x", avr->rampz); + tcc_define_symbol(tcc, "avr_rampz", sym); + sprintf(sym, "%08x", AVR_IOCTL_WATCHDOG_RESET); + tcc_define_symbol(tcc, "AVR_IOCTL_WATCHDOG_RESET", sym); + sprintf(sym, "%08x", AVR_IOCTL_FLASH_SPM); + tcc_define_symbol(tcc, "AVR_IOCTL_FLASH_SPM", sym); + + tcc_set_output_type(tcc, TCC_OUTPUT_MEMORY); +#ifdef TCC_FILETYPE_C + tcc_add_file(tcc, "jit_wrapper.c", TCC_FILETYPE_C); +#else + tcc_add_file(tcc, "jit_wrapper.c"); +#endif +// tcc_enable_debug(tcc); // API is gone? + void *firmware = NULL; +#ifdef TCC_RELOCATE_AUTO + if (tcc_relocate(tcc, TCC_RELOCATE_AUTO) == 0) +#else + if (tcc_relocate(tcc) == 0) +#endif + firmware = tcc_get_symbol(tcc, "firmware"); + + if (firmware) { + avr->jit.context = tcc; + avr->jit.jit_avr = &g_avr; + avr->jit.entry = firmware; + avr->run = avr_callback_run_jit; + } else { + exit(0); + } + } +#endif for (;;) { int state = avr_run(avr); if (state == cpu_Done || state == cpu_Crashed) diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index ee9e6ad..b2b9e0c 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -207,6 +207,19 @@ typedef struct avr_t { void (*init)(struct avr_t * avr); // called at reset time void (*reset)(struct avr_t * avr); + /*! + * Sleep default behaviour. + * In "raw" mode, it calls usleep, in gdb mode, it waits + * for howLong for gdb command on it's sockets. + */ + void (*sleep)(struct avr_t * avr, avr_cycle_count_t howLong); + /*! + * Default AVR core run function. + * Two modes are available, a "raw" run that goes as fast as + * it can, and a "gdb" mode that also watchouts for gdb events + * and is a little bit slower. + */ + avr_run_t run; struct { // called at init time (for special purposes like using a @@ -218,20 +231,24 @@ typedef struct avr_t { void *data; } custom; - /*! - * Default AVR core run function. - * Two modes are available, a "raw" run that goes as fast as - * it can, and a "gdb" mode that also watchouts for gdb events - * and is a little bit slower. - */ - avr_run_t run; - - /*! - * Sleep default behaviour. - * In "raw" mode, it calls usleep, in gdb mode, it waits - * for howLong for gdb command on it's sockets. + /* JIT/translator specific. This is the entry point of the native + * context that has been compiled from the AVR firmware, it is called + * repeteadly and is supposed to run for howLong cyles, or until + * the core changes state. + * Note the jit_avr is NOT a full avr_t, it's a much reduced one with + * just the bits required by the core, proper */ - void (*sleep)(struct avr_t * avr, avr_cycle_count_t howLong); + struct { + void * context; /* libtcc context */ + void * jit_avr; + avr_flashaddr_t (*entry)( + void * jit_avr, + avr_flashaddr_t pc, + int * state, + int8_t * interrupt_state, + int * cycles, + int howLong ); + } jit; /*! * Every IRQs will be stored in this pool. It is not @@ -442,7 +459,11 @@ avr_global_logger( /* * Type for custom logging functions */ -typedef void (*avr_logger_p)(struct avr_t* avr, const int level, const char * format, va_list ap); +typedef void (*avr_logger_p)( + struct avr_t* avr, + const int level, + const char * format, + va_list ap); /* Sets a global logging function in place of the default */ void @@ -460,6 +481,8 @@ void avr_callback_sleep_gdb(avr_t * avr, avr_cycle_count_t howLong); void avr_callback_run_gdb(avr_t * avr); void avr_callback_sleep_raw(avr_t * avr, avr_cycle_count_t howLong); void avr_callback_run_raw(avr_t * avr); +// and this one is for the translator/jit runtime +void avr_callback_run_jit(avr_t * avr); /** * Accumulates sleep requests (and returns a sleep time of 0) until diff --git a/simavr/sim/sim_core.c b/simavr/sim/sim_core.c index b96f74c..6dadac0 100644 --- a/simavr/sim/sim_core.c +++ b/simavr/sim/sim_core.c @@ -40,7 +40,13 @@ static const char * _sreg_bit_name = "cznvshti"; */ #if CONFIG_SIMAVR_TRACE +static const char * brxc_names[2][8] = { + { "brcc", "brne", "brpl", "brvc", NULL, "brhc", "brtc", "brid"}, + { "brcs", "breq", "brmi", "brvs", NULL, "brhs", "brts", "brie"}, +}; + #define T(w) w +#define CORE_SLEEP() #define REG_TOUCH(a, r) (a)->trace_data->touched[(r) >> 5] |= (1 << ((r) & 0x1f)) #define REG_ISTOUCHED(a, r) ((a)->trace_data->touched[(r) >> 5] & (1 << ((r) & 0x1f))) @@ -85,7 +91,7 @@ int donttrace = 0; printf("\n");\ } -void crash(avr_t* avr) +static void crash(avr_t* avr) { DUMP_REG(); printf("*** CYCLE %" PRI_avr_cycle_count "PC %04x\n", avr->cycle, avr->pc); @@ -106,8 +112,9 @@ void crash(avr_t* avr) #define REG_TOUCH(a, r) #define STATE(_f, args...) #define SREG() +#define CORE_SLEEP() -void crash(avr_t* avr) +static void crash(avr_t* avr) { avr_sadly_crashed(avr, 0); @@ -122,7 +129,11 @@ _avr_flash_read16le( return(avr->flash[addr] | (avr->flash[addr + 1] << 8)); } -void avr_core_watch_write(avr_t *avr, uint16_t addr, uint8_t v) +void +avr_core_watch_write( + avr_t *avr, + uint16_t addr, + uint8_t v) { if (addr > avr->ramend) { AVR_LOG(avr, LOG_ERROR, FONT_RED @@ -182,7 +193,10 @@ uint8_t avr_core_watch_read(avr_t *avr, uint16_t addr) * if it's an IO register (> 31) also (try to) call any callback that was * registered to track changes to that register. */ -static inline uint8_t _avr_set_r(avr_t * avr, uint8_t _sreg, uint16_t r, uint8_t v) +void _avr_set_r( + avr_t * avr, + uint16_t r, + uint8_t v) { REG_TOUCH(avr, r); @@ -253,7 +267,10 @@ static inline uint8_t _avr_set_ram(avr_t * avr, uint8_t _sreg, uint16_t addr, ui /* * Get a value from SRAM. */ -static inline uint8_t _avr_get_ram(avr_t * avr, uint16_t addr) +uint8_t +_avr_get_ram( + avr_t * avr, + uint16_t addr) { if (addr > 31 && addr < 31 + MAX_IOs) { avr_io_addr_t io = AVR_DATA_TO_IO(addr); @@ -289,18 +306,7 @@ static inline uint8_t _avr_pop8(avr_t * avr) return res; } -int _avr_push_addr(avr_t * avr, avr_flashaddr_t addr) -{ - uint16_t sp = _avr_sp_get(avr); - addr >>= 1; - for (int i = 0; i < avr->address_size; i++, addr >>= 8, sp--) { - _avr_set_ram(avr, 0, sp, addr); - } - _avr_sp_set(avr, sp); - return avr->address_size; -} - -avr_flashaddr_t _avr_pop_addr(avr_t * avr) +static avr_flashaddr_t _avr_pop_addr(avr_t * avr) { uint16_t sp = _avr_sp_get(avr) + 1; avr_flashaddr_t res = 0; @@ -312,6 +318,17 @@ avr_flashaddr_t _avr_pop_addr(avr_t * avr) return res; } +int _avr_push_addr(avr_t * avr, avr_flashaddr_t addr) +{ + uint16_t sp = _avr_sp_get(avr); + addr >>= 1; + for (int i = 0; i < avr->address_size; i++, addr >>= 8, sp--) { + _avr_set_ram(avr, 0, sp, addr); + } + _avr_sp_set(avr, sp); + return avr->address_size; +} + /* * "Pretty" register names */ @@ -384,71 +401,71 @@ void avr_dump_state(avr_t * avr) #endif #define get_d5(o) \ - const uint8_t d = (o >> 4) & 0x1f; + const uint8_t d = (o >> 4) & 0x1f #define get_vd5(o) \ - get_d5(o) \ - const uint8_t vd = avr->data[d]; + get_d5(o); \ + const uint8_t vd = avr->data[d] #define get_r5(o) \ - const uint8_t r = ((o >> 5) & 0x10) | (o & 0xf); + const uint8_t r = ((o >> 5) & 0x10) | (o & 0xf) #define get_d5_a6(o) \ get_d5(o); \ - const uint8_t A = ((((o >> 9) & 3) << 4) | ((o) & 0xf)) + 32; + const uint8_t A = ((((o >> 9) & 3) << 4) | ((o) & 0xf)) + 32 #define get_vd5_s3(o) \ get_vd5(o); \ - const uint8_t s = o & 7; + const uint8_t s = o & 7 #define get_vd5_s3_mask(o) \ get_vd5_s3(o); \ - const uint8_t mask = 1 << s; + const uint8_t mask = 1 << s #define get_vd5_vr5(o) \ get_r5(o); \ get_d5(o); \ - const uint8_t vd = avr->data[d], vr = avr->data[r]; + const uint8_t vd = avr->data[d], vr = avr->data[r] #define get_d5_vr5(o) \ get_d5(o); \ get_r5(o); \ - const uint8_t vr = avr->data[r]; + const uint8_t vr = avr->data[r] #define get_h4_k8(o) \ const uint8_t h = 16 + ((o >> 4) & 0xf); \ - const uint8_t k = ((o & 0x0f00) >> 4) | (o & 0xf); + const uint8_t k = ((o & 0x0f00) >> 4) | (o & 0xf) #define get_vh4_k8(o) \ - get_h4_k8(o) \ - const uint8_t vh = avr->data[h]; + get_h4_k8(o); \ + const uint8_t vh = avr->data[h] #define get_d5_q6(o) \ - get_d5(o) \ - const uint8_t q = ((o & 0x2000) >> 8) | ((o & 0x0c00) >> 7) | (o & 0x7); + get_d5(o); \ + const uint8_t q = ((o & 0x2000) >> 8) | ((o & 0x0c00) >> 7) | (o & 0x7) #define get_io5(o) \ - const uint8_t io = ((o >> 3) & 0x1f) + 32; + const uint8_t io = ((o >> 3) & 0x1f) + 32 #define get_io5_b3(o) \ get_io5(o); \ - const uint8_t b = o & 0x7; + const uint8_t b = o & 0x7 #define get_io5_b3mask(o) \ get_io5(o); \ - const uint8_t mask = 1 << (o & 0x7); + const uint8_t mask = 1 << (o & 0x7) // const int16_t o = ((int16_t)(op << 4)) >> 3; // CLANG BUG! #define get_o12(op) \ - const int16_t o = ((int16_t)((op << 4) & 0xffff)) >> 3; + const int16_t o = ((int16_t)((op << 4) & 0xffff)) >> 3 #define get_vp2_k6(o) \ const uint8_t p = 24 + ((o >> 3) & 0x6); \ const uint8_t k = ((o & 0x00c0) >> 2) | (o & 0xf); \ - const uint16_t vp = avr->data[p] | (avr->data[p + 1] << 8); + const uint16_t vp = avr->data[p] | (avr->data[p + 1] << 8) #define get_sreg_bit(o) \ - const uint8_t b = (o >> 4) & 7; + const uint8_t b = (o >> 4) & 7 /* * Add a "jump" address to the jump trace buffer @@ -599,6 +616,11 @@ static inline int _avr_is_instruction_32_bits(avr_t * avr, avr_flashaddr_t pc) o == 0x940f; // CALL Long Call to sub } +#define emit +#define end_emit break +#define emit_literal(...) +#define emit_literal_flush() + /* * Main opcode decoder * @@ -645,6 +667,16 @@ run_one_again: avr_flashaddr_t new_pc = avr->pc + 2; // future "default" pc int cycle = 1; +#define avr_state avr->state +#define avr_address_size avr->address_size +#define avr_flashend avr->flashend +#define avr_eind avr->eind +#define avr_rampz avr->rampz + + // JIT_EXTRACT_START <-- don't change this line, + // it's there to help the script extract the opcode state machine + emit_literal_flush(); + switch (opcode & 0xf000) { case 0x0000: { switch (opcode) { @@ -659,8 +691,8 @@ run_one_again: STATE("cpc %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); _sreg = _avr_flags_sub_Rzns(_sreg, res, vd, vr); SREG(); - } break; - case 0x0c00: { // ADD -- Add without carry -- 0000 11rd dddd rrrr + } end_emit; + case 0x0c00: emit { // ADD -- Add without carry -- 0000 11rd dddd rrrr get_vd5_vr5(opcode); uint8_t res = vd + vr; if (r == d) { @@ -671,36 +703,36 @@ run_one_again: _sreg = _avr_set_r(avr, _sreg, d, res); _sreg = _avr_flags_add_zns(_sreg, res, vd, vr); SREG(); - } break; - case 0x0800: { // SBC -- Subtract with carry -- 0000 10rd dddd rrrr + } end_emit; + case 0x0800: emit { // SBC -- Subtract with carry -- 0000 10rd dddd rrrr get_vd5_vr5(opcode); uint8_t res = vd - vr - SREG_BIT(S_C); STATE("sbc %s[%02x], %s[%02x] = %02x\n", avr_regname(d), avr->data[d], avr_regname(r), avr->data[r], res); _sreg = _avr_set_r(avr, _sreg, d, res); _sreg = _avr_flags_sub_Rzns(_sreg, res, vd, vr); SREG(); - } break; + } end_emit; default: switch (opcode & 0xff00) { - case 0x0100: { // MOVW -- Copy Register Word -- 0000 0001 dddd rrrr + case 0x0100: emit { // MOVW -- Copy Register Word -- 0000 0001 dddd rrrr uint8_t d = ((opcode >> 4) & 0xf) << 1; uint8_t r = ((opcode) & 0xf) << 1; STATE("movw %s:%s, %s:%s[%02x%02x]\n", avr_regname(d), avr_regname(d+1), avr_regname(r), avr_regname(r+1), avr->data[r+1], avr->data[r]); uint16_t vr = avr->data[r] | (avr->data[r + 1] << 8); - _avr_set_r16le(d, vr); - } break; - case 0x0200: { // MULS -- Multiply Signed -- 0000 0010 dddd rrrr + _avr_set_r16le(avr, d, vr); + } end_emit; + case 0x0200: emit { // MULS -- Multiply Signed -- 0000 0010 dddd rrrr int8_t r = 16 + (opcode & 0xf); int8_t d = 16 + ((opcode >> 4) & 0xf); int16_t res = ((int8_t)avr->data[r]) * ((int8_t)avr->data[d]); STATE("muls %s[%d], %s[%02x] = %d\n", avr_regname(d), ((int8_t)avr->data[d]), avr_regname(r), ((int8_t)avr->data[r]), res); - _avr_set_r16le(0, res); + _avr_set_r16le(avr, 0, res); SREG_SETBIT(S_C, (res >> 15) & 1); SREG_SETBIT(S_Z, res == 0); cycle++; SREG(); - } break; - case 0x0300: { // MUL -- Multiply -- 0000 0011 fddd frrr + } end_emit; + case 0x0300: emit { // MUL -- Multiply -- 0000 0011 fddd frrr int8_t r = 16 + (opcode & 0x7); int8_t d = 16 + ((opcode >> 4) & 0x7); int16_t res = 0; @@ -737,7 +769,7 @@ run_one_again: SREG_SETBIT(S_C, c); SREG_SETBIT(S_Z, res == 0); SREG(); - } break; + } end_emit; default: _avr_invalid_opcode(avr); } } @@ -747,34 +779,39 @@ run_one_again: case 0x1000: { switch (opcode & 0xfc00) { - case 0x1800: { // SUB -- Subtract without carry -- 0001 10rd dddd rrrr + case 0x1800: emit { // SUB -- Subtract without carry -- 0001 10rd dddd rrrr get_vd5_vr5(opcode); uint8_t res = vd - vr; STATE("sub %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); _sreg = _avr_set_r(avr, _sreg, d, res); _sreg = _avr_flags_sub_zns(_sreg, res, vd, vr); SREG(); - } break; - case 0x1000: { // CPSE -- Compare, skip if equal -- 0001 00rd dddd rrrr - get_vd5_vr5(opcode); - uint16_t res = vd == vr; - STATE("cpse %s[%02x], %s[%02x]\t; Will%s skip\n", avr_regname(d), avr->data[d], avr_regname(r), avr->data[r], res ? "":" not"); - if (res) { - if (_avr_is_instruction_32_bits(avr, new_pc)) { - new_pc += 4; cycle += 2; - } else { - new_pc += 2; cycle++; + } end_emit; + case 0x1000: { // CPSE -- Compare, skip if equal -- 0001 00rd dddd rrrr + /* This code is deduped like this to allow emmiting a 'constant' + * piece of code, without having to read the next instruction in case + * of JIT. In normal mode, we lose a few cycles but at least the code is + * clear */ + const int skip = 1 + _avr_is_instruction_32_bits(avr, new_pc); + emit { + emit_literal("const int skip = %d", skip); + get_vd5_vr5(opcode); + uint16_t res = vd == vr; + STATE("cpse %s[%02x], %s[%02x]\t; Will%s skip\n", avr_regname(d), avr->data[d], avr_regname(r), avr->data[r], res ? "":" not"); + if (res) { + new_pc += 2 * skip; cycle += skip; + TRACE_JUMP(); } - } + } end_emit; } break; - case 0x1400: { // CP -- Compare -- 0001 01rd dddd rrrr + case 0x1400: emit { // CP -- Compare -- 0001 01rd dddd rrrr get_vd5_vr5(opcode); uint8_t res = vd - vr; STATE("cp %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); _sreg = _avr_flags_sub_zns(_sreg, res, vd, vr); SREG(); - } break; - case 0x1c00: { // ADD -- Add with carry -- 0001 11rd dddd rrrr + } end_emit; + case 0x1c00: emit { // ADD -- Add with carry -- 0001 11rd dddd rrrr get_vd5_vr5(opcode); uint8_t res = vd + vr + SREG_BIT(S_C); if (r == d) { @@ -785,14 +822,14 @@ run_one_again: _sreg = _avr_set_r(avr, _sreg, d, res); _sreg = _avr_flags_add_zns(_sreg, res, vd, vr); SREG(); - } break; + } end_emit; default: _avr_invalid_opcode(avr); } } break; case 0x2000: { switch (opcode & 0xfc00) { - case 0x2000: { // AND -- Logical AND -- 0010 00rd dddd rrrr + case 0x2000: emit { // AND -- Logical AND -- 0010 00rd dddd rrrr get_vd5_vr5(opcode); uint8_t res = vd & vr; if (r == d) { @@ -803,8 +840,8 @@ run_one_again: _sreg = _avr_set_r(avr, _sreg, d, res); _sreg = _avr_flags_znv0s(_sreg, res); SREG(); - } break; - case 0x2400: { // EOR -- Logical Exclusive OR -- 0010 01rd dddd rrrr + } end_emit; + case 0x2400: emit { // EOR -- Logical Exclusive OR -- 0010 01rd dddd rrrr get_vd5_vr5(opcode); uint8_t res = vd ^ vr; if (r==d) { @@ -815,68 +852,68 @@ run_one_again: _sreg = _avr_set_r(avr, _sreg, d, res); _sreg = _avr_flags_znv0s(_sreg, res); SREG(); - } break; - case 0x2800: { // OR -- Logical OR -- 0010 10rd dddd rrrr + } end_emit; + case 0x2800: emit { // OR -- Logical OR -- 0010 10rd dddd rrrr get_vd5_vr5(opcode); uint8_t res = vd | vr; STATE("or %s[%02x], %s[%02x] = %02x\n", avr_regname(d), vd, avr_regname(r), vr, res); _sreg = _avr_set_r(avr, _sreg, d, res); _sreg = _avr_flags_znv0s(_sreg, res); SREG(); - } break; - case 0x2c00: { // MOV -- 0010 11rd dddd rrrr + } end_emit; + case 0x2c00: emit { // MOV -- 0010 11rd dddd rrrr get_d5_vr5(opcode); uint8_t res = vr; STATE("mov %s, %s[%02x] = %02x\n", avr_regname(d), avr_regname(r), vr, res); _sreg = _avr_set_r(avr, _sreg, d, res); - } break; + } end_emit; default: _avr_invalid_opcode(avr); } } break; - case 0x3000: { // CPI -- Compare Immediate -- 0011 kkkk hhhh kkkk + case 0x3000: emit { // CPI -- Compare Immediate -- 0011 kkkk hhhh kkkk get_vh4_k8(opcode); uint8_t res = vh - k; STATE("cpi %s[%02x], 0x%02x\n", avr_regname(h), vh, k); _sreg = _avr_flags_sub_zns(_sreg, res, vh, k); SREG(); - } break; + } end_emit; - case 0x4000: { // SBCI -- Subtract Immediate With Carry -- 0100 kkkk hhhh kkkk + case 0x4000: emit { // SBCI -- Subtract Immediate With Carry -- 0100 kkkk hhhh kkkk get_vh4_k8(opcode); uint8_t res = vh - k - SREG_BIT(S_C); STATE("sbci %s[%02x], 0x%02x = %02x\n", avr_regname(h), vh, k, res); _sreg = _avr_set_r(avr, _sreg, h, res); _sreg = _avr_flags_sub_Rzns(_sreg, res, vh, k); SREG(); - } break; + } end_emit; - case 0x5000: { // SUBI -- Subtract Immediate -- 0101 kkkk hhhh kkkk + case 0x5000: emit { // SUBI -- Subtract Immediate -- 0101 kkkk hhhh kkkk get_vh4_k8(opcode); uint8_t res = vh - k; STATE("subi %s[%02x], 0x%02x = %02x\n", avr_regname(h), vh, k, res); _sreg = _avr_set_r(avr, _sreg, h, res); _sreg = _avr_flags_sub_zns(_sreg, res, vh, k); SREG(); - } break; + } end_emit; - case 0x6000: { // ORI aka SBR -- Logical OR with Immediate -- 0110 kkkk hhhh kkkk + case 0x6000: emit { // ORI aka SBR -- Logical OR with Immediate -- 0110 kkkk hhhh kkkk get_vh4_k8(opcode); uint8_t res = vh | k; STATE("ori %s[%02x], 0x%02x\n", avr_regname(h), vh, k); _sreg = _avr_set_r(avr, _sreg, h, res); _sreg = _avr_flags_znv0s(_sreg, res); SREG(); - } break; + } end_emit; - case 0x7000: { // ANDI -- Logical AND with Immediate -- 0111 kkkk hhhh kkkk + case 0x7000: emit { // ANDI -- Logical AND with Immediate -- 0111 kkkk hhhh kkkk get_vh4_k8(opcode); uint8_t res = vh & k; STATE("andi %s[%02x], 0x%02x\n", avr_regname(h), vh, k); _sreg = _avr_set_r(avr, _sreg, h, res); _sreg = _avr_flags_znv0s(_sreg, res); SREG(); - } break; + } end_emit; case 0xa000: case 0x8000: { @@ -890,7 +927,7 @@ run_one_again: */ switch (opcode & 0xd008) { case 0xa000: - case 0x8000: { // LD (LDD) -- Load Indirect using Z -- 10q0 qqsd dddd yqqq + case 0x8000: emit { // LD (LDD) -- Load Indirect using Z -- 10q0 qqsd dddd yqqq uint16_t v = avr->data[R_ZL] | (avr->data[R_ZH] << 8); get_d5_q6(opcode); if (opcode & 0x0200) { @@ -901,9 +938,9 @@ run_one_again: _sreg = _avr_set_r(avr, _sreg, d, _avr_get_ram(avr, v+q)); } cycle += 1; // 2 cycles, 3 for tinyavr - } break; + } end_emit; case 0xa008: - case 0x8008: { // LD (LDD) -- Load Indirect using Y -- 10q0 qqsd dddd yqqq + case 0x8008: emit { // LD (LDD) -- Load Indirect using Y -- 10q0 qqsd dddd yqqq uint16_t v = avr->data[R_YL] | (avr->data[R_YH] << 8); get_d5_q6(opcode); if (opcode & 0x0200) { @@ -914,7 +951,7 @@ run_one_again: _sreg = _avr_set_r(avr, _sreg, d, _avr_get_ram(avr, v+q)); } cycle += 1; // 2 cycles, 3 for tinyavr - } break; + } end_emit; default: _avr_invalid_opcode(avr); } } break; @@ -922,122 +959,132 @@ run_one_again: case 0x9000: { /* this is an annoying special case, but at least these lines handle all the SREG set/clear opcodes */ if ((opcode & 0xff0f) == 0x9408) { - get_sreg_bit(opcode); - STATE("%s%c\n", opcode & 0x0080 ? "cl" : "se", _sreg_bit_name[b]); - SREG_SETBIT(b, (opcode & 0x0080) == 0); - SREG(); + emit { + get_sreg_bit(opcode); + STATE("%s%c\n", opcode & 0x0080 ? "cl" : "se", _sreg_bit_name[b]); + SREG_SETBIT(b, (opcode & 0x0080) == 0); + SREG(); + } end_emit; } else switch (opcode) { - case 0x9588: { // SLEEP -- 1001 0101 1000 1000 + case 0x9588: emit { // SLEEP -- 1001 0101 1000 1000 STATE("sleep\n"); /* Don't sleep if there are interrupts about to be serviced. * Without this check, it was possible to incorrectly enter a state * in which the cpu was sleeping and interrupts were disabled. For more * details, see the commit message. */ - if (!avr_has_pending_interrupts(avr) || !SREG_BIT(S_I)) - avr->state = cpu_Sleeping; - } break; - case 0x9598: { // BREAK -- 1001 0101 1001 1000 + if (!avr_has_pending_interrupts(avr) || !SREG_BIT(S_I)) { + avr_state = cpu_Sleeping; + SREG_FLUSH(CORE_SLEEP();); + } + } end_emit; + case 0x9598: emit { // BREAK -- 1001 0101 1001 1000 STATE("break\n"); if (avr->gdb) { // if gdb is on, we break here as in here // and we do so until gdb restores the instruction // that was here before - avr->state = cpu_StepDone; + avr_state = cpu_StepDone; new_pc = avr->pc; cycle = 0; } - } break; - case 0x95a8: { // WDR -- Watchdog Reset -- 1001 0101 1010 1000 + } end_emit; + case 0x95a8: emit { // WDR -- Watchdog Reset -- 1001 0101 1010 1000 STATE("wdr\n"); SREG_FLUSH(avr_ioctl(avr, AVR_IOCTL_WATCHDOG_RESET, 0)); - } break; - case 0x95e8: { // SPM -- Store Program Memory -- 1001 0101 1110 1000 + } end_emit; + case 0x95e8: emit { // SPM -- Store Program Memory -- 1001 0101 1110 1000 STATE("spm\n"); SREG_FLUSH(avr_ioctl(avr, AVR_IOCTL_FLASH_SPM, 0)); - } break; + } end_emit; case 0x9409: // IJMP -- Indirect jump -- 1001 0100 0000 1001 case 0x9419: // EIJMP -- Indirect jump -- 1001 0100 0001 1001 bit 4 is "indirect" case 0x9509: // ICALL -- Indirect Call to Subroutine -- 1001 0101 0000 1001 case 0x9519: { // EICALL -- Indirect Call to Subroutine -- 1001 0101 0001 1001 bit 8 is "push pc" int e = opcode & 0x10; int p = opcode & 0x100; - if (e && !avr->eind) + if (e && !avr_eind) _avr_invalid_opcode(avr); - uint32_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8); - if (e) - z |= avr->data[avr->eind] << 16; - STATE("%si%s Z[%04x]\n", e?"e":"", p?"call":"jmp", z << 1); - if (p) - cycle += _avr_push_addr(avr, new_pc) - 1; - new_pc = z << 1; - cycle++; - TRACE_JUMP(); + emit { + emit_literal("const int e = %d", e); + emit_literal("const int p = %d", p); + uint32_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8); + if (e) + z |= avr->data[avr_eind] << 16; + STATE("%si%s Z[%04x]\n", e?"e":"", p?"call":"jmp", z << 1); + if (p) + cycle += _avr_push_addr(avr, new_pc) - 1; + new_pc = z << 1; + cycle++; + TRACE_JUMP(); + } end_emit; } break; - case 0x9508: // RET -- Return -- 1001 0101 0000 1000 - case 0x9518: { // RETI -- Return from Interrupt -- 1001 0101 0001 1000 + case 0x9508: // RET -- Return -- 1001 0101 0000 1000 + case 0x9518: emit { // RETI -- Return from Interrupt -- 1001 0101 0001 1000 if (opcode == 0x9518) { SREG_FLUSH( avr_sreg_set(avr, S_I, 1); avr_interrupt_reti(avr) ); } new_pc = _avr_pop_addr(avr); - cycle += 1 + avr->address_size; + cycle += 1 + avr_address_size; STATE("ret%s\n", opcode & 0x10 ? "i" : ""); TRACE_JUMP(); STACK_FRAME_POP(); - } break; - case 0x95c8: { // LPM -- Load Program Memory R0 <- (Z) -- 1001 0101 1100 1000 + } end_emit; + case 0x95c8: emit { // LPM -- Load Program Memory R0 <- (Z) -- 1001 0101 1100 1000 uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8); - STATE("lpm %s, (Z[%04x])\n", avr_regname(0), z); + STATE("lpm %s, (Z[%04x]) = %02x\n", avr_regname(0), z, avr->flash[z]); cycle += 2; // 3 cycles _sreg = _avr_set_r(avr, _sreg, 0, avr->flash[z]); } break; case 0x95d8: { // ELPM -- Load Program Memory R0 <- (Z) -- 1001 0101 1101 1000 if (!avr->rampz) _avr_invalid_opcode(avr); - uint32_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8) | (avr->data[avr->rampz] << 16); - STATE("elpm %s, (Z[%02x:%04x])\n", avr_regname(0), z >> 16, z & 0xffff); - _sreg = _avr_set_r(avr, _sreg, 0, avr->flash[z]); - cycle += 2; // 3 cycles + emit { + uint32_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8) | (avr->data[avr_rampz] << 16); + STATE("elpm %s, (Z[%02x:%04x])\n", avr_regname(0), z >> 16, z & 0xffff); + _sreg = _avr_set_r(avr, sreg, 0, avr->flash[z]); + cycle += 2; // 3 cycles + } end_emit; } break; default: { switch (opcode & 0xfe0f) { - case 0x9000: { // LDS -- Load Direct from Data Space, 32 bits -- 1001 0000 0000 0000 + case 0x9000: emit { // LDS -- Load Direct from Data Space, 32 bits -- 1001 0000 0000 0000 get_d5(opcode); uint16_t x = _avr_flash_read16le(avr, new_pc); new_pc += 2; STATE("lds %s[%02x], 0x%04x\n", avr_regname(d), avr->data[d], x); _sreg = _avr_set_r(avr, _sreg, d, _avr_get_ram(avr, x)); cycle++; // 2 cycles - } break; + } end_emit; case 0x9005: - case 0x9004: { // LPM -- Load Program Memory -- 1001 000d dddd 01oo + case 0x9004: emit { // LPM -- Load Program Memory -- 1001 000d dddd 01oo get_d5(opcode); uint16_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8); int op = opcode & 1; STATE("lpm %s, (Z[%04x]%s)\n", avr_regname(d), z, op ? "+" : ""); _sreg = _avr_set_r(avr, _sreg, d, avr->flash[z]); - if (op) { - z++; - _avr_set_r16le_hl( R_ZL, z); - } + if (op) + _avr_set_r16le_hl( R_ZL, z + 1); cycle += 2; // 3 cycles - } break; + } end_emit; case 0x9006: case 0x9007: { // ELPM -- Extended Load Program Memory -- 1001 000d dddd 01oo - if (!avr->rampz) + if (!avr_rampz) _avr_invalid_opcode(avr); - uint32_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8) | (avr->data[avr->rampz] << 16); - get_d5(opcode); - int op = opcode & 1; - STATE("elpm %s, (Z[%02x:%04x]%s)\n", avr_regname(d), z >> 16, z & 0xffff, op ? "+" : ""); - _sreg = _avr_set_r(avr, _sreg, d, avr->flash[z]); - if (op) { - z++; - _sreg = _avr_set_r(avr, _sreg, avr->rampz, z >> 16); - _avr_set_r16le_hl( R_ZL, z); - } - cycle += 2; // 3 cycles + emit { + uint32_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8) | (avr->data[avr_rampz] << 16); + get_d5(opcode); + int op = opcode & 1; + STATE("elpm %s, (Z[%02x:%04x]%s)\n", avr_regname(d), z >> 16, z & 0xffff, op ? "+" : ""); + _sreg = _avr_set_r(avr, _sreg, d, avr->flash[z]); + if (op) { + z++; + _sreg = _avr_set_r(avr, _sreg, avr->rampz, z >> 16); + _avr_set_r16le_hl( R_ZL, z); + } + cycle += 2; // 3 cycles + } end_emit; } break; /* * Load store instructions @@ -1049,7 +1096,7 @@ run_one_again: */ case 0x900c: case 0x900d: - case 0x900e: { // LD -- Load Indirect from Data using X -- 1001 000d dddd 11oo + case 0x900e: emit { // LD -- Load Indirect from Data using X -- 1001 000d dddd 11oo int op = opcode & 3; get_d5(opcode); uint16_t x = (avr->data[R_XH] << 8) | avr->data[R_XL]; @@ -1058,12 +1105,12 @@ run_one_again: if (op == 2) x--; uint8_t vd = _avr_get_ram(avr, x); if (op == 1) x++; - _avr_set_r16le_hl( R_XL, x); - _sreg = _avr_set_r(avr, _sreg, d, vd); - } break; + _avr_set_r16le_hl(avr, R_XL, x); + _avr_set_r(avr, d, vd); + } end_emit; case 0x920c: case 0x920d: - case 0x920e: { // ST -- Store Indirect Data Space X -- 1001 001d dddd 11oo + case 0x920e: emit { // ST -- Store Indirect Data Space X -- 1001 001d dddd 11oo int op = opcode & 3; get_vd5(opcode); uint16_t x = (avr->data[R_XH] << 8) | avr->data[R_XL]; @@ -1075,7 +1122,7 @@ run_one_again: _avr_set_r16le_hl( R_XL, x); } break; case 0x9009: - case 0x900a: { // LD -- Load Indirect from Data using Y -- 1001 000d dddd 10oo + case 0x900a: emit { // LD -- Load Indirect from Data using Y -- 1001 000d dddd 10oo int op = opcode & 3; get_d5(opcode); uint16_t y = (avr->data[R_YH] << 8) | avr->data[R_YL]; @@ -1088,7 +1135,7 @@ run_one_again: _sreg = _avr_set_r(avr, _sreg, d, vd); } break; case 0x9209: - case 0x920a: { // ST -- Store Indirect Data Space Y -- 1001 001d dddd 10oo + case 0x920a: emit { // ST -- Store Indirect Data Space Y -- 1001 001d dddd 10oo int op = opcode & 3; get_vd5(opcode); uint16_t y = (avr->data[R_YH] << 8) | avr->data[R_YL]; @@ -1098,8 +1145,8 @@ run_one_again: _sreg = _avr_set_ram(avr, _sreg, y, vd); if (op == 1) y++; _avr_set_r16le_hl( R_YL, y); - } break; - case 0x9200: { // STS -- Store Direct to Data Space, 32 bits -- 1001 0010 0000 0000 + } end_emit; + case 0x9200: emit { // STS -- Store Direct to Data Space, 32 bits -- 1001 0010 0000 0000 get_vd5(opcode); uint16_t x = _avr_flash_read16le(avr, new_pc); new_pc += 2; @@ -1108,7 +1155,7 @@ run_one_again: _sreg = _avr_set_ram(avr, _sreg, x, vd); } break; case 0x9001: - case 0x9002: { // LD -- Load Indirect from Data using Z -- 1001 000d dddd 00oo + case 0x9002: emit { // LD -- Load Indirect from Data using Z -- 1001 000d dddd 00oo int op = opcode & 3; get_d5(opcode); uint16_t z = (avr->data[R_ZH] << 8) | avr->data[R_ZL]; @@ -1119,9 +1166,9 @@ run_one_again: if (op == 1) z++; _avr_set_r16le_hl( R_ZL, z); _sreg = _avr_set_r(avr, _sreg, d, vd); - } break; + } end_emit; case 0x9201: - case 0x9202: { // ST -- Store Indirect Data Space Z -- 1001 001d dddd 00oo + case 0x9202: emit { // ST -- Store Indirect Data Space Z -- 1001 001d dddd 00oo int op = opcode & 3; get_vd5(opcode); uint16_t z = (avr->data[R_ZH] << 8) | avr->data[R_ZL]; @@ -1131,22 +1178,22 @@ run_one_again: _sreg = _avr_set_ram(avr, _sreg, z, vd); if (op == 1) z++; _avr_set_r16le_hl( R_ZL, z); - } break; - case 0x900f: { // POP -- 1001 000d dddd 1111 + } end_emit; + case 0x900f: emit { // POP -- 1001 000d dddd 1111 get_d5(opcode); _sreg = _avr_set_r(avr, _sreg, d, _avr_pop8(avr)); T(uint16_t sp = _avr_sp_get(avr);) STATE("pop %s (@%04x)[%02x]\n", avr_regname(d), sp, avr->data[sp]); cycle++; - } break; - case 0x920f: { // PUSH -- 1001 001d dddd 1111 + } end_emit; + case 0x920f: emit { // PUSH -- 1001 001d dddd 1111 get_vd5(opcode); _avr_push8(avr, vd); T(uint16_t sp = _avr_sp_get(avr);) STATE("push %s[%02x] (@%04x)\n", avr_regname(d), vd, sp); cycle++; - } break; - case 0x9400: { // COM -- One's Complement -- 1001 010d dddd 0000 + } end_emit; + case 0x9400: emit { // COM -- One's Complement -- 1001 010d dddd 0000 get_vd5(opcode); uint8_t res = 0xff - vd; STATE("com %s[%02x] = %02x\n", avr_regname(d), vd, res); @@ -1154,8 +1201,8 @@ run_one_again: _sreg = _avr_flags_znv0s(_sreg, res); SREG_SETBIT(S_C, 1); SREG(); - } break; - case 0x9401: { // NEG -- Two's Complement -- 1001 010d dddd 0001 + } end_emit; + case 0x9401: emit { // NEG -- Two's Complement -- 1001 010d dddd 0001 get_vd5(opcode); uint8_t res = 0x00 - vd; STATE("neg %s[%02x] = %02x\n", avr_regname(d), vd, res); @@ -1165,14 +1212,14 @@ run_one_again: SREG_SETBIT(S_C, res != 0); _sreg = _avr_flags_zns(_sreg, res); SREG(); - } break; - case 0x9402: { // SWAP -- Swap Nibbles -- 1001 010d dddd 0010 + } end_emit; + case 0x9402: emit { // SWAP -- Swap Nibbles -- 1001 010d dddd 0010 get_vd5(opcode); uint8_t res = (vd >> 4) | (vd << 4) ; STATE("swap %s[%02x] = %02x\n", avr_regname(d), vd, res); _sreg = _avr_set_r(avr, _sreg, d, res); - } break; - case 0x9403: { // INC -- Increment -- 1001 010d dddd 0011 + } end_emit; + case 0x9403: emit { // INC -- Increment -- 1001 010d dddd 0011 get_vd5(opcode); uint8_t res = vd + 1; STATE("inc %s[%02x] = %02x\n", avr_regname(d), vd, res); @@ -1180,16 +1227,16 @@ run_one_again: SREG_SETBIT(S_V, res == 0x80); _sreg = _avr_flags_zns(_sreg, res); SREG(); - } break; - case 0x9405: { // ASR -- Arithmetic Shift Right -- 1001 010d dddd 0101 + } end_emit; + case 0x9405: emit { // ASR -- Arithmetic Shift Right -- 1001 010d dddd 0101 get_vd5(opcode); uint8_t res = (vd >> 1) | (vd & 0x80); STATE("asr %s[%02x]\n", avr_regname(d), vd); _sreg = _avr_set_r(avr, _sreg, d, res); _sreg = _avr_flags_zcnvs(_sreg, res, vd); SREG(); - } break; - case 0x9406: { // LSR -- Logical Shift Right -- 1001 010d dddd 0110 + } end_emit; + case 0x9406: emit { // LSR -- Logical Shift Right -- 1001 010d dddd 0110 get_vd5(opcode); uint8_t res = vd >> 1; STATE("lsr %s[%02x]\n", avr_regname(d), vd); @@ -1197,16 +1244,16 @@ run_one_again: SREG_SETBIT(S_N, 0); _sreg = _avr_flags_zcvs(_sreg, res, vd); SREG(); - } break; - case 0x9407: { // ROR -- Rotate Right -- 1001 010d dddd 0111 + } end_emit; + case 0x9407: emit { // ROR -- Rotate Right -- 1001 010d dddd 0111 get_vd5(opcode); uint8_t res = (SREG_BIT(S_C) ? 0x80 : 0) | vd >> 1; STATE("ror %s[%02x]\n", avr_regname(d), vd); - _sreg = _avr_set_r(avr, _sreg, d, res); - _sreg = _avr_flags_zcnvs(_sreg, res, vd); + _avr_set_r(avr, d, res); + _avr_flags_zcnvs(avr, res, vd); SREG(); - } break; - case 0x940a: { // DEC -- Decrement -- 1001 010d dddd 1010 + } end_emit; + case 0x940a: emit { // DEC -- Decrement -- 1001 010d dddd 1010 get_vd5(opcode); uint8_t res = vd - 1; STATE("dec %s[%02x] = %02x\n", avr_regname(d), vd, res); @@ -1214,9 +1261,9 @@ run_one_again: SREG_SETBIT(S_V, res == 0x7f); _sreg = _avr_flags_zns(_sreg, res); SREG(); - } break; + } end_emit; case 0x940c: - case 0x940d: { // JMP -- Long Call to sub, 32 bits -- 1001 010a aaaa 110a + case 0x940d: emit { // JMP -- Long Call to sub, 32 bits -- 1001 010a aaaa 110a avr_flashaddr_t a = ((opcode & 0x01f0) >> 3) | (opcode & 1); uint16_t x = _avr_flash_read16le(avr, new_pc); a = (a << 16) | x; @@ -1224,9 +1271,9 @@ run_one_again: new_pc = a << 1; cycle += 2; TRACE_JUMP(); - } break; + } end_emit; case 0x940e: - case 0x940f: { // CALL -- Long Call to sub, 32 bits -- 1001 010a aaaa 111a + case 0x940f: emit { // CALL -- Long Call to sub, 32 bits -- 1001 010a aaaa 111a avr_flashaddr_t a = ((opcode & 0x01f0) >> 3) | (opcode & 1); uint16_t x = _avr_flash_read16le(avr, new_pc); a = (a << 16) | x; @@ -1236,11 +1283,11 @@ run_one_again: new_pc = a << 1; TRACE_JUMP(); STACK_FRAME_PUSH(); - } break; + } end_emit; default: { switch (opcode & 0xff00) { - case 0x9600: { // ADIW -- Add Immediate to Word -- 1001 0110 KKpp KKKK + case 0x9600: emit { // ADIW -- Add Immediate to Word -- 1001 0110 KKpp KKKK get_vp2_k6(opcode); uint16_t res = vp + k; STATE("adiw %s:%s[%04x], 0x%02x\n", avr_regname(p), avr_regname(p + 1), vp, k); @@ -1250,8 +1297,8 @@ run_one_again: _sreg = _avr_flags_zns16(_sreg, res); SREG(); cycle++; - } break; - case 0x9700: { // SBIW -- Subtract Immediate from Word -- 1001 0111 KKpp KKKK + } end_emit; + case 0x9700: emit { // SBIW -- Subtract Immediate from Word -- 1001 0111 KKpp KKKK get_vp2_k6(opcode); uint16_t res = vp - k; STATE("sbiw %s:%s[%04x], 0x%02x\n", avr_regname(p), avr_regname(p + 1), vp, k); @@ -1261,48 +1308,50 @@ run_one_again: _sreg = _avr_flags_zns16(_sreg, res); SREG(); cycle++; - } break; - case 0x9800: { // CBI -- Clear Bit in I/O Register -- 1001 1000 AAAA Abbb + } end_emit; + case 0x9800: emit { // CBI -- Clear Bit in I/O Register -- 1001 1000 AAAA Abbb get_io5_b3mask(opcode); uint8_t res = _avr_get_ram(avr, io) & ~mask; STATE("cbi %s[%04x], 0x%02x = %02x\n", avr_regname(io), avr->data[io], mask, res); _sreg = _avr_set_ram(avr, _sreg, io, res); cycle++; - } break; - case 0x9900: { // SBIC -- Skip if Bit in I/O Register is Cleared -- 1001 1001 AAAA Abbb - get_io5_b3mask(opcode); - uint8_t res = _avr_get_ram(avr, io) & mask; - STATE("sbic %s[%04x], 0x%02x\t; Will%s branch\n", avr_regname(io), avr->data[io], mask, !res?"":" not"); - if (!res) { - if (_avr_is_instruction_32_bits(avr, new_pc)) { - new_pc += 4; cycle += 2; - } else { - new_pc += 2; cycle++; + } end_emit; + case 0x9900: { + const int skip = 1 + _avr_is_instruction_32_bits(avr, new_pc); + emit { // SBIC -- Skip if Bit in I/O Register is Cleared -- 1001 1001 AAAA Abbb + emit_literal("const int skip = %d", skip); + get_io5_b3mask(opcode); + uint8_t res = _avr_get_ram(avr, io) & mask; + STATE("sbic %s[%04x], 0x%02x\t; Will%s branch\n", avr_regname(io), avr->data[io], mask, !res?"":" not"); + if (!res) { + new_pc += 2 * skip; cycle += skip; + TRACE_JUMP(); } - } + } end_emit; } break; - case 0x9a00: { // SBI -- Set Bit in I/O Register -- 1001 1010 AAAA Abbb + case 0x9a00: emit { // SBI -- Set Bit in I/O Register -- 1001 1010 AAAA Abbb get_io5_b3mask(opcode); uint8_t res = _avr_get_ram(avr, io) | mask; STATE("sbi %s[%04x], 0x%02x = %02x\n", avr_regname(io), avr->data[io], mask, res); _sreg = _avr_set_ram(avr, _sreg, io, res); cycle++; - } break; - case 0x9b00: { // SBIS -- Skip if Bit in I/O Register is Set -- 1001 1011 AAAA Abbb - get_io5_b3mask(opcode); - uint8_t res = _avr_get_ram(avr, io) & mask; - STATE("sbis %s[%04x], 0x%02x\t; Will%s branch\n", avr_regname(io), avr->data[io], mask, res?"":" not"); - if (res) { - if (_avr_is_instruction_32_bits(avr, new_pc)) { - new_pc += 4; cycle += 2; - } else { - new_pc += 2; cycle++; + } end_emit; + case 0x9b00: { + const int skip = 1 + _avr_is_instruction_32_bits(avr, new_pc); + emit { // SBIS -- Skip if Bit in I/O Register is Set -- 1001 1011 AAAA Abbb + emit_literal("const int skip = %d", skip); + get_io5_b3mask(opcode); + uint8_t res = _avr_get_ram(avr, io) & mask; + STATE("sbis %s[%04x], 0x%02x\t; Will%s branch\n", avr_regname(io), avr->data[io], mask, res?"":" not"); + if (res) { + new_pc += 2 * skip; cycle += skip; + TRACE_JUMP(); } - } + } end_emit; } break; default: switch (opcode & 0xfc00) { - case 0x9c00: { // MUL -- Multiply Unsigned -- 1001 11rd dddd rrrr + case 0x9c00: emit { // MUL -- Multiply Unsigned -- 1001 11rd dddd rrrr get_vd5_vr5(opcode); uint16_t res = vd * vr; STATE("mul %s[%02x], %s[%02x] = %04x\n", avr_regname(d), vd, avr_regname(r), vr, res); @@ -1311,7 +1360,7 @@ run_one_again: SREG_SETBIT(S_Z, res == 0); SREG_SETBIT(S_C, (res >> 15) & 1); SREG(); - } break; + } end_emit; default: _avr_invalid_opcode(avr); } } @@ -1323,45 +1372,45 @@ run_one_again: case 0xb000: { switch (opcode & 0xf800) { - case 0xb800: { // OUT A,Rr -- 1011 1AAd dddd AAAA + case 0xb800: emit { // OUT A,Rr -- 1011 1AAd dddd AAAA get_d5_a6(opcode); STATE("out %s, %s[%02x]\n", avr_regname(A), avr_regname(d), avr->data[d]); _sreg = _avr_set_ram(avr, _sreg, A, avr->data[d]); - } break; - case 0xb000: { // IN Rd,A -- 1011 0AAd dddd AAAA + } end_emit; + case 0xb000: emit { // IN Rd,A -- 1011 0AAd dddd AAAA get_d5_a6(opcode); STATE("in %s, %s[%02x]\n", avr_regname(d), avr_regname(A), avr->data[A]); _sreg = _avr_set_r(avr, _sreg, d, _avr_get_ram(avr, A)); - } break; + } end_emit; default: _avr_invalid_opcode(avr); } } break; - case 0xc000: { // RJMP -- 1100 kkkk kkkk kkkk + case 0xc000: emit { // RJMP -- 1100 kkkk kkkk kkkk get_o12(opcode); STATE("rjmp .%d [%04x]\n", o >> 1, new_pc + o); - new_pc = (new_pc + o) % (avr->flashend+1); + new_pc = (new_pc + o) % (avr_flashend + 1); cycle++; TRACE_JUMP(); - } break; + } end_emit; - case 0xd000: { // RCALL -- 1101 kkkk kkkk kkkk + case 0xd000: emit { // RCALL -- 1101 kkkk kkkk kkkk get_o12(opcode); STATE("rcall .%d [%04x]\n", o >> 1, new_pc + o); cycle += _avr_push_addr(avr, new_pc); - new_pc = (new_pc + o) % (avr->flashend+1); + new_pc = (new_pc + o) % (avr_flashend + 1); // 'rcall .1' is used as a cheap "push 16 bits of room on the stack" if (o != 0) { TRACE_JUMP(); STACK_FRAME_PUSH(); } - } break; + } end_emit; - case 0xe000: { // LDI Rd, K aka SER (LDI r, 0xff) -- 1110 kkkk dddd kkkk + case 0xe000: emit { // LDI Rd, K aka SER (LDI r, 0xff) -- 1110 kkkk dddd kkkk get_h4_k8(opcode); STATE("ldi %s, 0x%02x\n", avr_regname(h), k); _sreg = _avr_set_r(avr, _sreg, h, k); - } break; + } end_emit; case 0xf000: { switch (opcode & 0xfe00) { @@ -1375,52 +1424,52 @@ run_one_again: case 0xf000: case 0xf200: case 0xf400: - case 0xf600: { // BRXC/BRXS -- All the SREG branches -- 1111 0Boo oooo osss + case 0xf600: emit { // BRXC/BRXS -- All the SREG branches -- 1111 0Boo oooo osss int16_t o = ((int16_t)(opcode << 6)) >> 9; // offset uint8_t s = opcode & 7; int set = (opcode & 0x0400) == 0; // this bit means BRXC otherwise BRXS - const char *names[2][8] = { - { "brcc", "brne", "brpl", "brvc", NULL, "brhc", "brtc", "brid"}, - { "brcs", "breq", "brmi", "brvs", NULL, "brhs", "brts", "brie"}, - }; int branch = (SREG_BIT(s) && set) || (!SREG_BIT(s) && !set); - if (names[set][s]) { - STATE("%s .%d [%04x]\t; Will%s branch\n", names[set][s], o, new_pc + (o << 1), branch ? "":" not"); +#ifdef CONFIG_SIMAVR_TRACE + if (brxc_names[set][s]) { + STATE("%s .%d [%04x]\t; Will%s branch\n", brxc_names[set][s], o, new_pc + (o << 1), branch ? "":" not"); } else { STATE("%s%c .%d [%04x]\t; Will%s branch\n", set ? "brbs" : "brbc", _sreg_bit_name[s], o, new_pc + (o << 1), branch ? "":" not"); } +#endif if (branch) { cycle++; // 2 cycles if taken, 1 otherwise new_pc = new_pc + (o << 1); + TRACE_JUMP(); } - } break; + } end_emit; case 0xf800: - case 0xf900: { // BLD -- Bit Store from T into a Bit in Register -- 1111 100d dddd 0bbb + case 0xf900: emit { // BLD -- Bit Store from T into a Bit in Register -- 1111 100d dddd 0bbb get_vd5_s3_mask(opcode); uint8_t v = (vd & ~mask) | (SREG_BIT(S_T) ? mask : 0); STATE("bld %s[%02x], 0x%02x = %02x\n", avr_regname(d), vd, mask, v); _sreg = _avr_set_r(avr, _sreg, d, v); - } break; + } end_emit; case 0xfa00: - case 0xfb00:{ // BST -- Bit Store into T from bit in Register -- 1111 101d dddd 0bbb - get_vd5_s3(opcode) + case 0xfb00: emit { // BST -- Bit Store into T from bit in Register -- 1111 101d dddd 0bbb + get_vd5_s3(opcode); STATE("bst %s[%02x], 0x%02x\n", avr_regname(d), vd, 1 << s); SREG_SETBIT(S_T, (vd >> s) & 1); SREG(); - } break; + } end_emit; case 0xfc00: - case 0xfe00: { // SBRS/SBRC -- Skip if Bit in Register is Set/Clear -- 1111 11sd dddd 0bbb - get_vd5_s3_mask(opcode) - int set = (opcode & 0x0200) != 0; - int branch = ((vd & mask) && set) || (!(vd & mask) && !set); - STATE("%s %s[%02x], 0x%02x\t; Will%s branch\n", set ? "sbrs" : "sbrc", avr_regname(d), vd, mask, branch ? "":" not"); - if (branch) { - if (_avr_is_instruction_32_bits(avr, new_pc)) { - new_pc += 4; cycle += 2; - } else { - new_pc += 2; cycle++; + case 0xfe00: { + const int skip = 1 + _avr_is_instruction_32_bits(avr, new_pc); + emit { // SBRS/SBRC -- Skip if Bit in Register is Set/Clear -- 1111 11sd dddd 0bbb + emit_literal("const int skip = %d", skip); + get_vd5_s3_mask(opcode); + int set = (opcode & 0x0200) != 0; + int branch = ((vd & mask) && set) || (!(vd & mask) && !set); + STATE("%s %s[%02x], 0x%02x\t; Will%s branch\n", set ? "sbrs" : "sbrc", avr_regname(d), vd, mask, branch ? "":" not"); + if (branch) { + new_pc += 2 * skip; cycle += skip; + TRACE_JUMP(); } - } + } end_emit; } break; default: _avr_invalid_opcode(avr); } @@ -1429,6 +1478,8 @@ run_one_again: default: _avr_invalid_opcode(avr); } + // JIT_EXTRACT_END <-- don't change this line + avr->cycle += cycle; SREG_END(avr); diff --git a/simavr/sim/sim_core_jit.c b/simavr/sim/sim_core_jit.c new file mode 100644 index 0000000..de60c86 --- /dev/null +++ b/simavr/sim/sim_core_jit.c @@ -0,0 +1,211 @@ +/* + sim_core_jit.c + + Copyright 2008, 2009 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#define _GNU_SOURCE /* for asprintf */ +#include +#include +#include +#include +#include +#include "sim_avr.h" +#include "sim_core.h" +#include "sim_gdb.h" +#include "avr_flash.h" + +#define _avr_invalid_opcode(a) {} + +static inline uint16_t +_avr_flash_read16le( + avr_t * avr, + avr_flashaddr_t addr) +{ + return(avr->flash[addr] | (avr->flash[addr + 1] << 8)); +} + + +static inline int _avr_is_instruction_32_bits(avr_t * avr, avr_flashaddr_t pc) +{ + uint16_t o = _avr_flash_read16le(avr, pc) & 0xfc0f; + return o == 0x9200 || // STS ! Store Direct to Data Space + o == 0x9000 || // LDS Load Direct from Data Space + o == 0x940c || // JMP Long Jump + o == 0x940d || // JMP Long Jump + o == 0x940e || // CALL Long Call to sub + o == 0x940f; // CALL Long Call to sub +} + +typedef struct buf_t { + char * buffer; + size_t b_len, b_size; +} buf_t, *buf_p; + +void +buf_add_len( + buf_p b, const char * t, int l) +{ + size_t newsize = b->b_size; + + while (b->b_len + l >= newsize) + newsize += 256; + if (newsize != b->b_size) { + b->buffer = realloc(b->buffer, newsize); + b->b_size = newsize; + } + memcpy(b->buffer + b->b_len, t, l + 1); + b->b_len += l; +} + +void +buf_add( + buf_p b, const char * t) +{ + buf_add_len(b, t, strlen(t)); +} + +avr_flashaddr_t +avr_translate_firmware( + avr_t * avr) +{ + buf_t code = {0}, literal = {0}; + buf_t jump_table = {0}; + + avr_flashaddr_t pc = 0; + + void jit_generate_head(uint16_t o) { + char * b; + if (asprintf(&b, "f%04x: {\nconst uint16_t opcode = 0x%04x;\n", pc, o)) {}; + buf_add(&code, b); free(b); + buf_add(&code, "cycle++;"); + if (asprintf(&b, "new_pc = 0x%04x + 2;\n", pc)) {}; + buf_add(&code, b); free(b); + // if (asprintf(&b, "printf(\"%04x: %04x; cycle %%d/%%d\\n\",cycle,howLong);\n", pc, o)); + // buf_add(&code, b); free(b); + /* this is gcc/tcc 'label as value' C extension. Handy */ + if (asprintf(&b, "[0x%04x]= &&f%04x,\n", pc/2, pc)) {}; + buf_add(&jump_table, b); free(b); + } + void jit_generate_tail(uint16_t o) { + buf_add(&code, "if (*is || cycle >= howLong) goto exit;\n}\n"); + } + void jit_generate_literal(const char * fmt, ...) { + char * b; + va_list ap; + va_start(ap, fmt); + if (vasprintf(&b, fmt, ap)) {}; + va_end(ap); + buf_add(&literal, b); + buf_add(&literal, ";\n"); + free(b); + } + void jit_literal_flush() { + if (literal.b_len) { + buf_add(&code, literal.buffer); + literal.b_len = 0; + } + } + void jit_generate(uint16_t o, const char * t) { + jit_generate_head(o); + jit_literal_flush(); + const char * l = t; + do { + const char * nl = index(l, '\n'); + if (strncmp(l, "STATE", 5) || avr->trace) + buf_add_len(&code, l, nl-l+1); + l = nl + 1; + } while (*l); + jit_generate_tail(o); + } + do { + avr_flashaddr_t new_pc = pc + 2; + uint16_t opcode = _avr_flash_read16le(avr, pc); + const int avr_rampz = avr->rampz; + const int avr_eind = avr->eind; + + #include "sim_core_jit.h" + pc = new_pc; + } while (pc < avr->codeend); + + printf("Code size: %ld\n", code.b_len); + + FILE *o = fopen("jit_code.c", "w"); + fprintf(o, "static const void * jt[%d] = {\n%s};\n", pc/2, jump_table.buffer); + /* goto current 'pc' */ + fprintf(o, "TRACE_JUMP();\n"); + fwrite(code.buffer, code.b_len, 1, o); + fclose(o); + free(code.buffer); + free(literal.buffer); + free(jump_table.buffer); + return 0; +} + + +void +avr_callback_run_jit( + avr_t * avr) +{ + avr_flashaddr_t new_pc = avr->pc; + + if (avr->state == cpu_Running) { + int cycle = 0; + new_pc = avr->jit.entry( + avr->jit.jit_avr, + new_pc, + &avr->state, + &avr->interrupt_state, + &cycle, 200); + avr->cycle += cycle; + } + + // run the cycle timers, get the suggested sleep time + // until the next timer is due + avr_cycle_count_t sleep = avr_cycle_timer_process(avr); + + avr->pc = new_pc; + + if (avr->state == cpu_Sleeping) { +#ifndef SREG_BIT + if (!avr->sreg[S_I]) { +#else + if (!SREG_BIT(S_I)) { +#endif + if (avr->log) + AVR_LOG(avr, LOG_TRACE, "simavr: sleeping with interrupts off, quitting gracefully\n"); + avr->state = cpu_Done; + return; + } + /* + * try to sleep for as long as we can (?) + */ + avr->sleep(avr, sleep); + avr->cycle += 1 + sleep; + } + // Interrupt servicing might change the PC too, during 'sleep' + if (avr->state == cpu_Running || avr->state == cpu_Sleeping) { + /* Note: checking interrupt_state here is completely superfluous, however + as interrupt_state tells us all we really need to know, here + a simple check here may be cheaper than a call not needed. */ + if (avr->interrupt_state) + avr_service_interrupts(avr); + } +} + + diff --git a/simavr/sim/sim_core_jit.h b/simavr/sim/sim_core_jit.h new file mode 100644 index 0000000..15bf1b1 --- /dev/null +++ b/simavr/sim/sim_core_jit.h @@ -0,0 +1,870 @@ +/* THIS FILE IS AUTOGENERATED, DO NOT EDIT */ +#ifndef __SIM_CORE_JIT_H__ +#define __SIM_CORE_JIT_H__ + // JIT_EXTRACT_START <-- don't change this line, + // it's there to help the script extract the opcode state machine + jit_literal_flush(); + + switch (opcode & 0xf000) { + case 0x0000: { + switch (opcode) { + case 0x0000: { // NOP +jit_generate(opcode, "STATE(\"nop\\n\");\n" +); + } break; + default: { + switch (opcode & 0xfc00) { + case 0x0400: { // CPC -- Compare with carry -- 0000 01rd dddd rrrr +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint8_t res = vd - vr - SREG_BIT(S_C);\n" +"STATE(\"cpc %s[%02x], %s[%02x] = %02x\\n\", avr_regname(d), vd, avr_regname(r), vr, res);\n" +"_avr_flags_sub_Rzns(avr, res, vd, vr);\n" +"SREG();\n" +); + } break; + case 0x0c00: { // ADD -- Add without carry -- 0000 11rd dddd rrrr +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint8_t res = vd + vr;\n" +"if (r == d) {\n" +"STATE(\"lsl %s[%02x] = %02x\\n\", avr_regname(d), vd, res & 0xff);\n" +"} else {\n" +"STATE(\"add %s[%02x], %s[%02x] = %02x\\n\", avr_regname(d), vd, avr_regname(r), vr, res);\n" +"}\n" +"_avr_set_r(avr, d, res);\n" +"_avr_flags_add_zns(avr, res, vd, vr);\n" +"SREG();\n" +); + } break; + case 0x0800: { // SBC -- Subtract with carry -- 0000 10rd dddd rrrr +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint8_t res = vd - vr - SREG_BIT(S_C);\n" +"STATE(\"sbc %s[%02x], %s[%02x] = %02x\\n\", avr_regname(d), avr_data[d], avr_regname(r), avr_data[r], res);\n" +"_avr_set_r(avr, d, res);\n" +"_avr_flags_sub_Rzns(avr, res, vd, vr);\n" +"SREG();\n" +); + } break; + default: + switch (opcode & 0xff00) { + case 0x0100: { // MOVW -- Copy Register Word -- 0000 0001 dddd rrrr +jit_generate(opcode, "uint8_t d = ((opcode >> 4) & 0xf) << 1;\n" +"uint8_t r = ((opcode) & 0xf) << 1;\n" +"STATE(\"movw %s:%s, %s:%s[%02x%02x]\\n\", avr_regname(d), avr_regname(d+1), avr_regname(r), avr_regname(r+1), avr_data[r+1], avr_data[r]);\n" +"uint16_t vr = avr_data[r] | (avr_data[r + 1] << 8);\n" +"_avr_set_r16le(avr, d, vr);\n" +); + } break; + case 0x0200: { // MULS -- Multiply Signed -- 0000 0010 dddd rrrr +jit_generate(opcode, "int8_t r = 16 + (opcode & 0xf);\n" +"int8_t d = 16 + ((opcode >> 4) & 0xf);\n" +"int16_t res = ((int8_t)avr_data[r]) * ((int8_t)avr_data[d]);\n" +"STATE(\"muls %s[%d], %s[%02x] = %d\\n\", avr_regname(d), ((int8_t)avr_data[d]), avr_regname(r), ((int8_t)avr_data[r]), res);\n" +"_avr_set_r16le(avr, 0, res);\n" +"SREG_SETBIT(S_C, (res >> 15) & 1);\n" +"SREG_SETBIT(S_Z, res == 0);\n" +"cycle++;\n" +"SREG();\n" +); + } break; + case 0x0300: { // MUL -- Multiply -- 0000 0011 fddd frrr +jit_generate(opcode, "int8_t r = 16 + (opcode & 0x7);\n" +"int8_t d = 16 + ((opcode >> 4) & 0x7);\n" +"int16_t res = 0;\n" +"uint8_t c = 0;\n" +"T(const char * name = \"\";)\n" +"switch (opcode & 0x88) {\n" +"case 0x00: // MULSU -- Multiply Signed Unsigned -- 0000 0011 0ddd 0rrr\n" +"res = ((uint8_t)avr_data[r]) * ((int8_t)avr_data[d]);\n" +"c = (res >> 15) & 1;\n" +"T(name = \"mulsu\";)\n" +"break;\n" +"case 0x08: // FMUL -- Fractional Multiply Unsigned -- 0000 0011 0ddd 1rrr\n" +"res = ((uint8_t)avr_data[r]) * ((uint8_t)avr_data[d]);\n" +"c = (res >> 15) & 1;\n" +"res <<= 1;\n" +"T(name = \"fmul\";)\n" +"break;\n" +"case 0x80: // FMULS -- Multiply Signed -- 0000 0011 1ddd 0rrr\n" +"res = ((int8_t)avr_data[r]) * ((int8_t)avr_data[d]);\n" +"c = (res >> 15) & 1;\n" +"res <<= 1;\n" +"T(name = \"fmuls\";)\n" +"break;\n" +"case 0x88: // FMULSU -- Multiply Signed Unsigned -- 0000 0011 1ddd 1rrr\n" +"res = ((uint8_t)avr_data[r]) * ((int8_t)avr_data[d]);\n" +"c = (res >> 15) & 1;\n" +"res <<= 1;\n" +"T(name = \"fmulsu\";)\n" +"break;\n" +"}\n" +"cycle++;\n" +"STATE(\"%s %s[%d], %s[%02x] = %d\\n\", name, avr_regname(d), ((int8_t)avr_data[d]), avr_regname(r), ((int8_t)avr_data[r]), res);\n" +"_avr_set_r16le(avr, 0, res);\n" +"SREG_SETBIT(S_C, c);\n" +"SREG_SETBIT(S_Z, res == 0);\n" +"SREG();\n" +); + } break; + default: _avr_invalid_opcode(avr); + } + } + } + } + } break; + + case 0x1000: { + switch (opcode & 0xfc00) { + case 0x1800: { // SUB -- Subtract without carry -- 0001 10rd dddd rrrr +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint8_t res = vd - vr;\n" +"STATE(\"sub %s[%02x], %s[%02x] = %02x\\n\", avr_regname(d), vd, avr_regname(r), vr, res);\n" +"_avr_set_r(avr, d, res);\n" +"_avr_flags_sub_zns(avr, res, vd, vr);\n" +"SREG();\n" +); + } break; + case 0x1000: { // CPSE -- Compare, skip if equal -- 0001 00rd dddd rrrr + /* This code is deduped like this to allow emmiting a 'constant' + * piece of code, without having to read the next instruction in case + * of JIT. In normal mode, we lose a few cycles but at least the code is + * clear */ + const int skip = 1 + _avr_is_instruction_32_bits(avr, new_pc); + { + jit_generate_literal("const int skip = %d", skip); +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint16_t res = vd == vr;\n" +"STATE(\"cpse %s[%02x], %s[%02x]\\t; Will%s skip\\n\", avr_regname(d), avr_data[d], avr_regname(r), avr_data[r], res ? \"\":\" not\");\n" +"if (res) {\n" +"new_pc += 2 * skip; cycle += skip;\n" +"TRACE_JUMP();\n" +"}\n" +); + } break; + } break; + case 0x1400: { // CP -- Compare -- 0001 01rd dddd rrrr +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint8_t res = vd - vr;\n" +"STATE(\"cp %s[%02x], %s[%02x] = %02x\\n\", avr_regname(d), vd, avr_regname(r), vr, res);\n" +"_avr_flags_sub_zns(avr, res, vd, vr);\n" +"SREG();\n" +); + } break; + case 0x1c00: { // ADD -- Add with carry -- 0001 11rd dddd rrrr +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint8_t res = vd + vr + SREG_BIT(S_C);\n" +"if (r == d) {\n" +"STATE(\"rol %s[%02x] = %02x\\n\", avr_regname(d), avr_data[d], res);\n" +"} else {\n" +"STATE(\"addc %s[%02x], %s[%02x] = %02x\\n\", avr_regname(d), avr_data[d], avr_regname(r), avr_data[r], res);\n" +"}\n" +"_avr_set_r(avr, d, res);\n" +"_avr_flags_add_zns(avr, res, vd, vr);\n" +"SREG();\n" +); + } break; + default: _avr_invalid_opcode(avr); + } + } break; + + case 0x2000: { + switch (opcode & 0xfc00) { + case 0x2000: { // AND -- Logical AND -- 0010 00rd dddd rrrr +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint8_t res = vd & vr;\n" +"if (r == d) {\n" +"STATE(\"tst %s[%02x]\\n\", avr_regname(d), avr_data[d]);\n" +"} else {\n" +"STATE(\"and %s[%02x], %s[%02x] = %02x\\n\", avr_regname(d), vd, avr_regname(r), vr, res);\n" +"}\n" +"_avr_set_r(avr, d, res);\n" +"_avr_flags_znv0s(avr, res);\n" +"SREG();\n" +); + } break; + case 0x2400: { // EOR -- Logical Exclusive OR -- 0010 01rd dddd rrrr +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint8_t res = vd ^ vr;\n" +"if (r==d) {\n" +"STATE(\"clr %s[%02x]\\n\", avr_regname(d), avr_data[d]);\n" +"} else {\n" +"STATE(\"eor %s[%02x], %s[%02x] = %02x\\n\", avr_regname(d), vd, avr_regname(r), vr, res);\n" +"}\n" +"_avr_set_r(avr, d, res);\n" +"_avr_flags_znv0s(avr, res);\n" +"SREG();\n" +); + } break; + case 0x2800: { // OR -- Logical OR -- 0010 10rd dddd rrrr +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint8_t res = vd | vr;\n" +"STATE(\"or %s[%02x], %s[%02x] = %02x\\n\", avr_regname(d), vd, avr_regname(r), vr, res);\n" +"_avr_set_r(avr, d, res);\n" +"_avr_flags_znv0s(avr, res);\n" +"SREG();\n" +); + } break; + case 0x2c00: { // MOV -- 0010 11rd dddd rrrr +jit_generate(opcode, "get_d5_vr5(opcode);\n" +"uint8_t res = vr;\n" +"STATE(\"mov %s, %s[%02x] = %02x\\n\", avr_regname(d), avr_regname(r), vr, res);\n" +"_avr_set_r(avr, d, res);\n" +); + } break; + default: _avr_invalid_opcode(avr); + } + } break; + + case 0x3000: { // CPI -- Compare Immediate -- 0011 kkkk hhhh kkkk +jit_generate(opcode, "get_vh4_k8(opcode);\n" +"uint8_t res = vh - k;\n" +"STATE(\"cpi %s[%02x], 0x%02x\\n\", avr_regname(h), vh, k);\n" +"_avr_flags_sub_zns(avr, res, vh, k);\n" +"SREG();\n" +); + } break; + + case 0x4000: { // SBCI -- Subtract Immediate With Carry -- 0100 kkkk hhhh kkkk +jit_generate(opcode, "get_vh4_k8(opcode);\n" +"uint8_t res = vh - k - SREG_BIT(S_C);\n" +"STATE(\"sbci %s[%02x], 0x%02x = %02x\\n\", avr_regname(h), vh, k, res);\n" +"_avr_set_r(avr, h, res);\n" +"_avr_flags_sub_Rzns(avr, res, vh, k);\n" +"SREG();\n" +); + } break; + + case 0x5000: { // SUBI -- Subtract Immediate -- 0101 kkkk hhhh kkkk +jit_generate(opcode, "get_vh4_k8(opcode);\n" +"uint8_t res = vh - k;\n" +"STATE(\"subi %s[%02x], 0x%02x = %02x\\n\", avr_regname(h), vh, k, res);\n" +"_avr_set_r(avr, h, res);\n" +"_avr_flags_sub_zns(avr, res, vh, k);\n" +"SREG();\n" +); + } break; + + case 0x6000: { // ORI aka SBR -- Logical OR with Immediate -- 0110 kkkk hhhh kkkk +jit_generate(opcode, "get_vh4_k8(opcode);\n" +"uint8_t res = vh | k;\n" +"STATE(\"ori %s[%02x], 0x%02x\\n\", avr_regname(h), vh, k);\n" +"_avr_set_r(avr, h, res);\n" +"_avr_flags_znv0s(avr, res);\n" +"SREG();\n" +); + } break; + + case 0x7000: { // ANDI -- Logical AND with Immediate -- 0111 kkkk hhhh kkkk +jit_generate(opcode, "get_vh4_k8(opcode);\n" +"uint8_t res = vh & k;\n" +"STATE(\"andi %s[%02x], 0x%02x\\n\", avr_regname(h), vh, k);\n" +"_avr_set_r(avr, h, res);\n" +"_avr_flags_znv0s(avr, res);\n" +"SREG();\n" +); + } break; + + case 0xa000: + case 0x8000: { + /* + * Load (LDD/STD) store instructions + * + * 10q0 qqsd dddd yqqq + * s = 0 = load, 1 = store + * y = 16 bits register index, 1 = Y, 0 = X + * q = 6 bit displacement + */ + switch (opcode & 0xd008) { + case 0xa000: + case 0x8000: { // LD (LDD) -- Load Indirect using Z -- 10q0 qqsd dddd yqqq +jit_generate(opcode, "uint16_t v = avr_data[R_ZL] | (avr_data[R_ZH] << 8);\n" +"get_d5_q6(opcode);\n" +"if (opcode & 0x0200) {\n" +"STATE(\"st (Z+%d[%04x]), %s[%02x]\\n\", q, v+q, avr_regname(d), avr_data[d]);\n" +"_avr_set_ram(avr, v+q, avr_data[d]);\n" +"} else {\n" +"STATE(\"ld %s, (Z+%d[%04x])=[%02x]\\n\", avr_regname(d), q, v+q, avr_data[v+q]);\n" +"_avr_set_r(avr, d, _avr_get_ram(avr, v+q));\n" +"}\n" +"cycle += 1; // 2 cycles, 3 for tinyavr\n" +); + } break; + case 0xa008: + case 0x8008: { // LD (LDD) -- Load Indirect using Y -- 10q0 qqsd dddd yqqq +jit_generate(opcode, "uint16_t v = avr_data[R_YL] | (avr_data[R_YH] << 8);\n" +"get_d5_q6(opcode);\n" +"if (opcode & 0x0200) {\n" +"STATE(\"st (Y+%d[%04x]), %s[%02x]\\n\", q, v+q, avr_regname(d), avr_data[d]);\n" +"_avr_set_ram(avr, v+q, avr_data[d]);\n" +"} else {\n" +"STATE(\"ld %s, (Y+%d[%04x])=[%02x]\\n\", avr_regname(d), q, v+q, avr_data[d+q]);\n" +"_avr_set_r(avr, d, _avr_get_ram(avr, v+q));\n" +"}\n" +"cycle += 1; // 2 cycles, 3 for tinyavr\n" +); + } break; + default: _avr_invalid_opcode(avr); + } + } break; + + case 0x9000: { + /* this is an annoying special case, but at least these lines handle all the SREG set/clear opcodes */ + if ((opcode & 0xff0f) == 0x9408) { + { +jit_generate(opcode, "get_sreg_bit(opcode);\n" +"STATE(\"%s%c\\n\", opcode & 0x0080 ? \"cl\" : \"se\", _sreg_bit_name[b]);\n" +"SREG_SETBIT(b, (opcode & 0x0080) == 0);\n" +"SREG();\n" +); + } break; + } else switch (opcode) { + case 0x9588: { // SLEEP -- 1001 0101 1000 1000 +jit_generate(opcode, "STATE(\"sleep\\n\");\n" +"/* Don't sleep if there are interrupts about to be serviced.\n" +"* Without this check, it was possible to incorrectly enter a state\n" +"* in which the cpu was sleeping and interrupts were disabled. For more\n" +"* details, see the commit message. */\n" +"if (!avr_has_pending_interrupts(avr) || !SREG_BIT(S_I)) {\n" +"avr_state = cpu_Sleeping;\n" +"CORE_SLEEP();\n" +"}\n" +); + } break; + case 0x9598: { // BREAK -- 1001 0101 1001 1000 +jit_generate(opcode, "STATE(\"break\\n\");\n" +"if (avr->gdb) {\n" +"// if gdb is on, we break here as in here\n" +"// and we do so until gdb restores the instruction\n" +"// that was here before\n" +"avr_state = cpu_StepDone;\n" +"new_pc = avr->pc;\n" +"cycle = 0;\n" +"}\n" +); + } break; + case 0x95a8: { // WDR -- Watchdog Reset -- 1001 0101 1010 1000 +jit_generate(opcode, "STATE(\"wdr\\n\");\n" +"avr_ioctl(avr, AVR_IOCTL_WATCHDOG_RESET, 0);\n" +); + } break; + case 0x95e8: { // SPM -- Store Program Memory -- 1001 0101 1110 1000 +jit_generate(opcode, "STATE(\"spm\\n\");\n" +"avr_ioctl(avr, AVR_IOCTL_FLASH_SPM, 0);\n" +); + } break; + case 0x9409: // IJMP -- Indirect jump -- 1001 0100 0000 1001 + case 0x9419: // EIJMP -- Indirect jump -- 1001 0100 0001 1001 bit 4 is "indirect" + case 0x9509: // ICALL -- Indirect Call to Subroutine -- 1001 0101 0000 1001 + case 0x9519: { // EICALL -- Indirect Call to Subroutine -- 1001 0101 0001 1001 bit 8 is "push pc" + int e = opcode & 0x10; + int p = opcode & 0x100; + if (e && !avr_eind) + _avr_invalid_opcode(avr); + { + jit_generate_literal("const int e = %d", e); + jit_generate_literal("const int p = %d", p); +jit_generate(opcode, "uint32_t z = avr_data[R_ZL] | (avr_data[R_ZH] << 8);\n" +"if (e)\n" +"z |= avr_data[avr_eind] << 16;\n" +"STATE(\"%si%s Z[%04x]\\n\", e?\"e\":\"\", p?\"call\":\"jmp\", z << 1);\n" +"if (p)\n" +"cycle += _avr_push_addr(avr, new_pc) - 1;\n" +"new_pc = z << 1;\n" +"cycle++;\n" +"TRACE_JUMP();\n" +); + } break; + } break; + case 0x9508: // RET -- Return -- 1001 0101 0000 1000 + case 0x9518: { // RETI -- Return from Interrupt -- 1001 0101 0001 1000 +jit_generate(opcode, "if (opcode == 0x9518) {\n" +"avr_sreg_set(avr, S_I, 1);\n" +"avr_interrupt_reti(avr);\n" +"}\n" +"new_pc = _avr_pop_addr(avr);\n" +"cycle += 1 + avr_address_size;\n" +"STATE(\"ret%s\\n\", opcode & 0x10 ? \"i\" : \"\");\n" +"TRACE_JUMP();\n" +"STACK_FRAME_POP();\n" +); + } break; + case 0x95c8: { // LPM -- Load Program Memory R0 <- (Z) -- 1001 0101 1100 1000 +jit_generate(opcode, "uint16_t z = avr_data[R_ZL] | (avr_data[R_ZH] << 8);\n" +"STATE(\"lpm %s, (Z[%04x]) = %02x\\n\", avr_regname(0), z, avr_flash[z]);\n" +"cycle += 2; // 3 cycles\n" +"_avr_set_r(avr, 0, avr_flash[z]);\n" +); + } break; + case 0x95d8: { // ELPM -- Load Program Memory R0 <- (Z) -- 1001 0101 1101 1000 + if (!avr_rampz) + _avr_invalid_opcode(avr); + { +jit_generate(opcode, "uint32_t z = avr_data[R_ZL] | (avr_data[R_ZH] << 8) | (avr_data[avr_rampz] << 16);\n" +"STATE(\"elpm %s, (Z[%02x:%04x])\\n\", avr_regname(0), z >> 16, z & 0xffff);\n" +"_avr_set_r(avr, 0, avr_flash[z]);\n" +"cycle += 2; // 3 cycles\n" +); + } break; + } break; + default: { + switch (opcode & 0xfe0f) { + case 0x9000: { // LDS -- Load Direct from Data Space, 32 bits -- 1001 0000 0000 0000 +jit_generate(opcode, "get_d5(opcode);\n" +"uint16_t x = _avr_flash_read16le(avr, new_pc);\n" +"new_pc += 2;\n" +"STATE(\"lds %s[%02x], 0x%04x\\n\", avr_regname(d), avr_data[d], x);\n" +"_avr_set_r(avr, d, _avr_get_ram(avr, x));\n" +"cycle++; // 2 cycles\n" +); + } break; + case 0x9005: + case 0x9004: { // LPM -- Load Program Memory -- 1001 000d dddd 01oo +jit_generate(opcode, "get_d5(opcode);\n" +"uint16_t z = avr_data[R_ZL] | (avr_data[R_ZH] << 8);\n" +"int op = opcode & 1;\n" +"STATE(\"lpm %s, (Z[%04x]%s) = %02x\\n\", avr_regname(d), z, op ? \"+\" : \"\", avr_flash[z]);\n" +"_avr_set_r(avr, d, avr_flash[z]);\n" +"if (op)\n" +"_avr_set_r16le_hl(avr, R_ZL, z + 1);\n" +"cycle += 2; // 3 cycles\n" +); + } break; + case 0x9006: + case 0x9007: { // ELPM -- Extended Load Program Memory -- 1001 000d dddd 01oo + if (!avr_rampz) + _avr_invalid_opcode(avr); + { +jit_generate(opcode, "uint32_t z = avr_data[R_ZL] | (avr_data[R_ZH] << 8) | (avr_data[avr_rampz] << 16);\n" +"get_d5(opcode);\n" +"int op = opcode & 1;\n" +"STATE(\"elpm %s, (Z[%02x:%04x]%s)\\n\", avr_regname(d), z >> 16, z & 0xffff, op ? \"+\" : \"\");\n" +"_avr_set_r(avr, d, avr_flash[z]);\n" +"if (op) {\n" +"z++;\n" +"_avr_set_r(avr, avr_rampz, z >> 16);\n" +"_avr_set_r16le_hl(avr, R_ZL, z);\n" +"}\n" +"cycle += 2; // 3 cycles\n" +); + } break; + } break; + /* + * Load store instructions + * + * 1001 00sr rrrr iioo + * s = 0 = load, 1 = store + * ii = 16 bits register index, 11 = X, 10 = Y, 00 = Z + * oo = 1) post increment, 2) pre-decrement + */ + case 0x900c: + case 0x900d: + case 0x900e: { // LD -- Load Indirect from Data using X -- 1001 000d dddd 11oo +jit_generate(opcode, "int op = opcode & 3;\n" +"get_d5(opcode);\n" +"uint16_t x = (avr_data[R_XH] << 8) | avr_data[R_XL];\n" +"STATE(\"ld %s, %sX[%04x]%s\\n\", avr_regname(d), op == 2 ? \"--\" : \"\", x, op == 1 ? \"++\" : \"\");\n" +"cycle++; // 2 cycles (1 for tinyavr, except with inc/dec 2)\n" +"if (op == 2) x--;\n" +"uint8_t vd = _avr_get_ram(avr, x);\n" +"if (op == 1) x++;\n" +"_avr_set_r16le_hl(avr, R_XL, x);\n" +"_avr_set_r(avr, d, vd);\n" +); + } break; + case 0x920c: + case 0x920d: + case 0x920e: { // ST -- Store Indirect Data Space X -- 1001 001d dddd 11oo +jit_generate(opcode, "int op = opcode & 3;\n" +"get_vd5(opcode);\n" +"uint16_t x = (avr_data[R_XH] << 8) | avr_data[R_XL];\n" +"STATE(\"st %sX[%04x]%s, %s[%02x] \\n\", op == 2 ? \"--\" : \"\", x, op == 1 ? \"++\" : \"\", avr_regname(d), vd);\n" +"cycle++; // 2 cycles, except tinyavr\n" +"if (op == 2) x--;\n" +"_avr_set_ram(avr, x, vd);\n" +"if (op == 1) x++;\n" +"_avr_set_r16le_hl(avr, R_XL, x);\n" +); + } break; + case 0x9009: + case 0x900a: { // LD -- Load Indirect from Data using Y -- 1001 000d dddd 10oo +jit_generate(opcode, "int op = opcode & 3;\n" +"get_d5(opcode);\n" +"uint16_t y = (avr_data[R_YH] << 8) | avr_data[R_YL];\n" +"STATE(\"ld %s, %sY[%04x]%s\\n\", avr_regname(d), op == 2 ? \"--\" : \"\", y, op == 1 ? \"++\" : \"\");\n" +"cycle++; // 2 cycles, except tinyavr\n" +"if (op == 2) y--;\n" +"uint8_t vd = _avr_get_ram(avr, y);\n" +"if (op == 1) y++;\n" +"_avr_set_r16le_hl(avr, R_YL, y);\n" +"_avr_set_r(avr, d, vd);\n" +); + } break; + case 0x9209: + case 0x920a: { // ST -- Store Indirect Data Space Y -- 1001 001d dddd 10oo +jit_generate(opcode, "int op = opcode & 3;\n" +"get_vd5(opcode);\n" +"uint16_t y = (avr_data[R_YH] << 8) | avr_data[R_YL];\n" +"STATE(\"st %sY[%04x]%s, %s[%02x]\\n\", op == 2 ? \"--\" : \"\", y, op == 1 ? \"++\" : \"\", avr_regname(d), vd);\n" +"cycle++;\n" +"if (op == 2) y--;\n" +"_avr_set_ram(avr, y, vd);\n" +"if (op == 1) y++;\n" +"_avr_set_r16le_hl(avr, R_YL, y);\n" +); + } break; + case 0x9200: { // STS -- Store Direct to Data Space, 32 bits -- 1001 0010 0000 0000 +jit_generate(opcode, "get_vd5(opcode);\n" +"uint16_t x = _avr_flash_read16le(avr, new_pc);\n" +"new_pc += 2;\n" +"STATE(\"sts 0x%04x, %s[%02x]\\n\", x, avr_regname(d), vd);\n" +"cycle++;\n" +"_avr_set_ram(avr, x, vd);\n" +); + } break; + case 0x9001: + case 0x9002: { // LD -- Load Indirect from Data using Z -- 1001 000d dddd 00oo +jit_generate(opcode, "int op = opcode & 3;\n" +"get_d5(opcode);\n" +"uint16_t z = (avr_data[R_ZH] << 8) | avr_data[R_ZL];\n" +"STATE(\"ld %s, %sZ[%04x]%s\\n\", avr_regname(d), op == 2 ? \"--\" : \"\", z, op == 1 ? \"++\" : \"\");\n" +"cycle++;; // 2 cycles, except tinyavr\n" +"if (op == 2) z--;\n" +"uint8_t vd = _avr_get_ram(avr, z);\n" +"if (op == 1) z++;\n" +"_avr_set_r16le_hl(avr, R_ZL, z);\n" +"_avr_set_r(avr, d, vd);\n" +); + } break; + case 0x9201: + case 0x9202: { // ST -- Store Indirect Data Space Z -- 1001 001d dddd 00oo +jit_generate(opcode, "int op = opcode & 3;\n" +"get_vd5(opcode);\n" +"uint16_t z = (avr_data[R_ZH] << 8) | avr_data[R_ZL];\n" +"STATE(\"st %sZ[%04x]%s, %s[%02x] \\n\", op == 2 ? \"--\" : \"\", z, op == 1 ? \"++\" : \"\", avr_regname(d), vd);\n" +"cycle++; // 2 cycles, except tinyavr\n" +"if (op == 2) z--;\n" +"_avr_set_ram(avr, z, vd);\n" +"if (op == 1) z++;\n" +"_avr_set_r16le_hl(avr, R_ZL, z);\n" +); + } break; + case 0x900f: { // POP -- 1001 000d dddd 1111 +jit_generate(opcode, "get_d5(opcode);\n" +"_avr_set_r(avr, d, _avr_pop8(avr));\n" +"T(uint16_t sp = _avr_sp_get(avr);)\n" +"STATE(\"pop %s (@%04x)[%02x]\\n\", avr_regname(d), sp, avr_data[sp]);\n" +"cycle++;\n" +); + } break; + case 0x920f: { // PUSH -- 1001 001d dddd 1111 +jit_generate(opcode, "get_vd5(opcode);\n" +"_avr_push8(avr, vd);\n" +"T(uint16_t sp = _avr_sp_get(avr);)\n" +"STATE(\"push %s[%02x] (@%04x)\\n\", avr_regname(d), vd, sp);\n" +"cycle++;\n" +); + } break; + case 0x9400: { // COM -- One's Complement -- 1001 010d dddd 0000 +jit_generate(opcode, "get_vd5(opcode);\n" +"uint8_t res = 0xff - vd;\n" +"STATE(\"com %s[%02x] = %02x\\n\", avr_regname(d), vd, res);\n" +"_avr_set_r(avr, d, res);\n" +"_avr_flags_znv0s(avr, res);\n" +"SREG_SETBIT(S_C, 1);\n" +"SREG();\n" +); + } break; + case 0x9401: { // NEG -- Two's Complement -- 1001 010d dddd 0001 +jit_generate(opcode, "get_vd5(opcode);\n" +"uint8_t res = 0x00 - vd;\n" +"STATE(\"neg %s[%02x] = %02x\\n\", avr_regname(d), vd, res);\n" +"_avr_set_r(avr, d, res);\n" +"SREG_SETBIT(S_H, ((res >> 3) | (vd >> 3)) & 1);\n" +"SREG_SETBIT(S_V, res == 0x80);\n" +"SREG_SETBIT(S_C, res != 0);\n" +"_avr_flags_zns(avr, res);\n" +"SREG();\n" +); + } break; + case 0x9402: { // SWAP -- Swap Nibbles -- 1001 010d dddd 0010 +jit_generate(opcode, "get_vd5(opcode);\n" +"uint8_t res = (vd >> 4) | (vd << 4) ;\n" +"STATE(\"swap %s[%02x] = %02x\\n\", avr_regname(d), vd, res);\n" +"_avr_set_r(avr, d, res);\n" +); + } break; + case 0x9403: { // INC -- Increment -- 1001 010d dddd 0011 +jit_generate(opcode, "get_vd5(opcode);\n" +"uint8_t res = vd + 1;\n" +"STATE(\"inc %s[%02x] = %02x\\n\", avr_regname(d), vd, res);\n" +"_avr_set_r(avr, d, res);\n" +"SREG_SETBIT(S_V, res == 0x80);\n" +"_avr_flags_zns(avr, res);\n" +"SREG();\n" +); + } break; + case 0x9405: { // ASR -- Arithmetic Shift Right -- 1001 010d dddd 0101 +jit_generate(opcode, "get_vd5(opcode);\n" +"uint8_t res = (vd >> 1) | (vd & 0x80);\n" +"STATE(\"asr %s[%02x]\\n\", avr_regname(d), vd);\n" +"_avr_set_r(avr, d, res);\n" +"_avr_flags_zcnvs(avr, res, vd);\n" +"SREG();\n" +); + } break; + case 0x9406: { // LSR -- Logical Shift Right -- 1001 010d dddd 0110 +jit_generate(opcode, "get_vd5(opcode);\n" +"uint8_t res = vd >> 1;\n" +"STATE(\"lsr %s[%02x]\\n\", avr_regname(d), vd);\n" +"_avr_set_r(avr, d, res);\n" +"SREG_SETBIT(S_N, 0);\n" +"_avr_flags_zcvs(avr, res, vd);\n" +"SREG();\n" +); + } break; + case 0x9407: { // ROR -- Rotate Right -- 1001 010d dddd 0111 +jit_generate(opcode, "get_vd5(opcode);\n" +"uint8_t res = (SREG_BIT(S_C) ? 0x80 : 0) | vd >> 1;\n" +"STATE(\"ror %s[%02x]\\n\", avr_regname(d), vd);\n" +"_avr_set_r(avr, d, res);\n" +"_avr_flags_zcnvs(avr, res, vd);\n" +"SREG();\n" +); + } break; + case 0x940a: { // DEC -- Decrement -- 1001 010d dddd 1010 +jit_generate(opcode, "get_vd5(opcode);\n" +"uint8_t res = vd - 1;\n" +"STATE(\"dec %s[%02x] = %02x\\n\", avr_regname(d), vd, res);\n" +"_avr_set_r(avr, d, res);\n" +"SREG_SETBIT(S_V, res == 0x7f);\n" +"_avr_flags_zns(avr, res);\n" +"SREG();\n" +); + } break; + case 0x940c: + case 0x940d: { // JMP -- Long Call to sub, 32 bits -- 1001 010a aaaa 110a +jit_generate(opcode, "avr_flashaddr_t a = ((opcode & 0x01f0) >> 3) | (opcode & 1);\n" +"uint16_t x = _avr_flash_read16le(avr, new_pc);\n" +"a = (a << 16) | x;\n" +"STATE(\"jmp 0x%06x\\n\", a);\n" +"new_pc = a << 1;\n" +"cycle += 2;\n" +"TRACE_JUMP();\n" +); + } break; + case 0x940e: + case 0x940f: { // CALL -- Long Call to sub, 32 bits -- 1001 010a aaaa 111a +jit_generate(opcode, "avr_flashaddr_t a = ((opcode & 0x01f0) >> 3) | (opcode & 1);\n" +"uint16_t x = _avr_flash_read16le(avr, new_pc);\n" +"a = (a << 16) | x;\n" +"STATE(\"call 0x%06x\\n\", a);\n" +"new_pc += 2;\n" +"cycle += 1 + _avr_push_addr(avr, new_pc);\n" +"new_pc = a << 1;\n" +"TRACE_JUMP();\n" +"STACK_FRAME_PUSH();\n" +); + } break; + + default: { + switch (opcode & 0xff00) { + case 0x9600: { // ADIW -- Add Immediate to Word -- 1001 0110 KKpp KKKK +jit_generate(opcode, "get_vp2_k6(opcode);\n" +"uint16_t res = vp + k;\n" +"STATE(\"adiw %s:%s[%04x], 0x%02x\\n\", avr_regname(p), avr_regname(p + 1), vp, k);\n" +"_avr_set_r16le_hl(avr, p, res);\n" +"SREG_SETBIT(S_V, ((~vp & res) >> 15) & 1);\n" +"SREG_SETBIT(S_C, ((~res & vp) >> 15) & 1);\n" +"_avr_flags_zns16(avr, res);\n" +"SREG();\n" +"cycle++;\n" +); + } break; + case 0x9700: { // SBIW -- Subtract Immediate from Word -- 1001 0111 KKpp KKKK +jit_generate(opcode, "get_vp2_k6(opcode);\n" +"uint16_t res = vp - k;\n" +"STATE(\"sbiw %s:%s[%04x], 0x%02x\\n\", avr_regname(p), avr_regname(p + 1), vp, k);\n" +"_avr_set_r16le_hl(avr, p, res);\n" +"SREG_SETBIT(S_V, ((vp & ~res) >> 15) & 1);\n" +"SREG_SETBIT(S_C, ((res & ~vp) >> 15) & 1);\n" +"_avr_flags_zns16(avr, res);\n" +"SREG();\n" +"cycle++;\n" +); + } break; + case 0x9800: { // CBI -- Clear Bit in I/O Register -- 1001 1000 AAAA Abbb +jit_generate(opcode, "get_io5_b3mask(opcode);\n" +"uint8_t res = _avr_get_ram(avr, io) & ~mask;\n" +"STATE(\"cbi %s[%04x], 0x%02x = %02x\\n\", avr_regname(io), avr_data[io], mask, res);\n" +"_avr_set_ram(avr, io, res);\n" +"cycle++;\n" +); + } break; + case 0x9900: { + const int skip = 1 + _avr_is_instruction_32_bits(avr, new_pc); + { // SBIC -- Skip if Bit in I/O Register is Cleared -- 1001 1001 AAAA Abbb + jit_generate_literal("const int skip = %d", skip); +jit_generate(opcode, "get_io5_b3mask(opcode);\n" +"uint8_t res = _avr_get_ram(avr, io) & mask;\n" +"STATE(\"sbic %s[%04x], 0x%02x\\t; Will%s branch\\n\", avr_regname(io), avr_data[io], mask, !res?\"\":\" not\");\n" +"if (!res) {\n" +"new_pc += 2 * skip; cycle += skip;\n" +"TRACE_JUMP();\n" +"}\n" +); + } break; + } break; + case 0x9a00: { // SBI -- Set Bit in I/O Register -- 1001 1010 AAAA Abbb +jit_generate(opcode, "get_io5_b3mask(opcode);\n" +"uint8_t res = _avr_get_ram(avr, io) | mask;\n" +"STATE(\"sbi %s[%04x], 0x%02x = %02x\\n\", avr_regname(io), avr_data[io], mask, res);\n" +"_avr_set_ram(avr, io, res);\n" +"cycle++;\n" +); + } break; + case 0x9b00: { + const int skip = 1 + _avr_is_instruction_32_bits(avr, new_pc); + { // SBIS -- Skip if Bit in I/O Register is Set -- 1001 1011 AAAA Abbb + jit_generate_literal("const int skip = %d", skip); +jit_generate(opcode, "get_io5_b3mask(opcode);\n" +"uint8_t res = _avr_get_ram(avr, io) & mask;\n" +"STATE(\"sbis %s[%04x], 0x%02x\\t; Will%s branch\\n\", avr_regname(io), avr_data[io], mask, res?\"\":\" not\");\n" +"if (res) {\n" +"new_pc += 2 * skip; cycle += skip;\n" +"TRACE_JUMP();\n" +"}\n" +); + } break; + } break; + default: + switch (opcode & 0xfc00) { + case 0x9c00: { // MUL -- Multiply Unsigned -- 1001 11rd dddd rrrr +jit_generate(opcode, "get_vd5_vr5(opcode);\n" +"uint16_t res = vd * vr;\n" +"STATE(\"mul %s[%02x], %s[%02x] = %04x\\n\", avr_regname(d), vd, avr_regname(r), vr, res);\n" +"cycle++;\n" +"_avr_set_r16le(avr, 0, res);\n" +"SREG_SETBIT(S_Z, res == 0);\n" +"SREG_SETBIT(S_C, (res >> 15) & 1);\n" +"SREG();\n" +); + } break; + default: _avr_invalid_opcode(avr); + } + } + } break; + } + } break; + } + } break; + + case 0xb000: { + switch (opcode & 0xf800) { + case 0xb800: { // OUT A,Rr -- 1011 1AAd dddd AAAA +jit_generate(opcode, "get_d5_a6(opcode);\n" +"STATE(\"out %s, %s[%02x]\\n\", avr_regname(A), avr_regname(d), avr_data[d]);\n" +"_avr_set_ram(avr, A, avr_data[d]);\n" +); + } break; + case 0xb000: { // IN Rd,A -- 1011 0AAd dddd AAAA +jit_generate(opcode, "get_d5_a6(opcode);\n" +"STATE(\"in %s, %s[%02x]\\n\", avr_regname(d), avr_regname(A), avr_data[A]);\n" +"_avr_set_r(avr, d, _avr_get_ram(avr, A));\n" +); + } break; + default: _avr_invalid_opcode(avr); + } + } break; + + case 0xc000: { // RJMP -- 1100 kkkk kkkk kkkk +jit_generate(opcode, "get_o12(opcode);\n" +"STATE(\"rjmp .%d [%04x]\\n\", o >> 1, new_pc + o);\n" +"new_pc = (new_pc + o) % (avr_flashend + 1);\n" +"cycle++;\n" +"TRACE_JUMP();\n" +); + } break; + + case 0xd000: { // RCALL -- 1101 kkkk kkkk kkkk +jit_generate(opcode, "get_o12(opcode);\n" +"STATE(\"rcall .%d [%04x]\\n\", o >> 1, new_pc + o);\n" +"cycle += _avr_push_addr(avr, new_pc);\n" +"new_pc = (new_pc + o) % (avr_flashend + 1);\n" +"// 'rcall .1' is used as a cheap \"push 16 bits of room on the stack\"\n" +"if (o != 0) {\n" +"TRACE_JUMP();\n" +"STACK_FRAME_PUSH();\n" +"}\n" +); + } break; + + case 0xe000: { // LDI Rd, K aka SER (LDI r, 0xff) -- 1110 kkkk dddd kkkk +jit_generate(opcode, "get_h4_k8(opcode);\n" +"STATE(\"ldi %s, 0x%02x\\n\", avr_regname(h), k);\n" +"_avr_set_r(avr, h, k);\n" +); + } break; + + case 0xf000: { + switch (opcode & 0xfe00) { + case 0xf000: + case 0xf200: + case 0xf400: + case 0xf600: { // BRXC/BRXS -- All the SREG branches -- 1111 0Boo oooo osss +jit_generate(opcode, "int16_t o = ((int16_t)(opcode << 6)) >> 9; // offset\n" +"uint8_t s = opcode & 7;\n" +"int set = (opcode & 0x0400) == 0; // this bit means BRXC otherwise BRXS\n" +"int branch = (SREG_BIT(s) && set) || (!SREG_BIT(s) && !set);\n" +"#ifdef CONFIG_SIMAVR_TRACE\n" +"if (brxc_names[set][s]) {\n" +"STATE(\"%s .%d [%04x]\\t; Will%s branch\\n\", brxc_names[set][s], o, new_pc + (o << 1), branch ? \"\":\" not\");\n" +"} else {\n" +"STATE(\"%s%c .%d [%04x]\\t; Will%s branch\\n\", set ? \"brbs\" : \"brbc\", _sreg_bit_name[s], o, new_pc + (o << 1), branch ? \"\":\" not\");\n" +"}\n" +"#endif\n" +"if (branch) {\n" +"cycle++; // 2 cycles if taken, 1 otherwise\n" +"new_pc = new_pc + (o << 1);\n" +"TRACE_JUMP();\n" +"}\n" +); + } break; + case 0xf800: + case 0xf900: { // BLD -- Bit Store from T into a Bit in Register -- 1111 100d dddd 0bbb +jit_generate(opcode, "get_vd5_s3_mask(opcode);\n" +"uint8_t v = (vd & ~mask) | (SREG_BIT(S_T) ? mask : 0);\n" +"STATE(\"bld %s[%02x], 0x%02x = %02x\\n\", avr_regname(d), vd, mask, v);\n" +"_avr_set_r(avr, d, v);\n" +); + } break; + case 0xfa00: + case 0xfb00: { // BST -- Bit Store into T from bit in Register -- 1111 101d dddd 0bbb +jit_generate(opcode, "get_vd5_s3(opcode);\n" +"STATE(\"bst %s[%02x], 0x%02x\\n\", avr_regname(d), vd, 1 << s);\n" +"SREG_SETBIT(S_T, (vd >> s) & 1);\n" +"SREG();\n" +); + } break; + case 0xfc00: + case 0xfe00: { + const int skip = 1 + _avr_is_instruction_32_bits(avr, new_pc); + { // SBRS/SBRC -- Skip if Bit in Register is Set/Clear -- 1111 11sd dddd 0bbb + jit_generate_literal("const int skip = %d", skip); +jit_generate(opcode, "get_vd5_s3_mask(opcode);\n" +"int set = (opcode & 0x0200) != 0;\n" +"int branch = ((vd & mask) && set) || (!(vd & mask) && !set);\n" +"STATE(\"%s %s[%02x], 0x%02x\\t; Will%s branch\\n\", set ? \"sbrs\" : \"sbrc\", avr_regname(d), vd, mask, branch ? \"\":\" not\");\n" +"if (branch) {\n" +"new_pc += 2 * skip; cycle += skip;\n" +"TRACE_JUMP();\n" +"}\n" +); + } break; + } break; + default: _avr_invalid_opcode(avr); + } + } break; + + default: _avr_invalid_opcode(avr); + + } +#endif /*__SIM_CORE_JIT_H__*/