binutils-gdb/sim/avr/interp.c

1778 lines
36 KiB
C

/* Simulator for Atmel's AVR core.
Copyright (C) 2009-2016 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 "libiberty.h"
#include "gdb/remote-sim.h"
#include "sim-main.h"
#include "sim-base.h"
#include "sim-options.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;
/* 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. */
/* TODO: Should be moved to SIM_CPU. */
static struct avr_insn_cell flash[MAX_AVR_FLASH];
static byte sram[MAX_AVR_SRAM];
/* 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;
}
}
return OP_bad;
}
static void
do_call (SIM_CPU *cpu, unsigned int npc)
{
SIM_DESC sd = CPU_STATE (cpu);
unsigned int sp = read_word (REG_SP);
/* Big endian! */
sram[sp--] = cpu->pc;
sram[sp--] = cpu->pc >> 8;
if (sd->avr_pc22)
{
sram[sp--] = cpu->pc >> 16;
cpu->cycles++;
}
write_word (REG_SP, sp);
cpu->pc = npc & PC_MASK;
cpu->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 (SIM_CPU *cpu, 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;
cpu->cycles++;
}
static void
step_once (SIM_CPU *cpu)
{
unsigned int ipc;
int code;
word op;
byte res;
byte r, d, vd;
again:
code = flash[cpu->pc].code;
op = flash[cpu->pc].op;
#if 0
if (tracing && 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 (!tracing)
sim_cb_eprintf (callback, "%06x: %04x\n", 2 * cpu->pc, flash[cpu->pc].op);
else
{
sim_cb_eprintf (callback, "pc=0x%06x insn=0x%04x code=%d r=%d\n",
2 * cpu->pc, flash[cpu->pc].op, code, flash[cpu->pc].r);
disassemble_insn (CPU_STATE (cpu), cpu->pc);
sim_cb_eprintf (callback, "\n");
}
}
#endif
ipc = cpu->pc;
cpu->pc = (cpu->pc + 1) & PC_MASK;
cpu->cycles++;
switch (code)
{
case OP_unknown:
flash[ipc].code = decode(ipc);
cpu->pc = ipc;
cpu->cycles--;
goto again;
case OP_nop:
break;
case OP_jmp:
/* 2 words instruction, but we don't care about the pc. */
cpu->pc = ((flash[ipc].r << 16) | flash[ipc + 1].op) & PC_MASK;
cpu->cycles += 2;
break;
case OP_eijmp:
cpu->pc = ((sram[EIND] << 16) | read_word (REGZ)) & PC_MASK;
cpu->cycles += 2;
break;
case OP_ijmp:
cpu->pc = read_word (REGZ) & PC_MASK;
cpu->cycles += 1;
break;
case OP_call:
/* 2 words instruction. */
cpu->pc++;
do_call (cpu, (flash[ipc].r << 16) | flash[ipc + 1].op);
break;
case OP_eicall:
do_call (cpu, (sram[EIND] << 16) | read_word (REGZ));
break;
case OP_icall:
do_call (cpu, read_word (REGZ));
break;
case OP_rcall:
do_call (cpu, cpu->pc + sign_ext (op & 0xfff, 12));
break;
case OP_reti:
sram[SREG] |= SREG_I;
/* Fall through */
case OP_ret:
{
SIM_DESC sd = CPU_STATE (cpu);
unsigned int sp = read_word (REG_SP);
if (sd->avr_pc22)
{
cpu->pc = sram[++sp] << 16;
cpu->cycles++;
}
else
cpu->pc = 0;
cpu->pc |= sram[++sp] << 8;
cpu->pc |= sram[++sp];
write_word (REG_SP, sp);
}
cpu->cycles += 3;
break;
case OP_break:
/* Stop on this address. */
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, cpu->pc, sim_stopped, SIM_SIGTRAP);
cpu->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 (cpu->pc);
cpu->pc += l;
cpu->cycles += l;
}
break;
case OP_push:
{
unsigned int sp = read_word (REG_SP);
sram[sp--] = sram[get_d (op)];
write_word (REG_SP, sp);
}
cpu->cycles++;
break;
case OP_pop:
{
unsigned int sp = read_word (REG_SP);
sram[get_d (op)] = sram[++sp];
write_word (REG_SP, sp);
}
cpu->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:
cpu->pc = (cpu->pc + sign_ext (op & 0xfff, 12)) & PC_MASK;
cpu->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 (cpu, (word)sram[get_r (op)] * (word)sram[get_d (op)]);
break;
case OP_muls:
gen_mul (cpu, (sword)(sbyte)sram[get_r16 (op)]
* (sword)(sbyte)sram[get_d16 (op)]);
break;
case OP_mulsu:
gen_mul (cpu, (sword)(word)sram[get_r16_23 (op)]
* (sword)(sbyte)sram[get_d16_23 (op)]);
break;
case OP_fmul:
gen_mul (cpu, ((word)sram[get_r16_23 (op)]
* (word)sram[get_d16_23 (op)]) << 1);
break;
case OP_fmuls:
gen_mul (cpu, ((sword)(sbyte)sram[get_r16_23 (op)]
* (sword)(sbyte)sram[get_d16_23 (op)]) << 1);
break;
case OP_fmulsu:
gen_mul (cpu, ((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)
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, cpu->pc, sim_exited, 0);
else if (d == ABORT_PORT)
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, cpu->pc, sim_exited, 1);
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 (cpu->pc);
cpu->pc += l;
cpu->cycles += l;
}
break;
case OP_sbis:
if (sram[get_biA (op) + 0x20] & 1 << get_b(op))
{
int l = get_insn_length (cpu->pc);
cpu->pc += l;
cpu->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[cpu->pc].op];
cpu->pc++;
cpu->cycles++;
break;
case OP_sts:
sram[flash[cpu->pc].op] = sram[get_d (op)];
cpu->pc++;
cpu->cycles++;
break;
case OP_cpse:
if (sram[get_r (op)] == sram[get_d (op)])
{
int l = get_insn_length (cpu->pc);
cpu->pc += l;
cpu->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))
{
cpu->pc = (cpu->pc + get_k (op)) & PC_MASK;
cpu->cycles++;
}
break;
case OP_brbs:
if (sram[SREG] & flash[ipc].r)
{
cpu->pc = (cpu->pc + get_k (op)) & PC_MASK;
cpu->cycles++;
}
break;
case OP_lpm:
sram[0] = get_lpm (read_word (REGZ));
cpu->cycles += 2;
break;
case OP_lpm_Z:
sram[get_d (op)] = get_lpm (read_word (REGZ));
cpu->cycles += 2;
break;
case OP_lpm_inc_Z:
sram[get_d (op)] = get_lpm (read_word_post_inc (REGZ));
cpu->cycles += 2;
break;
case OP_elpm:
sram[0] = get_lpm (get_z ());
cpu->cycles += 2;
break;
case OP_elpm_Z:
sram[get_d (op)] = get_lpm (get_z ());
cpu->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;
}
cpu->cycles += 2;
break;
case OP_ld_Z_inc:
sram[get_d (op)] = sram[read_word_post_inc (REGZ) & SRAM_MASK];
cpu->cycles++;
break;
case OP_ld_dec_Z:
sram[get_d (op)] = sram[read_word_pre_dec (REGZ) & SRAM_MASK];
cpu->cycles++;
break;
case OP_ld_X_inc:
sram[get_d (op)] = sram[read_word_post_inc (REGX) & SRAM_MASK];
cpu->cycles++;
break;
case OP_ld_dec_X:
sram[get_d (op)] = sram[read_word_pre_dec (REGX) & SRAM_MASK];
cpu->cycles++;
break;
case OP_ld_Y_inc:
sram[get_d (op)] = sram[read_word_post_inc (REGY) & SRAM_MASK];
cpu->cycles++;
break;
case OP_ld_dec_Y:
sram[get_d (op)] = sram[read_word_pre_dec (REGY) & SRAM_MASK];
cpu->cycles++;
break;
case OP_st_X:
sram[read_word (REGX) & SRAM_MASK] = sram[get_d (op)];
cpu->cycles++;
break;
case OP_st_X_inc:
sram[read_word_post_inc (REGX) & SRAM_MASK] = sram[get_d (op)];
cpu->cycles++;
break;
case OP_st_dec_X:
sram[read_word_pre_dec (REGX) & SRAM_MASK] = sram[get_d (op)];
cpu->cycles++;
break;
case OP_st_Z_inc:
sram[read_word_post_inc (REGZ) & SRAM_MASK] = sram[get_d (op)];
cpu->cycles++;
break;
case OP_st_dec_Z:
sram[read_word_pre_dec (REGZ) & SRAM_MASK] = sram[get_d (op)];
cpu->cycles++;
break;
case OP_st_Y_inc:
sram[read_word_post_inc (REGY) & SRAM_MASK] = sram[get_d (op)];
cpu->cycles++;
break;
case OP_st_dec_Y:
sram[read_word_pre_dec (REGY) & SRAM_MASK] = sram[get_d (op)];
cpu->cycles++;
break;
case OP_std_Y:
sram[read_word (REGY) + flash[ipc].r] = sram[get_d (op)];
cpu->cycles++;
break;
case OP_std_Z:
sram[read_word (REGZ) + flash[ipc].r] = sram[get_d (op)];
cpu->cycles++;
break;
case OP_ldd_Z:
sram[get_d (op)] = sram[read_word (REGZ) + flash[ipc].r];
cpu->cycles++;
break;
case OP_ldd_Y:
sram[get_d (op)] = sram[read_word (REGY) + flash[ipc].r];
cpu->cycles++;
break;
case OP_ld_X:
sram[get_d (op)] = sram[read_word (REGX) & SRAM_MASK];
cpu->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);
}
cpu->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);
}
cpu->cycles++;
break;
case OP_bad:
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
default:
sim_engine_halt (CPU_STATE (cpu), cpu, NULL, cpu->pc, sim_signalled, SIM_SIGILL);
}
}
void
sim_engine_run (SIM_DESC sd,
int next_cpu_nr, /* ignore */
int nr_cpus, /* ignore */
int siggnal) /* ignore */
{
SIM_CPU *cpu;
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
cpu = STATE_CPU (sd, 0);
while (1)
{
step_once (cpu);
if (sim_events_tick (sd))
sim_events_process (sd);
}
}
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;
}
}
static int
avr_reg_store (SIM_CPU *cpu, 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)
{
cpu->pc = (memory[0] >> 1) | (memory[1] << 7)
| (memory[2] << 15) | (memory[3] << 23);
cpu->pc &= PC_MASK;
return 4;
}
return 0;
}
static int
avr_reg_fetch (SIM_CPU *cpu, 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] = cpu->pc << 1;
memory[1] = cpu->pc >> 7;
memory[2] = cpu->pc >> 15;
memory[3] = cpu->pc >> 23;
return 4;
}
return 0;
}
static sim_cia
avr_pc_get (sim_cpu *cpu)
{
return cpu->pc;
}
static void
avr_pc_set (sim_cpu *cpu, sim_cia pc)
{
cpu->pc = pc;
}
static void
free_state (SIM_DESC sd)
{
if (STATE_MODULES (sd) != NULL)
sim_module_uninstall (sd);
sim_cpu_free_all (sd);
sim_state_free (sd);
}
SIM_DESC
sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv)
{
int i;
SIM_DESC sd = sim_state_alloc (kind, cb);
SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
/* The cpu data is kept in a separately allocated chunk of memory. */
if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
{
/* XXX: Only first core gets profiled ? */
SIM_CPU *cpu = STATE_CPU (sd, 0);
STATE_WATCHPOINTS (sd)->pc = &cpu->pc;
STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (cpu->pc);
}
if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* getopt will print the error message so we just have to exit if this fails.
FIXME: Hmmm... in the case of gdb we need getopt to call
print_filtered. */
if (sim_parse_args (sd, argv) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* Check for/establish the a reference program image. */
if (sim_analyze_program (sd,
(STATE_PROG_ARGV (sd) != NULL
? *STATE_PROG_ARGV (sd)
: NULL), abfd) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
/* Configure/verify the target byte order and other runtime
configuration options. */
if (sim_config (sd) != SIM_RC_OK)
{
sim_module_uninstall (sd);
return 0;
}
if (sim_post_argv_init (sd) != SIM_RC_OK)
{
/* Uninstall the modules to avoid memory leaks,
file descriptor leaks, etc. */
sim_module_uninstall (sd);
return 0;
}
/* CPU specific initialization. */
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
{
SIM_CPU *cpu = STATE_CPU (sd, i);
CPU_REG_FETCH (cpu) = avr_reg_fetch;
CPU_REG_STORE (cpu) = avr_reg_store;
CPU_PC_FETCH (cpu) = avr_pc_get;
CPU_PC_STORE (cpu) = avr_pc_set;
}
/* Clear all the memory. */
memset (sram, 0, sizeof (sram));
memset (flash, 0, sizeof (flash));
return sd;
}
SIM_RC
sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **env)
{
SIM_CPU *cpu = STATE_CPU (sd, 0);
SIM_ADDR addr;
/* Set the PC. */
if (abfd != NULL)
addr = bfd_get_start_address (abfd);
else
addr = 0;
sim_pc_set (cpu, addr);
if (abfd != NULL)
sd->avr_pc22 = (bfd_get_mach (abfd) >= bfd_mach_avr6);
return SIM_RC_OK;
}