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
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
( 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
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
--- /dev/null
+#!/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
--- /dev/null
+
+/*
+ * 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;
+}
#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 <libtcc.h>
+#endif
+
static void
display_usage(
const char * app)
{
- printf("Usage: %s [...] <firmware>\n", app);
- printf( " [--freq|-f <freq>] Sets the frequency for an .hex firmware\n"
- " [--mcu|-m <device>] 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 <vector>] Add traces for IRQ vector <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 <file>] A .vcd file to use as input signals\n"
- " [-v] Raise verbosity level\n"
- " (can be passed more than once)\n"
- " <firmware> 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 <device>] [-f <frequency>] 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 <vector> Add trace vector at <vector>\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++)
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,
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]));
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));
exit(1);
}
}
+ } else {
+ fprintf(stderr, "%s invalid option '%s'\n", argv[0], argv[pi]);
+ exit(1);
}
}
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)
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
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
/*
* 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
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
*/
#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)))
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);
#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);
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
* 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);
/*
* 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);
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;
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
*/
#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
o == 0x940f; // CALL Long Call to sub
}
+#define emit
+#define end_emit break
+#define emit_literal(...)
+#define emit_literal_flush()
+
/*
* Main opcode decoder
*
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) {
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) {
_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;
SREG_SETBIT(S_C, c);
SREG_SETBIT(S_Z, res == 0);
SREG();
- } break;
+ } end_emit;
default: _avr_invalid_opcode(avr);
}
}
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) {
_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) {
_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) {
_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: {
*/
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) {
_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) {
_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;
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
*/
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];
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];
_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];
_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];
_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;
_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];
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];
_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);
_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);
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);
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);
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);
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;
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;
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);
_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);
_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);
SREG_SETBIT(S_Z, res == 0);
SREG_SETBIT(S_C, (res >> 15) & 1);
SREG();
- } break;
+ } end_emit;
default: _avr_invalid_opcode(avr);
}
}
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) {
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);
}
default: _avr_invalid_opcode(avr);
}
+ // JIT_EXTRACT_END <-- don't change this line
+
avr->cycle += cycle;
SREG_END(avr);
--- /dev/null
+/*
+ sim_core_jit.c
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+ */
+
+#define _GNU_SOURCE /* for asprintf */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#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);
+ }
+}
+
+
--- /dev/null
+/* 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__*/