diff options
author | Tristan Gingold <gingold@adacore.com> | 2009-04-27 10:50:53 +0000 |
---|---|---|
committer | Tristan Gingold <gingold@adacore.com> | 2009-04-27 10:50:53 +0000 |
commit | df1756f414a26ac33aa2d0dbe6d757e214e45419 (patch) | |
tree | 4a6e03df3637cb5a7914a620417dbd8c22f8a619 /sim/avr/interp.c | |
parent | 57a460012a55aec007ee5ea2f229f79699cfd01a (diff) | |
download | binutils-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.c | 1847 |
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; +} |