aboutsummaryrefslogtreecommitdiff
path: root/sim/avr/interp.c
diff options
context:
space:
mode:
authorTristan Gingold <gingold@adacore.com>2009-04-27 10:50:53 +0000
committerTristan Gingold <gingold@adacore.com>2009-04-27 10:50:53 +0000
commitdf1756f414a26ac33aa2d0dbe6d757e214e45419 (patch)
tree4a6e03df3637cb5a7914a620417dbd8c22f8a619 /sim/avr/interp.c
parent57a460012a55aec007ee5ea2f229f79699cfd01a (diff)
downloadbinutils-df1756f414a26ac33aa2d0dbe6d757e214e45419.zip
binutils-df1756f414a26ac33aa2d0dbe6d757e214e45419.tar.gz
binutils-df1756f414a26ac33aa2d0dbe6d757e214e45419.tar.bz2
2009-04-27 Tristan Gingold <gingold@adacore.com>
* avr: New directory. * avr/interp.c, avr/Makefile.in, avr/configure.ac: New files. * avr/config.in: New file, generated by autoheader. * avr/configure: New file generated by autoconf. * configure.ac: Add avr. * configure: Regenerated.
Diffstat (limited to 'sim/avr/interp.c')
-rw-r--r--sim/avr/interp.c1847
1 files changed, 1847 insertions, 0 deletions
diff --git a/sim/avr/interp.c b/sim/avr/interp.c
new file mode 100644
index 0000000..e4e80c3
--- /dev/null
+++ b/sim/avr/interp.c
@@ -0,0 +1,1847 @@
+/* Simulator for Atmel's AVR core.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+ Written by Tristan Gingold, AdaCore.
+
+ This file is part of GDB, the GNU debugger.
+
+ This program 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.
+
+ This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "bfd.h"
+#include "gdb/callback.h"
+#include "gdb/signals.h"
+#include "libiberty.h"
+#include "gdb/remote-sim.h"
+#include "dis-asm.h"
+#include "sim-utils.h"
+
+/* As AVR is a 8/16 bits processor, define handy types. */
+typedef unsigned short int word;
+typedef signed short int sword;
+typedef unsigned char byte;
+typedef signed char sbyte;
+
+/* Debug flag to display instructions and registers. */
+static int tracing = 0;
+static int lock_step = 0;
+static int verbose;
+
+/* The only real register. */
+static unsigned int pc;
+
+/* We update a cycle counter. */
+static unsigned int cycles = 0;
+
+/* If true, the pc needs more than 2 bytes. */
+static int avr_pc22;
+
+static struct bfd *cur_bfd;
+
+static enum sim_stop cpu_exception;
+static int cpu_signal;
+
+static SIM_OPEN_KIND sim_kind;
+static char *myname;
+static host_callback *callback;
+
+/* Max size of I space (which is always flash on avr). */
+#define MAX_AVR_FLASH (128 * 1024)
+#define PC_MASK (MAX_AVR_FLASH - 1)
+
+/* Mac size of D space. */
+#define MAX_AVR_SRAM (64 * 1024)
+#define SRAM_MASK (MAX_AVR_SRAM - 1)
+
+/* D space offset in ELF file. */
+#define SRAM_VADDR 0x800000
+
+/* Simulator specific ports. */
+#define STDIO_PORT 0x52
+#define EXIT_PORT 0x4F
+#define ABORT_PORT 0x49
+
+/* GDB defined register numbers. */
+#define AVR_SREG_REGNUM 32
+#define AVR_SP_REGNUM 33
+#define AVR_PC_REGNUM 34
+
+/* Memory mapped registers. */
+#define SREG 0x5F
+#define REG_SP 0x5D
+#define EIND 0x5C
+#define RAMPZ 0x5B
+
+#define REGX 0x1a
+#define REGY 0x1c
+#define REGZ 0x1e
+#define REGZ_LO 0x1e
+#define REGZ_HI 0x1f
+
+/* Sreg (status) bits. */
+#define SREG_I 0x80
+#define SREG_T 0x40
+#define SREG_H 0x20
+#define SREG_S 0x10
+#define SREG_V 0x08
+#define SREG_N 0x04
+#define SREG_Z 0x02
+#define SREG_C 0x01
+
+/* In order to speed up emulation we use a simple approach:
+ a code is associated with each instruction. The pre-decoding occurs
+ usually once when the instruction is first seen.
+ This works well because I&D spaces are separated.
+
+ Missing opcodes: sleep, spm, wdr (as they are mmcu dependent).
+*/
+enum avr_opcode
+ {
+ /* Opcode not yet decoded. */
+ OP_unknown,
+ OP_bad,
+
+ OP_nop,
+
+ OP_rjmp,
+ OP_rcall,
+ OP_ret,
+ OP_reti,
+
+ OP_break,
+
+ OP_brbs,
+ OP_brbc,
+
+ OP_bset,
+ OP_bclr,
+
+ OP_bld,
+ OP_bst,
+
+ OP_sbrc,
+ OP_sbrs,
+
+ OP_eor,
+ OP_and,
+ OP_andi,
+ OP_or,
+ OP_ori,
+ OP_com,
+ OP_swap,
+ OP_neg,
+
+ OP_out,
+ OP_in,
+ OP_cbi,
+ OP_sbi,
+
+ OP_sbic,
+ OP_sbis,
+
+ OP_ldi,
+ OP_cpse,
+ OP_cp,
+ OP_cpi,
+ OP_cpc,
+ OP_sub,
+ OP_sbc,
+ OP_sbiw,
+ OP_adiw,
+ OP_add,
+ OP_adc,
+ OP_subi,
+ OP_sbci,
+ OP_inc,
+ OP_dec,
+ OP_lsr,
+ OP_ror,
+ OP_asr,
+
+ OP_mul,
+ OP_muls,
+ OP_mulsu,
+ OP_fmul,
+ OP_fmuls,
+ OP_fmulsu,
+
+ OP_mov,
+ OP_movw,
+
+ OP_push,
+ OP_pop,
+
+ OP_st_X,
+ OP_st_dec_X,
+ OP_st_X_inc,
+ OP_st_Y_inc,
+ OP_st_dec_Y,
+ OP_st_Z_inc,
+ OP_st_dec_Z,
+ OP_std_Y,
+ OP_std_Z,
+ OP_ldd_Y,
+ OP_ldd_Z,
+ OP_ld_Z_inc,
+ OP_ld_dec_Z,
+ OP_ld_Y_inc,
+ OP_ld_dec_Y,
+ OP_ld_X,
+ OP_ld_X_inc,
+ OP_ld_dec_X,
+
+ OP_lpm,
+ OP_lpm_Z,
+ OP_lpm_inc_Z,
+ OP_elpm,
+ OP_elpm_Z,
+ OP_elpm_inc_Z,
+
+ OP_ijmp,
+ OP_icall,
+
+ OP_eijmp,
+ OP_eicall,
+
+ /* 2 words opcodes. */
+#define OP_2words OP_jmp
+ OP_jmp,
+ OP_call,
+ OP_sts,
+ OP_lds
+ };
+
+struct avr_insn_cell
+{
+ /* The insn (16 bits). */
+ word op;
+
+ /* Pre-decoding code. */
+ enum avr_opcode code : 8;
+ /* One byte of additional information. */
+ byte r;
+};
+
+/* I&D memories. */
+static struct avr_insn_cell flash[MAX_AVR_FLASH];
+static byte sram[MAX_AVR_SRAM];
+
+void
+sim_size (int s)
+{
+}
+
+/* Sign extend a value. */
+static int sign_ext (word val, int nb_bits)
+{
+ if (val & (1 << (nb_bits - 1)))
+ return val | (-1 << nb_bits);
+ return val;
+}
+
+/* Insn field extractors. */
+
+/* Extract xxxx_xxxRx_xxxx_RRRR. */
+static inline byte get_r (word op)
+{
+ return (op & 0xf) | ((op >> 5) & 0x10);
+}
+
+/* Extract xxxx_xxxxx_xxxx_RRRR. */
+static inline byte get_r16 (word op)
+{
+ return 16 + (op & 0xf);
+}
+
+/* Extract xxxx_xxxxx_xxxx_xRRR. */
+static inline byte get_r16_23 (word op)
+{
+ return 16 + (op & 0x7);
+}
+
+/* Extract xxxx_xxxD_DDDD_xxxx. */
+static inline byte get_d (word op)
+{
+ return (op >> 4) & 0x1f;
+}
+
+/* Extract xxxx_xxxx_DDDD_xxxx. */
+static inline byte get_d16 (word op)
+{
+ return 16 + ((op >> 4) & 0x0f);
+}
+
+/* Extract xxxx_xxxx_xDDD_xxxx. */
+static inline byte get_d16_23 (word op)
+{
+ return 16 + ((op >> 4) & 0x07);
+}
+
+/* Extract xxxx_xAAx_xxxx_AAAA. */
+static inline byte get_A (word op)
+{
+ return (op & 0x0f) | ((op & 0x600) >> 5);
+}
+
+/* Extract xxxx_xxxx_AAAA_Axxx. */
+static inline byte get_biA (word op)
+{
+ return (op >> 3) & 0x1f;
+}
+
+/* Extract xxxx_KKKK_xxxx_KKKK. */
+static inline byte get_K (word op)
+{
+ return (op & 0xf) | ((op & 0xf00) >> 4);
+}
+
+/* Extract xxxx_xxKK_KKKK_Kxxx. */
+static inline int get_k (word op)
+{
+ return sign_ext ((op & 0x3f8) >> 3, 7);
+}
+
+/* Extract xxxx_xxxx_xxDD_xxxx. */
+static inline byte get_d24 (word op)
+{
+ return 24 + ((op >> 3) & 6);
+}
+
+/* Extract xxxx_xxxx_KKxx_KKKK. */
+static inline byte get_k6 (word op)
+{
+ return (op & 0xf) | ((op >> 2) & 0x30);
+}
+
+/* Extract xxQx_QQxx_xxxx_xQQQ. */
+static inline byte get_q (word op)
+{
+ return (op & 7) | ((op >> 7) & 0x18)| ((op >> 8) & 0x20);
+}
+
+/* Extract xxxx_xxxx_xxxx_xBBB. */
+static inline byte get_b (word op)
+{
+ return (op & 7);
+}
+
+/* AVR is little endian. */
+static inline word
+read_word (unsigned int addr)
+{
+ return sram[addr] | (sram[addr + 1] << 8);
+}
+
+static inline void
+write_word (unsigned int addr, word w)
+{
+ sram[addr] = w;
+ sram[addr + 1] = w >> 8;
+}
+
+static inline word
+read_word_post_inc (unsigned int addr)
+{
+ word v = read_word (addr);
+ write_word (addr, v + 1);
+ return v;
+}
+
+static inline word
+read_word_pre_dec (unsigned int addr)
+{
+ word v = read_word (addr) - 1;
+ write_word (addr, v);
+ return v;
+}
+
+static void
+update_flags_logic (byte res)
+{
+ sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z);
+ if (res == 0)
+ sram[SREG] |= SREG_Z;
+ if (res & 0x80)
+ sram[SREG] |= SREG_N | SREG_S;
+}
+
+static void
+update_flags_add (byte r, byte a, byte b)
+{
+ byte carry;
+
+ sram[SREG] &= ~(SREG_H | SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+ if (r & 0x80)
+ sram[SREG] |= SREG_N;
+ carry = (a & b) | (a & ~r) | (b & ~r);
+ if (carry & 0x08)
+ sram[SREG] |= SREG_H;
+ if (carry & 0x80)
+ sram[SREG] |= SREG_C;
+ if (((a & b & ~r) | (~a & ~b & r)) & 0x80)
+ sram[SREG] |= SREG_V;
+ if (!(sram[SREG] & SREG_N) ^ !(sram[SREG] & SREG_V))
+ sram[SREG] |= SREG_S;
+ if (r == 0)
+ sram[SREG] |= SREG_Z;
+}
+
+static void update_flags_sub (byte r, byte a, byte b)
+{
+ byte carry;
+
+ sram[SREG] &= ~(SREG_H | SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+ if (r & 0x80)
+ sram[SREG] |= SREG_N;
+ carry = (~a & b) | (b & r) | (r & ~a);
+ if (carry & 0x08)
+ sram[SREG] |= SREG_H;
+ if (carry & 0x80)
+ sram[SREG] |= SREG_C;
+ if (((a & ~b & ~r) | (~a & b & r)) & 0x80)
+ sram[SREG] |= SREG_V;
+ if (!(sram[SREG] & SREG_N) ^ !(sram[SREG] & SREG_V))
+ sram[SREG] |= SREG_S;
+ /* Note: Z is not set. */
+}
+
+static enum avr_opcode
+decode (unsigned int pc)
+{
+ word op1 = flash[pc].op;
+
+ switch ((op1 >> 12) & 0x0f)
+ {
+ case 0x0:
+ switch ((op1 >> 10) & 0x3)
+ {
+ case 0x0:
+ switch ((op1 >> 8) & 0x3)
+ {
+ case 0x0:
+ if (op1 == 0)
+ return OP_nop;
+ break;
+ case 0x1:
+ return OP_movw;
+ case 0x2:
+ return OP_muls;
+ case 0x3:
+ if (op1 & 0x80)
+ {
+ if (op1 & 0x08)
+ return OP_fmulsu;
+ else
+ return OP_fmuls;
+ }
+ else
+ {
+ if (op1 & 0x08)
+ return OP_fmul;
+ else
+ return OP_mulsu;
+ }
+ }
+ break;
+ case 0x1:
+ return OP_cpc;
+ case 0x2:
+ flash[pc].r = SREG_C;
+ return OP_sbc;
+ case 0x3:
+ flash[pc].r = 0;
+ return OP_add;
+ }
+ break;
+ case 0x1:
+ switch ((op1 >> 10) & 0x3)
+ {
+ case 0x0:
+ return OP_cpse;
+ case 0x1:
+ return OP_cp;
+ case 0x2:
+ flash[pc].r = 0;
+ return OP_sub;
+ case 0x3:
+ flash[pc].r = SREG_C;
+ return OP_adc;
+ }
+ break;
+ case 0x2:
+ switch ((op1 >> 10) & 0x3)
+ {
+ case 0x0:
+ return OP_and;
+ case 0x1:
+ return OP_eor;
+ case 0x2:
+ return OP_or;
+ case 0x3:
+ return OP_mov;
+ }
+ break;
+ case 0x3:
+ return OP_cpi;
+ case 0x4:
+ return OP_sbci;
+ case 0x5:
+ return OP_subi;
+ case 0x6:
+ return OP_ori;
+ case 0x7:
+ return OP_andi;
+ case 0x8:
+ case 0xa:
+ if (op1 & 0x0200)
+ {
+ if (op1 & 0x0008)
+ {
+ flash[pc].r = get_q (op1);
+ return OP_std_Y;
+ }
+ else
+ {
+ flash[pc].r = get_q (op1);
+ return OP_std_Z;
+ }
+ }
+ else
+ {
+ if (op1 & 0x0008)
+ {
+ flash[pc].r = get_q (op1);
+ return OP_ldd_Y;
+ }
+ else
+ {
+ flash[pc].r = get_q (op1);
+ return OP_ldd_Z;
+ }
+ }
+ break;
+ case 0x9: /* 9xxx */
+ switch ((op1 >> 8) & 0xf)
+ {
+ case 0x0:
+ case 0x1:
+ switch ((op1 >> 0) & 0xf)
+ {
+ case 0x0:
+ return OP_lds;
+ case 0x1:
+ return OP_ld_Z_inc;
+ case 0x2:
+ return OP_ld_dec_Z;
+ case 0x4:
+ return OP_lpm_Z;
+ case 0x5:
+ return OP_lpm_inc_Z;
+ case 0x6:
+ return OP_elpm_Z;
+ case 0x7:
+ return OP_elpm_inc_Z;
+ case 0x9:
+ return OP_ld_Y_inc;
+ case 0xa:
+ return OP_ld_dec_Y;
+ case 0xc:
+ return OP_ld_X;
+ case 0xd:
+ return OP_ld_X_inc;
+ case 0xe:
+ return OP_ld_dec_X;
+ case 0xf:
+ return OP_pop;
+ }
+ break;
+ case 0x2:
+ case 0x3:
+ switch ((op1 >> 0) & 0xf)
+ {
+ case 0x0:
+ return OP_sts;
+ case 0x1:
+ return OP_st_Z_inc;
+ case 0x2:
+ return OP_st_dec_Z;
+ case 0x9:
+ return OP_st_Y_inc;
+ case 0xa:
+ return OP_st_dec_Y;
+ case 0xc:
+ return OP_st_X;
+ case 0xd:
+ return OP_st_X_inc;
+ case 0xe:
+ return OP_st_dec_X;
+ case 0xf:
+ return OP_push;
+ }
+ break;
+ case 0x4:
+ case 0x5:
+ switch (op1 & 0xf)
+ {
+ case 0x0:
+ return OP_com;
+ case 0x1:
+ return OP_neg;
+ case 0x2:
+ return OP_swap;
+ case 0x3:
+ return OP_inc;
+ case 0x5:
+ flash[pc].r = 0x80;
+ return OP_asr;
+ case 0x6:
+ flash[pc].r = 0;
+ return OP_lsr;
+ case 0x7:
+ return OP_ror;
+ case 0x8: /* 9[45]x8 */
+ switch ((op1 >> 4) & 0x1f)
+ {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ return OP_bset;
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ return OP_bclr;
+ case 0x10:
+ return OP_ret;
+ case 0x11:
+ return OP_reti;
+ case 0x19:
+ return OP_break;
+ case 0x1c:
+ return OP_lpm;
+ case 0x1d:
+ return OP_elpm;
+ default:
+ break;
+ }
+ break;
+ case 0x9: /* 9[45]x9 */
+ switch ((op1 >> 4) & 0x1f)
+ {
+ case 0x00:
+ return OP_ijmp;
+ case 0x01:
+ return OP_eijmp;
+ case 0x10:
+ return OP_icall;
+ case 0x11:
+ return OP_eicall;
+ default:
+ break;
+ }
+ break;
+ case 0xa:
+ return OP_dec;
+ case 0xc:
+ case 0xd:
+ flash[pc].r = ((op1 & 0x1f0) >> 3) | (op1 & 1);
+ return OP_jmp;
+ case 0xe:
+ case 0xf:
+ flash[pc].r = ((op1 & 0x1f0) >> 3) | (op1 & 1);
+ return OP_call;
+ }
+ break;
+ case 0x6:
+ return OP_adiw;
+ case 0x7:
+ return OP_sbiw;
+ case 0x8:
+ return OP_cbi;
+ case 0x9:
+ return OP_sbic;
+ case 0xa:
+ return OP_sbi;
+ case 0xb:
+ return OP_sbis;
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ return OP_mul;
+ }
+ break;
+ case 0xb:
+ flash[pc].r = get_A (op1);
+ if (((op1 >> 11) & 1) == 0)
+ return OP_in;
+ else
+ return OP_out;
+ case 0xc:
+ return OP_rjmp;
+ case 0xd:
+ return OP_rcall;
+ case 0xe:
+ return OP_ldi;
+ case 0xf:
+ switch ((op1 >> 9) & 7)
+ {
+ case 0:
+ case 1:
+ flash[pc].r = 1 << (op1 & 7);
+ return OP_brbs;
+ case 2:
+ case 3:
+ flash[pc].r = 1 << (op1 & 7);
+ return OP_brbc;
+ case 4:
+ if ((op1 & 8) == 0)
+ {
+ flash[pc].r = 1 << (op1 & 7);
+ return OP_bld;
+ }
+ break;
+ case 5:
+ if ((op1 & 8) == 0)
+ {
+ flash[pc].r = 1 << (op1 & 7);
+ return OP_bst;
+ }
+ break;
+ case 6:
+ if ((op1 & 8) == 0)
+ {
+ flash[pc].r = 1 << (op1 & 7);
+ return OP_sbrc;
+ }
+ break;
+ case 7:
+ if ((op1 & 8) == 0)
+ {
+ flash[pc].r = 1 << (op1 & 7);
+ return OP_sbrs;
+ }
+ break;
+ }
+ }
+ sim_cb_eprintf (callback,
+ "Unhandled instruction at pc=0x%x, op=%04x\n", pc * 2, op1);
+ return OP_bad;
+}
+
+/* Disassemble an instruction. */
+
+static int
+disasm_read_memory (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
+ struct disassemble_info *info)
+{
+ int res;
+
+ res = sim_read (NULL, memaddr, myaddr, length);
+ if (res != length)
+ return -1;
+ return 0;
+}
+
+/* Memory error support for an opcodes disassembler. */
+
+static void
+disasm_perror_memory (int status, bfd_vma memaddr,
+ struct disassemble_info *info)
+{
+ if (status != -1)
+ /* Can't happen. */
+ info->fprintf_func (info->stream, "Unknown error %d.", status);
+ else
+ /* Actually, address between memaddr and memaddr + len was
+ out of bounds. */
+ info->fprintf_func (info->stream,
+ "Address 0x%x is out of bounds.",
+ (int) memaddr);
+}
+
+static void
+disassemble_insn (SIM_DESC sd, SIM_ADDR pc)
+{
+ struct disassemble_info disasm_info;
+ int len;
+ int i;
+
+ INIT_DISASSEMBLE_INFO (disasm_info, callback, sim_cb_eprintf);
+
+ disasm_info.arch = bfd_get_arch (cur_bfd);
+ disasm_info.mach = bfd_get_mach (cur_bfd);
+ disasm_info.endian = BFD_ENDIAN_LITTLE;
+ disasm_info.read_memory_func = disasm_read_memory;
+ disasm_info.memory_error_func = disasm_perror_memory;
+
+ len = print_insn_avr (pc << 1, &disasm_info);
+ len = len / 2;
+ for (i = 0; i < len; i++)
+ sim_cb_eprintf (callback, " %04x", flash[pc + i].op);
+}
+
+static void
+do_call (unsigned int npc)
+{
+ unsigned int sp = read_word (REG_SP);
+
+ /* Big endian! */
+ sram[sp--] = pc;
+ sram[sp--] = pc >> 8;
+ if (avr_pc22)
+ {
+ sram[sp--] = pc >> 16;
+ cycles++;
+ }
+ write_word (REG_SP, sp);
+ pc = npc & PC_MASK;
+ cycles += 3;
+}
+
+static int
+get_insn_length (unsigned int p)
+{
+ if (flash[p].code == OP_unknown)
+ flash[p].code = decode(p);
+ if (flash[p].code >= OP_2words)
+ return 2;
+ else
+ return 1;
+}
+
+static unsigned int
+get_z (void)
+{
+ return (sram[RAMPZ] << 16) | (sram[REGZ_HI] << 8) | sram[REGZ_LO];
+}
+
+static unsigned char
+get_lpm (unsigned int addr)
+{
+ word w;
+
+ w = flash[(addr >> 1) & PC_MASK].op;
+ if (addr & 1)
+ w >>= 8;
+ return w;
+}
+
+static void
+gen_mul (unsigned int res)
+{
+ write_word (0, res);
+ sram[SREG] &= ~(SREG_Z | SREG_C);
+ if (res == 0)
+ sram[SREG] |= SREG_Z;
+ if (res & 0x8000)
+ sram[SREG] |= SREG_C;
+ cycles++;
+}
+
+void
+sim_resume (SIM_DESC sd, int step, int signal)
+{
+ unsigned int ipc;
+
+ if (step)
+ {
+ cpu_exception = sim_stopped;
+ cpu_signal = TARGET_SIGNAL_TRAP;
+ }
+ else
+ cpu_exception = sim_running;
+
+ do
+ {
+ int code;
+ word op;
+ byte res;
+ byte r, d, vd;
+
+ again:
+ code = flash[pc].code;
+ op = flash[pc].op;
+
+
+ if ((tracing || lock_step) && code != OP_unknown)
+ {
+ if (verbose > 0) {
+ int flags;
+ int i;
+
+ sim_cb_eprintf (callback, "R00-07:");
+ for (i = 0; i < 8; i++)
+ sim_cb_eprintf (callback, " %02x", sram[i]);
+ sim_cb_eprintf (callback, " -");
+ for (i = 8; i < 16; i++)
+ sim_cb_eprintf (callback, " %02x", sram[i]);
+ sim_cb_eprintf (callback, " SP: %02x %02x",
+ sram[REG_SP + 1], sram[REG_SP]);
+ sim_cb_eprintf (callback, "\n");
+ sim_cb_eprintf (callback, "R16-31:");
+ for (i = 16; i < 24; i++)
+ sim_cb_eprintf (callback, " %02x", sram[i]);
+ sim_cb_eprintf (callback, " -");
+ for (i = 24; i < 32; i++)
+ sim_cb_eprintf (callback, " %02x", sram[i]);
+ sim_cb_eprintf (callback, " ");
+ flags = sram[SREG];
+ for (i = 0; i < 8; i++)
+ sim_cb_eprintf (callback, "%c",
+ flags & (0x80 >> i) ? "ITHSVNZC"[i] : '-');
+ sim_cb_eprintf (callback, "\n");
+ }
+
+ if (lock_step && !tracing)
+ sim_cb_eprintf (callback, "%06x: %04x\n", 2 * pc, flash[pc].op);
+ else
+ {
+ sim_cb_eprintf (callback, "pc=0x%06x insn=0x%04x code=%d r=%d\n",
+ 2 * pc, flash[pc].op, code, flash[pc].r);
+ disassemble_insn (sd, pc);
+ sim_cb_eprintf (callback, "\n");
+ }
+ }
+
+ ipc = pc;
+ pc = (pc + 1) & PC_MASK;
+ cycles++;
+
+ switch (code)
+ {
+ case OP_unknown:
+ flash[ipc].code = decode(ipc);
+ pc = ipc;
+ cycles--;
+ goto again;
+ break;
+
+ case OP_nop:
+ break;
+
+ case OP_jmp:
+ /* 2 words instruction, but we don't care about the pc. */
+ pc = ((flash[ipc].r << 16) | flash[ipc + 1].op) & PC_MASK;
+ cycles += 2;
+ break;
+
+ case OP_eijmp:
+ pc = ((sram[EIND] << 16) | read_word (REGZ)) & PC_MASK;
+ cycles += 2;
+ break;
+
+ case OP_ijmp:
+ pc = read_word (REGZ) & PC_MASK;
+ cycles += 1;
+ break;
+
+ case OP_call:
+ /* 2 words instruction. */
+ pc++;
+ do_call ((flash[ipc].r << 16) | flash[ipc + 1].op);
+ break;
+
+ case OP_eicall:
+ do_call ((sram[EIND] << 16) | read_word (REGZ));
+ break;
+
+ case OP_icall:
+ do_call (read_word (REGZ));
+ break;
+
+ case OP_rcall:
+ do_call (pc + sign_ext (op & 0xfff, 12));
+ break;
+
+ case OP_reti:
+ sram[SREG] |= SREG_I;
+ /* Fall through */
+ case OP_ret:
+ {
+ unsigned int sp = read_word (REG_SP);
+ if (avr_pc22)
+ {
+ pc = sram[++sp] = pc << 16;
+ cycles++;
+ }
+ else
+ pc = 0;
+ pc |= sram[++sp] << 8;
+ pc |= sram[++sp];
+ write_word (REG_SP, sp);
+ }
+ cycles += 3;
+ break;
+
+ case OP_break:
+ /* Stop on this address. */
+ cpu_exception = sim_stopped;
+ cpu_signal = TARGET_SIGNAL_TRAP;
+ pc = ipc;
+ break;
+
+ case OP_bld:
+ d = get_d (op);
+ r = flash[ipc].r;
+ if (sram[SREG] & SREG_T)
+ sram[d] |= r;
+ else
+ sram[d] &= ~r;
+ break;
+
+ case OP_bst:
+ if (sram[get_d (op)] & flash[ipc].r)
+ sram[SREG] |= SREG_T;
+ else
+ sram[SREG] &= ~SREG_T;
+ break;
+
+ case OP_sbrc:
+ case OP_sbrs:
+ if (((sram[get_d (op)] & flash[ipc].r) == 0) ^ ((op & 0x0200) != 0))
+ {
+ int l = get_insn_length(pc);
+ pc += l;
+ cycles += l;
+ }
+ break;
+
+ case OP_push:
+ {
+ unsigned int sp = read_word (REG_SP);
+ sram[sp--] = sram[get_d (op)];
+ write_word (REG_SP, sp);
+ }
+ cycles++;
+ break;
+
+ case OP_pop:
+ {
+ unsigned int sp = read_word (REG_SP);
+ sram[get_d (op)] = sram[++sp];
+ write_word (REG_SP, sp);
+ }
+ cycles++;
+ break;
+
+ case OP_bclr:
+ sram[SREG] &= ~(1 << ((op >> 4) & 0x7));
+ break;
+
+ case OP_bset:
+ sram[SREG] |= 1 << ((op >> 4) & 0x7);
+ break;
+
+ case OP_rjmp:
+ pc = (pc + sign_ext (op & 0xfff, 12)) & PC_MASK;
+ cycles++;
+ break;
+
+ case OP_eor:
+ d = get_d (op);
+ res = sram[d] ^ sram[get_r (op)];
+ sram[d] = res;
+ update_flags_logic (res);
+ break;
+
+ case OP_and:
+ d = get_d (op);
+ res = sram[d] & sram[get_r (op)];
+ sram[d] = res;
+ update_flags_logic (res);
+ break;
+
+ case OP_andi:
+ d = get_d16 (op);
+ res = sram[d] & get_K (op);
+ sram[d] = res;
+ update_flags_logic (res);
+ break;
+
+ case OP_or:
+ d = get_d (op);
+ res = sram[d] | sram[get_r (op)];
+ sram[d] = res;
+ update_flags_logic (res);
+ break;
+
+ case OP_ori:
+ d = get_d16 (op);
+ res = sram[d] | get_K (op);
+ sram[d] = res;
+ update_flags_logic (res);
+ break;
+
+ case OP_com:
+ d = get_d (op);
+ res = ~sram[d];
+ sram[d] = res;
+ update_flags_logic (res);
+ sram[SREG] |= SREG_C;
+ break;
+
+ case OP_swap:
+ d = get_d (op);
+ vd = sram[d];
+ sram[d] = (vd >> 4) | (vd << 4);
+ break;
+
+ case OP_neg:
+ d = get_d (op);
+ vd = sram[d];
+ res = -vd;
+ sram[d] = res;
+ sram[SREG] &= ~(SREG_H | SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+ if (res == 0)
+ sram[SREG] |= SREG_Z;
+ else
+ sram[SREG] |= SREG_C;
+ if (res == 0x80)
+ sram[SREG] |= SREG_V | SREG_N;
+ else if (res & 0x80)
+ sram[SREG] |= SREG_N | SREG_S;
+ if ((res | vd) & 0x08)
+ sram[SREG] |= SREG_H;
+ break;
+
+ case OP_inc:
+ d = get_d (op);
+ res = sram[d] + 1;
+ sram[d] = res;
+ sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z);
+ if (res == 0x80)
+ sram[SREG] |= SREG_V | SREG_N;
+ else if (res & 0x80)
+ sram[SREG] |= SREG_N | SREG_S;
+ else if (res == 0)
+ sram[SREG] |= SREG_Z;
+ break;
+
+ case OP_dec:
+ d = get_d (op);
+ res = sram[d] - 1;
+ sram[d] = res;
+ sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z);
+ if (res == 0x7f)
+ sram[SREG] |= SREG_V | SREG_S;
+ else if (res & 0x80)
+ sram[SREG] |= SREG_N | SREG_S;
+ else if (res == 0)
+ sram[SREG] |= SREG_Z;
+ break;
+
+ case OP_lsr:
+ case OP_asr:
+ d = get_d (op);
+ vd = sram[d];
+ res = (vd >> 1) | (vd & flash[ipc].r);
+ sram[d] = res;
+ sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+ if (vd & 1)
+ sram[SREG] |= SREG_C | SREG_S;
+ if (res & 0x80)
+ sram[SREG] |= SREG_N;
+ if (!(sram[SREG] & SREG_N) ^ !(sram[SREG] & SREG_C))
+ sram[SREG] |= SREG_V;
+ if (res == 0)
+ sram[SREG] |= SREG_Z;
+ break;
+
+ case OP_ror:
+ d = get_d (op);
+ vd = sram[d];
+ res = vd >> 1 | (sram[SREG] << 7);
+ sram[d] = res;
+ sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+ if (vd & 1)
+ sram[SREG] |= SREG_C | SREG_S;
+ if (res & 0x80)
+ sram[SREG] |= SREG_N;
+ if (!(sram[SREG] & SREG_N) ^ !(sram[SREG] & SREG_C))
+ sram[SREG] |= SREG_V;
+ if (res == 0)
+ sram[SREG] |= SREG_Z;
+ break;
+
+ case OP_mul:
+ gen_mul ((word)sram[get_r (op)] * (word)sram[get_d (op)]);
+ break;
+
+ case OP_muls:
+ gen_mul((sword)(sbyte)sram[get_r16 (op)]
+ * (sword)(sbyte)sram[get_d16 (op)]);
+ break;
+
+ case OP_mulsu:
+ gen_mul ((sword)(word)sram[get_r16_23 (op)]
+ * (sword)(sbyte)sram[get_d16_23 (op)]);
+ break;
+
+ case OP_fmul:
+ gen_mul(((word)sram[get_r16_23 (op)]
+ * (word)sram[get_d16_23 (op)]) << 1);
+ break;
+
+ case OP_fmuls:
+ gen_mul(((sword)(sbyte)sram[get_r16_23 (op)]
+ * (sword)(sbyte)sram[get_d16_23 (op)]) << 1);
+ break;
+
+ case OP_fmulsu:
+ gen_mul(((sword)(word)sram[get_r16_23 (op)]
+ * (sword)(sbyte)sram[get_d16_23 (op)]) << 1);
+ break;
+
+ case OP_adc:
+ case OP_add:
+ r = sram[get_r (op)];
+ d = get_d (op);
+ vd = sram[d];
+ res = r + vd + (sram[SREG] & flash[ipc].r);
+ sram[d] = res;
+ update_flags_add (res, vd, r);
+ break;
+
+ case OP_sub:
+ d = get_d (op);
+ vd = sram[d];
+ r = sram[get_r (op)];
+ res = vd - r;
+ sram[d] = res;
+ update_flags_sub (res, vd, r);
+ if (res == 0)
+ sram[SREG] |= SREG_Z;
+ break;
+
+ case OP_sbc:
+ {
+ byte old = sram[SREG];
+ d = get_d (op);
+ vd = sram[d];
+ r = sram[get_r (op)];
+ res = vd - r - (old & SREG_C);
+ sram[d] = res;
+ update_flags_sub (res, vd, r);
+ if (res == 0 && (old & SREG_Z))
+ sram[SREG] |= SREG_Z;
+ }
+ break;
+
+ case OP_subi:
+ d = get_d16 (op);
+ vd = sram[d];
+ r = get_K (op);
+ res = vd - r;
+ sram[d] = res;
+ update_flags_sub (res, vd, r);
+ if (res == 0)
+ sram[SREG] |= SREG_Z;
+ break;
+
+ case OP_sbci:
+ {
+ byte old = sram[SREG];
+
+ d = get_d16 (op);
+ vd = sram[d];
+ r = get_K (op);
+ res = vd - r - (old & SREG_C);
+ sram[d] = res;
+ update_flags_sub (res, vd, r);
+ if (res == 0 && (old & SREG_Z))
+ sram[SREG] |= SREG_Z;
+ }
+ break;
+
+ case OP_mov:
+ sram[get_d (op)] = sram[get_r (op)];
+ break;
+
+ case OP_movw:
+ d = (op & 0xf0) >> 3;
+ r = (op & 0x0f) << 1;
+ sram[d] = sram[r];
+ sram[d + 1] = sram[r + 1];
+ break;
+
+ case OP_out:
+ d = get_A (op) + 0x20;
+ res = sram[get_d (op)];
+ sram[d] = res;
+ if (d == STDIO_PORT)
+ putchar (res);
+ else if (d == EXIT_PORT)
+ {
+ cpu_exception = sim_exited;
+ cpu_signal = 0;
+ return;
+ }
+ else if (d == ABORT_PORT)
+ {
+ cpu_exception = sim_exited;
+ cpu_signal = 1;
+ return;
+ }
+ break;
+
+ case OP_in:
+ d = get_A (op) + 0x20;
+ sram[get_d (op)] = sram[d];
+ break;
+
+ case OP_cbi:
+ d = get_biA (op) + 0x20;
+ sram[d] &= ~(1 << get_b(op));
+ break;
+
+ case OP_sbi:
+ d = get_biA (op) + 0x20;
+ sram[d] |= 1 << get_b(op);
+ break;
+
+ case OP_sbic:
+ if (!(sram[get_biA (op) + 0x20] & 1 << get_b(op)))
+ {
+ int l = get_insn_length(pc);
+ pc += l;
+ cycles += l;
+ }
+ break;
+
+ case OP_sbis:
+ if (sram[get_biA (op) + 0x20] & 1 << get_b(op))
+ {
+ int l = get_insn_length(pc);
+ pc += l;
+ cycles += l;
+ }
+ break;
+
+ case OP_ldi:
+ res = get_K (op);
+ d = get_d16 (op);
+ sram[d] = res;
+ break;
+
+ case OP_lds:
+ sram[get_d (op)] = sram[flash[pc].op];
+ pc++;
+ cycles++;
+ break;
+
+ case OP_sts:
+ sram[flash[pc].op] = sram[get_d (op)];
+ pc++;
+ cycles++;
+ break;
+
+ case OP_cpse:
+ if (sram[get_r (op)] == sram[get_d (op)])
+ {
+ int l = get_insn_length(pc);
+ pc += l;
+ cycles += l;
+ }
+ break;
+
+ case OP_cp:
+ r = sram[get_r (op)];
+ d = sram[get_d (op)];
+ res = d - r;
+ update_flags_sub (res, d, r);
+ if (res == 0)
+ sram[SREG] |= SREG_Z;
+ break;
+
+ case OP_cpi:
+ r = get_K (op);
+ d = sram[get_d16 (op)];
+ res = d - r;
+ update_flags_sub (res, d, r);
+ if (res == 0)
+ sram[SREG] |= SREG_Z;
+ break;
+
+ case OP_cpc:
+ {
+ byte old = sram[SREG];
+ d = sram[get_d (op)];
+ r = sram[get_r (op)];
+ res = d - r - (old & SREG_C);
+ update_flags_sub (res, d, r);
+ if (res == 0 && (old & SREG_Z))
+ sram[SREG] |= SREG_Z;
+ }
+ break;
+
+ case OP_brbc:
+ if (!(sram[SREG] & flash[ipc].r))
+ {
+ pc = (pc + get_k (op)) & PC_MASK;
+ cycles++;
+ }
+ break;
+
+ case OP_brbs:
+ if (sram[SREG] & flash[ipc].r)
+ {
+ pc = (pc + get_k (op)) & PC_MASK;
+ cycles++;
+ }
+ break;
+
+ case OP_lpm:
+ sram[0] = get_lpm (read_word (REGZ));
+ cycles += 2;
+ break;
+
+ case OP_lpm_Z:
+ sram[get_d (op)] = get_lpm (read_word (REGZ));
+ cycles += 2;
+ break;
+
+ case OP_lpm_inc_Z:
+ sram[get_d (op)] = get_lpm (read_word_post_inc (REGZ));
+ cycles += 2;
+ break;
+
+ case OP_elpm:
+ sram[0] = get_lpm (get_z ());
+ cycles += 2;
+ break;
+
+ case OP_elpm_Z:
+ sram[get_d (op)] = get_lpm (get_z ());
+ cycles += 2;
+ break;
+
+ case OP_elpm_inc_Z:
+ {
+ unsigned int z = get_z ();
+
+ sram[get_d (op)] = get_lpm (z);
+ z++;
+ sram[REGZ_LO] = z;
+ sram[REGZ_HI] = z >> 8;
+ sram[RAMPZ] = z >> 16;
+ }
+ cycles += 2;
+ break;
+
+ case OP_ld_Z_inc:
+ sram[get_d (op)] = sram[read_word_post_inc (REGZ) & SRAM_MASK];
+ cycles++;
+ break;
+
+ case OP_ld_dec_Z:
+ sram[get_d (op)] = sram[read_word_pre_dec (REGZ) & SRAM_MASK];
+ cycles++;
+ break;
+
+ case OP_ld_X_inc:
+ sram[get_d (op)] = sram[read_word_post_inc (REGX) & SRAM_MASK];
+ cycles++;
+ break;
+
+ case OP_ld_dec_X:
+ sram[get_d (op)] = sram[read_word_pre_dec (REGX) & SRAM_MASK];
+ cycles++;
+ break;
+
+ case OP_ld_Y_inc:
+ sram[get_d (op)] = sram[read_word_post_inc (REGY) & SRAM_MASK];
+ cycles++;
+ break;
+
+ case OP_ld_dec_Y:
+ sram[get_d (op)] = sram[read_word_pre_dec (REGY) & SRAM_MASK];
+ cycles++;
+ break;
+
+ case OP_st_X:
+ sram[read_word (REGX) & SRAM_MASK] = sram[get_d (op)];
+ cycles++;
+ break;
+
+ case OP_st_X_inc:
+ sram[read_word_post_inc (REGX) & SRAM_MASK] = sram[get_d (op)];
+ cycles++;
+ break;
+
+ case OP_st_dec_X:
+ sram[read_word_pre_dec (REGX) & SRAM_MASK] = sram[get_d (op)];
+ cycles++;
+ break;
+
+ case OP_st_Z_inc:
+ sram[read_word_post_inc (REGZ) & SRAM_MASK] = sram[get_d (op)];
+ cycles++;
+ break;
+
+ case OP_st_dec_Z:
+ sram[read_word_pre_dec (REGZ) & SRAM_MASK] = sram[get_d (op)];
+ cycles++;
+ break;
+
+ case OP_st_Y_inc:
+ sram[read_word_post_inc (REGY) & SRAM_MASK] = sram[get_d (op)];
+ cycles++;
+ break;
+
+ case OP_st_dec_Y:
+ sram[read_word_pre_dec (REGY) & SRAM_MASK] = sram[get_d (op)];
+ cycles++;
+ break;
+
+ case OP_std_Y:
+ sram[read_word (REGY) + flash[ipc].r] = sram[get_d (op)];
+ cycles++;
+ break;
+
+ case OP_std_Z:
+ sram[read_word (REGZ) + flash[ipc].r] = sram[get_d (op)];
+ cycles++;
+ break;
+
+ case OP_ldd_Z:
+ sram[get_d (op)] = sram[read_word (REGZ) + flash[ipc].r];
+ cycles++;
+ break;
+
+ case OP_ldd_Y:
+ sram[get_d (op)] = sram[read_word (REGY) + flash[ipc].r];
+ cycles++;
+ break;
+
+ case OP_ld_X:
+ sram[get_d (op)] = sram[read_word (REGX) & SRAM_MASK];
+ cycles++;
+ break;
+
+ case OP_sbiw:
+ {
+ word wk = get_k6 (op);
+ word wres;
+ word wr;
+
+ d = get_d24 (op);
+ wr = read_word (d);
+ wres = wr - wk;
+
+ sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+ if (wres == 0)
+ sram[SREG] |= SREG_Z;
+ if (wres & 0x8000)
+ sram[SREG] |= SREG_N;
+ if (wres & ~wr & 0x8000)
+ sram[SREG] |= SREG_C;
+ if (~wres & wr & 0x8000)
+ sram[SREG] |= SREG_V;
+ if (((~wres & wr) ^ wres) & 0x8000)
+ sram[SREG] |= SREG_S;
+ write_word (d, wres);
+ }
+ cycles++;
+ break;
+
+ case OP_adiw:
+ {
+ word wk = get_k6 (op);
+ word wres;
+ word wr;
+
+ d = get_d24 (op);
+ wr = read_word (d);
+ wres = wr + wk;
+
+ sram[SREG] &= ~(SREG_S | SREG_V | SREG_N | SREG_Z | SREG_C);
+ if (wres == 0)
+ sram[SREG] |= SREG_Z;
+ if (wres & 0x8000)
+ sram[SREG] |= SREG_N;
+ if (~wres & wr & 0x8000)
+ sram[SREG] |= SREG_C;
+ if (wres & ~wr & 0x8000)
+ sram[SREG] |= SREG_V;
+ if (((wres & ~wr) ^ wres) & 0x8000)
+ sram[SREG] |= SREG_S;
+ write_word (d, wres);
+ }
+ cycles++;
+ break;
+
+ case OP_bad:
+ sim_cb_eprintf (callback, "Bad instruction at pc=0x%x\n", ipc * 2);
+ return;
+
+ default:
+ sim_cb_eprintf (callback,
+ "Unhandled instruction at pc=0x%x, code=%d\n",
+ 2 * ipc, code);
+ return;
+ }
+ }
+ while (cpu_exception == sim_running);
+}
+
+
+int
+sim_trace (SIM_DESC sd)
+{
+ tracing = 1;
+
+ sim_resume (sd, 0, 0);
+
+ tracing = 0;
+
+ return 1;
+}
+
+int
+sim_write (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size)
+{
+ int osize = size;
+
+ if (addr >= 0 && addr < SRAM_VADDR)
+ {
+ if (addr & 1)
+ return 0;
+ addr /= 2;
+ while (size > 1 && addr < MAX_AVR_FLASH)
+ {
+ flash[addr].op = buffer[0] | (buffer[1] << 8);
+ flash[addr].code = OP_unknown;
+ addr++;
+ buffer += 2;
+ size -= 2;
+ }
+ return osize - size;
+ }
+ else if (addr >= SRAM_VADDR && addr < SRAM_VADDR + MAX_AVR_SRAM)
+ {
+ addr -= SRAM_VADDR;
+ if (addr + size > MAX_AVR_SRAM)
+ size = MAX_AVR_SRAM - addr;
+ memcpy (sram + addr, buffer, size);
+ return size;
+ }
+ else
+ return 0;
+}
+
+int
+sim_read (SIM_DESC sd, SIM_ADDR addr, unsigned char *buffer, int size)
+{
+ int osize = size;
+
+ if (addr >= 0 && addr < SRAM_VADDR)
+ {
+ if (addr & 1)
+ return 0;
+ addr /= 2;
+ while (size > 1 && addr < MAX_AVR_FLASH)
+ {
+ buffer[0] = flash[addr].op;
+ buffer[1] = flash[addr].op >> 8;
+ addr++;
+ buffer += 2;
+ size -= 2;
+ }
+ return osize - size;
+ }
+ else if (addr >= SRAM_VADDR && addr < SRAM_VADDR + MAX_AVR_SRAM)
+ {
+ addr -= SRAM_VADDR;
+ if (addr + size > MAX_AVR_SRAM)
+ size = MAX_AVR_SRAM - addr;
+ memcpy (buffer, sram + addr, size);
+ return size;
+ }
+ else
+ {
+ /* Avoid errors. */
+ memset (buffer, 0, size);
+ return size;
+ }
+}
+
+int
+sim_store_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
+{
+ if (rn < 32 && length == 1)
+ {
+ sram[rn] = *memory;
+ return 1;
+ }
+ if (rn == AVR_SREG_REGNUM && length == 1)
+ {
+ sram[SREG] = *memory;
+ return 1;
+ }
+ if (rn == AVR_SP_REGNUM && length == 2)
+ {
+ sram[REG_SP] = memory[0];
+ sram[REG_SP + 1] = memory[1];
+ return 2;
+ }
+ if (rn == AVR_PC_REGNUM && length == 4)
+ {
+ pc = (memory[0] >> 1) | (memory[1] << 7)
+ | (memory[2] << 15) | (memory[3] << 23);
+ pc &= PC_MASK;
+ return 4;
+ }
+ return 0;
+}
+
+int
+sim_fetch_register (SIM_DESC sd, int rn, unsigned char *memory, int length)
+{
+ if (rn < 32 && length == 1)
+ {
+ *memory = sram[rn];
+ return 1;
+ }
+ if (rn == AVR_SREG_REGNUM && length == 1)
+ {
+ *memory = sram[SREG];
+ return 1;
+ }
+ if (rn == AVR_SP_REGNUM && length == 2)
+ {
+ memory[0] = sram[REG_SP];
+ memory[1] = sram[REG_SP + 1];
+ return 2;
+ }
+ if (rn == AVR_PC_REGNUM && length == 4)
+ {
+ memory[0] = pc << 1;
+ memory[1] = pc >> 7;
+ memory[2] = pc >> 15;
+ memory[3] = pc >> 23;
+ return 4;
+ }
+ return 0;
+}
+
+void
+sim_stop_reason (SIM_DESC sd, enum sim_stop * reason, int *sigrc)
+{
+ *reason = cpu_exception;
+ *sigrc = cpu_signal;
+}
+
+int
+sim_stop (SIM_DESC sd)
+{
+ cpu_exception = sim_stopped;
+ cpu_signal = TARGET_SIGNAL_INT;
+ return 0;
+}
+
+void
+sim_info (SIM_DESC sd, int verbose)
+{
+ callback->printf_filtered
+ (callback, "\n\n# cycles %10u\n", cycles);
+}
+
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv)
+{
+ myname = argv[0];
+ callback = cb;
+
+ cur_bfd = abfd;
+
+ /* Fudge our descriptor for now. */
+ return (SIM_DESC) 1;
+}
+
+void
+sim_close (SIM_DESC sd, int quitting)
+{
+ /* nothing to do */
+}
+
+SIM_RC
+sim_load (SIM_DESC sd, char *prog, bfd *abfd, int from_tty)
+{
+ bfd *prog_bfd;
+
+ prog_bfd = sim_load_file (sd, myname, callback, prog, abfd,
+ sim_kind == SIM_OPEN_DEBUG,
+ 0, sim_write);
+ if (prog_bfd == NULL)
+ return SIM_RC_FAIL;
+
+ avr_pc22 = (bfd_get_mach (prog_bfd) >= bfd_mach_avr6);
+
+ if (abfd != NULL)
+ cur_bfd = abfd;
+
+ return SIM_RC_OK;
+}
+
+SIM_RC
+sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd, char **argv, char **env)
+{
+ /* Set the initial register set. */
+ pc = 0;
+
+ return SIM_RC_OK;
+}
+
+void
+sim_kill (SIM_DESC sd)
+{
+ /* nothing to do */
+}
+
+void
+sim_do_command (SIM_DESC sd, char *cmd)
+{
+ /* Nothing there yet; it's all an error. */
+
+ if (cmd == NULL)
+ return;
+
+ if (strcmp (cmd, "verbose") == 0)
+ verbose = 2;
+ else if (strcmp (cmd, "trace") == 0)
+ tracing = 1;
+ else
+ sim_cb_eprintf (callback,
+ "Error: \"%s\" is not a valid avr simulator command.\n",
+ cmd);
+}
+
+void
+sim_set_callbacks (host_callback *ptr)
+{
+ callback = ptr;
+}