mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
af9f7da78b
For the ports that don't use the common/ subdir, we need to add stub funcs to them to avoid build failures with gdb and command completion. These do not implement the actual completion functionality ... any port that wants that can either convert to the common/ subdir, or fill out the function on their own time. Signed-off-by: Mike Frysinger <vapier@gentoo.org>
1862 lines
38 KiB
C
1862 lines
38 KiB
C
/* Simulator for Atmel's AVR core.
|
|
Copyright (C) 2009, 2010, 2011 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] << 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, const unsigned char *buffer, int size)
|
|
{
|
|
int osize = size;
|
|
|
|
if (addr >= 0 && addr < SRAM_VADDR)
|
|
{
|
|
while (size > 0 && addr < (MAX_AVR_FLASH << 1))
|
|
{
|
|
word val = flash[addr >> 1].op;
|
|
|
|
if (addr & 1)
|
|
val = (val & 0xff) | (buffer[0] << 8);
|
|
else
|
|
val = (val & 0xff00) | buffer[0];
|
|
|
|
flash[addr >> 1].op = val;
|
|
flash[addr >> 1].code = OP_unknown;
|
|
addr++;
|
|
buffer++;
|
|
size--;
|
|
}
|
|
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)
|
|
{
|
|
while (size > 0 && addr < (MAX_AVR_FLASH << 1))
|
|
{
|
|
word val = flash[addr >> 1].op;
|
|
|
|
if (addr & 1)
|
|
val >>= 8;
|
|
|
|
*buffer++ = val;
|
|
addr++;
|
|
size--;
|
|
}
|
|
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 1;
|
|
}
|
|
|
|
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;
|
|
|
|
/* Clear all the memory. */
|
|
memset (sram, 0, sizeof (sram));
|
|
memset (flash, 0, sizeof (flash));
|
|
|
|
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;
|
|
}
|
|
|
|
char **
|
|
sim_complete_command (SIM_DESC sd, char *text, char *word)
|
|
{
|
|
return NULL;
|
|
}
|