text: /* Simulator for the moxie processor
     Copyright (C) 2008-2021 Free Software Foundation, Inc.
     Contributed by Anthony Green
  
  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/>.  */
  
  /* This must come before any other includes.  */
  #include "defs.h"
  
  #include <fcntl.h>
  #include <signal.h>
  #include <stdlib.h>
  #include <string.h>
  #include <sys/param.h>
  #include <unistd.h>
  #include "bfd.h"
  #include "libiberty.h"
  #include "sim/sim.h"
  
  #include "sim-main.h"
  #include "sim-base.h"
  #include "sim-options.h"
  #include "sim-io.h"
  #include "sim-signal.h"
  #include "targ-vals.h"
  
  typedef int word;
  typedef unsigned int uword;
  
  /* Extract the signed 10-bit offset from a 16-bit branch
     instruction.  */
  #define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1)
  
  #define EXTRACT_WORD(addr) \
    ((sim_core_read_aligned_1 (scpu, cia, read_map, addr) << 24) \
     + (sim_core_read_aligned_1 (scpu, cia, read_map, addr+1) << 16) \
     + (sim_core_read_aligned_1 (scpu, cia, read_map, addr+2) << 8) \
     + (sim_core_read_aligned_1 (scpu, cia, read_map, addr+3)))
  
  #define EXTRACT_OFFSET(addr)						\
    (unsigned int)							\
    (((signed short)							\
      ((sim_core_read_aligned_1 (scpu, cia, read_map, addr) << 8)		\
       + (sim_core_read_aligned_1 (scpu, cia, read_map, addr+1))) << 16) >> 16)
  
  static unsigned long
  moxie_extract_unsigned_integer (unsigned char *addr, int len)
  {
    unsigned long retval;
    unsigned char * p;
    unsigned char * startaddr = (unsigned char *)addr;
    unsigned char * endaddr = startaddr + len;
   
    if (len > (int) sizeof (unsigned long))
      printf ("That operation is not available on integers of more than %zu bytes.",
  	    sizeof (unsigned long));
   
    /* Start at the most significant end of the integer, and work towards
       the least significant.  */
    retval = 0;
  
    for (p = endaddr; p > startaddr;)
      retval = (retval << 8) | * -- p;
    
    return retval;
  }
  
  static void
  moxie_store_unsigned_integer (unsigned char *addr, int len, unsigned long val)
  {
    unsigned char * p;
    unsigned char * startaddr = (unsigned char *)addr;
    unsigned char * endaddr = startaddr + len;
  
    for (p = endaddr; p > startaddr;)
      {
        * -- p = val & 0xff;
        val >>= 8;
      }
  }
  
  /* moxie register names.  */
  static const char *reg_names[16] = 
    { "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", 
      "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" };
  
  /* The machine state.
  
     This state is maintained in host byte order.  The fetch/store
     register functions must translate between host byte order and the
     target processor byte order.  Keeping this data in target byte
     order simplifies the register read/write functions.  Keeping this
     data in native order improves the performance of the simulator.
     Simulation speed is deemed more important.  */
  
  #define NUM_MOXIE_REGS 17 /* Including PC */
  #define NUM_MOXIE_SREGS 256 /* The special registers */
  #define PC_REGNO     16
  
  /* The ordering of the moxie_regset structure is matched in the
     gdb/config/moxie/tm-moxie.h file in the REGISTER_NAMES macro.  */
  /* TODO: This should be moved to sim-main.h:_sim_cpu.  */
  struct moxie_regset
  {
    word		  regs[NUM_MOXIE_REGS + 1]; /* primary registers */
    word		  sregs[256];             /* special registers */
    word            cc;                   /* the condition code reg */
    unsigned long long insts;                /* instruction counter */
  };
  
  #define CC_GT  1<<0
  #define CC_LT  1<<1
  #define CC_EQ  1<<2
  #define CC_GTU 1<<3
  #define CC_LTU 1<<4
  
  /* TODO: This should be moved to sim-main.h:_sim_cpu.  */
  union
  {
    struct moxie_regset asregs;
    word asints [1];		/* but accessed larger... */
  } cpu;
  
  static void
  set_initial_gprs (void)
  {
    int i;
    long space;
    
    /* Set up machine just out of reset.  */
    cpu.asregs.regs[PC_REGNO] = 0;
    
    /* Clean out the register contents.  */
    for (i = 0; i < NUM_MOXIE_REGS; i++)
      cpu.asregs.regs[i] = 0;
    for (i = 0; i < NUM_MOXIE_SREGS; i++)
      cpu.asregs.sregs[i] = 0;
  }
  
  /* Write a 1 byte value to memory.  */
  
  static INLINE void
  wbat (sim_cpu *scpu, word pc, word x, word v)
  {
    address_word cia = CPU_PC_GET (scpu);
    
    sim_core_write_aligned_1 (scpu, cia, write_map, x, v);
  }
  
  /* Write a 2 byte value to memory.  */
  
  static INLINE void
  wsat (sim_cpu *scpu, word pc, word x, word v)
  {
    address_word cia = CPU_PC_GET (scpu);
    
    sim_core_write_aligned_2 (scpu, cia, write_map, x, v);
  }
  
  /* Write a 4 byte value to memory.  */
  
  static INLINE void
  wlat (sim_cpu *scpu, word pc, word x, word v)
  {
    address_word cia = CPU_PC_GET (scpu);
  	
    sim_core_write_aligned_4 (scpu, cia, write_map, x, v);
  }
  
  /* Read 2 bytes from memory.  */
  
  static INLINE int
  rsat (sim_cpu *scpu, word pc, word x)
  {
    address_word cia = CPU_PC_GET (scpu);
    
    return (sim_core_read_aligned_2 (scpu, cia, read_map, x));
  }
  
  /* Read 1 byte from memory.  */
  
  static INLINE int
  rbat (sim_cpu *scpu, word pc, word x)
  {
    address_word cia = CPU_PC_GET (scpu);
    
    return (sim_core_read_aligned_1 (scpu, cia, read_map, x));
  }
  
  /* Read 4 bytes from memory.  */
  
  static INLINE int
  rlat (sim_cpu *scpu, word pc, word x)
  {
    address_word cia = CPU_PC_GET (scpu);
    
    return (sim_core_read_aligned_4 (scpu, cia, read_map, x));
  }
  
  #define CHECK_FLAG(T,H) if (tflags & T) { hflags |= H; tflags ^= T; }
  
  static unsigned int
  convert_target_flags (unsigned int tflags)
  {
    unsigned int hflags = 0x0;
  
    CHECK_FLAG(0x0001, O_WRONLY);
    CHECK_FLAG(0x0002, O_RDWR);
    CHECK_FLAG(0x0008, O_APPEND);
    CHECK_FLAG(0x0200, O_CREAT);
    CHECK_FLAG(0x0400, O_TRUNC);
    CHECK_FLAG(0x0800, O_EXCL);
    CHECK_FLAG(0x2000, O_SYNC);
  
    if (tflags != 0x0)
      fprintf (stderr, 
  	     "Simulator Error: problem converting target open flags for host.  0x%x\n", 
  	     tflags);
  
    return hflags;
  }
  
  /* TODO: Split this up into finger trace levels than just insn.  */
  #define MOXIE_TRACE_INSN(str) \
    TRACE_INSN (scpu, "0x%08x, %s, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x", \
  	      opc, str, cpu.asregs.regs[0], cpu.asregs.regs[1], \
  	      cpu.asregs.regs[2], cpu.asregs.regs[3], cpu.asregs.regs[4], \
  	      cpu.asregs.regs[5], cpu.asregs.regs[6], cpu.asregs.regs[7], \
  	      cpu.asregs.regs[8], cpu.asregs.regs[9], cpu.asregs.regs[10], \
  	      cpu.asregs.regs[11], cpu.asregs.regs[12], cpu.asregs.regs[13], \
  	      cpu.asregs.regs[14], cpu.asregs.regs[15])
  
  void
  sim_engine_run (SIM_DESC sd,
  		int next_cpu_nr, /* ignore  */
  		int nr_cpus, /* ignore  */
  		int siggnal) /* ignore  */
  {
    word pc, opc;
    unsigned short inst;
    sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
    address_word cia = CPU_PC_GET (scpu);
  
    pc = cpu.asregs.regs[PC_REGNO];
  
    /* Run instructions here. */
    do 
      {
        opc = pc;
  
        /* Fetch the instruction at pc.  */
        inst = (sim_core_read_aligned_1 (scpu, cia, read_map, pc) << 8)
  	+ sim_core_read_aligned_1 (scpu, cia, read_map, pc+1);
  
        /* Decode instruction.  */
        if (inst & (1 << 15))
  	{
  	  if (inst & (1 << 14))
  	    {
  	      /* This is a Form 3 instruction.  */
  	      int opcode = (inst >> 10 & 0xf);
  
  	      switch (opcode)
  		{
  		case 0x00: /* beq */
  		  {
  		    MOXIE_TRACE_INSN ("beq");
  		    if (cpu.asregs.cc & CC_EQ)
  		      pc += INST2OFFSET(inst);
  		  }
  		  break;
  		case 0x01: /* bne */
  		  {
  		    MOXIE_TRACE_INSN ("bne");
  		    if (! (cpu.asregs.cc & CC_EQ))
  		      pc += INST2OFFSET(inst);
  		  }
  		  break;
  		case 0x02: /* blt */
  		  {
  		    MOXIE_TRACE_INSN ("blt");
  		    if (cpu.asregs.cc & CC_LT)
  		      pc += INST2OFFSET(inst);
  		  }		  break;
  		case 0x03: /* bgt */
  		  {
  		    MOXIE_TRACE_INSN ("bgt");
  		    if (cpu.asregs.cc & CC_GT)
  		      pc += INST2OFFSET(inst);
  		  }
  		  break;
  		case 0x04: /* bltu */
  		  {
  		    MOXIE_TRACE_INSN ("bltu");
  		    if (cpu.asregs.cc & CC_LTU)
  		      pc += INST2OFFSET(inst);
  		  }
  		  break;
  		case 0x05: /* bgtu */
  		  {
  		    MOXIE_TRACE_INSN ("bgtu");
  		    if (cpu.asregs.cc & CC_GTU)
  		      pc += INST2OFFSET(inst);
  		  }
  		  break;
  		case 0x06: /* bge */
  		  {
  		    MOXIE_TRACE_INSN ("bge");
  		    if (cpu.asregs.cc & (CC_GT | CC_EQ))
  		      pc += INST2OFFSET(inst);
  		  }
  		  break;
  		case 0x07: /* ble */
  		  {
  		    MOXIE_TRACE_INSN ("ble");
  		    if (cpu.asregs.cc & (CC_LT | CC_EQ))
  		      pc += INST2OFFSET(inst);
  		  }
  		  break;
  		case 0x08: /* bgeu */
  		  {
  		    MOXIE_TRACE_INSN ("bgeu");
  		    if (cpu.asregs.cc & (CC_GTU | CC_EQ))
  		      pc += INST2OFFSET(inst);
  		  }
  		  break;
  		case 0x09: /* bleu */
  		  {
  		    MOXIE_TRACE_INSN ("bleu");
  		    if (cpu.asregs.cc & (CC_LTU | CC_EQ))
  		      pc += INST2OFFSET(inst);
  		  }
  		  break;
  		default:
  		  {
  		    MOXIE_TRACE_INSN ("SIGILL3");
  		    sim_engine_halt (sd, scpu, NULL, pc, sim_stopped, SIM_SIGILL);
  		    break;
  		  }
  		}
  	    }
  	  else
  	    {
  	      /* This is a Form 2 instruction.  */
  	      int opcode = (inst >> 12 & 0x3);
  	      switch (opcode)
  		{
  		case 0x00: /* inc */
  		  {
  		    int a = (inst >> 8) & 0xf;
  		    unsigned av = cpu.asregs.regs[a];
  		    unsigned v = (inst & 0xff);
  
  		    MOXIE_TRACE_INSN ("inc");
  		    cpu.asregs.regs[a] = av + v;
  		  }
  		  break;
  		case 0x01: /* dec */
  		  {
  		    int a = (inst >> 8) & 0xf;
  		    unsigned av = cpu.asregs.regs[a];
  		    unsigned v = (inst & 0xff);
  
  		    MOXIE_TRACE_INSN ("dec");
  		    cpu.asregs.regs[a] = av - v;
  		  }
  		  break;
  		case 0x02: /* gsr */
  		  {
  		    int a = (inst >> 8) & 0xf;
  		    unsigned v = (inst & 0xff);
  
  		    MOXIE_TRACE_INSN ("gsr");
  		    cpu.asregs.regs[a] = cpu.asregs.sregs[v];
  		  }
  		  break;
  		case 0x03: /* ssr */
  		  {
  		    int a = (inst >> 8) & 0xf;
  		    unsigned v = (inst & 0xff);
  
  		    MOXIE_TRACE_INSN ("ssr");
  		    cpu.asregs.sregs[v] = cpu.asregs.regs[a];
  		  }
  		  break;
  		default:
  		  MOXIE_TRACE_INSN ("SIGILL2");
  		  sim_engine_halt (sd, scpu, NULL, pc, sim_stopped, SIM_SIGILL);
  		  break;
  		}
  	    }
  	}
        else
  	{
  	  /* This is a Form 1 instruction.  */
  	  int opcode = inst >> 8;
  	  switch (opcode)
  	    {
  	    case 0x00: /* bad */
  	      opc = opcode;
  	      MOXIE_TRACE_INSN ("SIGILL0");
  	      sim_engine_halt (sd, scpu, NULL, pc, sim_stopped, SIM_SIGILL);
  	      break;
  	    case 0x01: /* ldi.l (immediate) */
  	      {
  		int reg = (inst >> 4) & 0xf;
  		unsigned int val = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("ldi.l");
  		cpu.asregs.regs[reg] = val;
  		pc += 4;
  	      }
  	      break;
  	    case 0x02: /* mov (register-to-register) */
  	      {
  		int dest  = (inst >> 4) & 0xf;
  		int src = (inst ) & 0xf;
  
  		MOXIE_TRACE_INSN ("mov");
  		cpu.asregs.regs[dest] = cpu.asregs.regs[src];
  	      }
  	      break;
   	    case 0x03: /* jsra */
   	      {
   		unsigned int fn = EXTRACT_WORD(pc+2);
   		unsigned int sp = cpu.asregs.regs[1];
  
  		MOXIE_TRACE_INSN ("jsra");
   		/* Save a slot for the static chain.  */
  		sp -= 4;
  
   		/* Push the return address.  */
  		sp -= 4;
   		wlat (scpu, opc, sp, pc + 6);
   		
   		/* Push the current frame pointer.  */
   		sp -= 4;
   		wlat (scpu, opc, sp, cpu.asregs.regs[0]);
   
   		/* Uncache the stack pointer and set the pc and $fp.  */
  		cpu.asregs.regs[1] = sp;
  		cpu.asregs.regs[0] = sp;
   		pc = fn - 2;
   	      }
   	      break;
   	    case 0x04: /* ret */
   	      {
   		unsigned int sp = cpu.asregs.regs[0];
  
  		MOXIE_TRACE_INSN ("ret");
   
   		/* Pop the frame pointer.  */
   		cpu.asregs.regs[0] = rlat (scpu, opc, sp);
   		sp += 4;
   		
   		/* Pop the return address.  */
   		pc = rlat (scpu, opc, sp) - 2;
   		sp += 4;
  
  		/* Skip over the static chain slot.  */
  		sp += 4;
   
   		/* Uncache the stack pointer.  */
   		cpu.asregs.regs[1] = sp;
    	      }
    	      break;
  	    case 0x05: /* add.l */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		unsigned av = cpu.asregs.regs[a];
  		unsigned bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("add.l");
  		cpu.asregs.regs[a] = av + bv;
  	      }
  	      break;
  	    case 0x06: /* push */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		int sp = cpu.asregs.regs[a] - 4;
  
  		MOXIE_TRACE_INSN ("push");
  		wlat (scpu, opc, sp, cpu.asregs.regs[b]);
  		cpu.asregs.regs[a] = sp;
  	      }
  	      break;
  	    case 0x07: /* pop */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		int sp = cpu.asregs.regs[a];
  
  		MOXIE_TRACE_INSN ("pop");
  		cpu.asregs.regs[b] = rlat (scpu, opc, sp);
  		cpu.asregs.regs[a] = sp + 4;
  	      }
  	      break;
  	    case 0x08: /* lda.l */
  	      {
  		int reg = (inst >> 4) & 0xf;
  		unsigned int addr = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("lda.l");
  		cpu.asregs.regs[reg] = rlat (scpu, opc, addr);
  		pc += 4;
  	      }
  	      break;
  	    case 0x09: /* sta.l */
  	      {
  		int reg = (inst >> 4) & 0xf;
  		unsigned int addr = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("sta.l");
  		wlat (scpu, opc, addr, cpu.asregs.regs[reg]);
  		pc += 4;
  	      }
  	      break;
  	    case 0x0a: /* ld.l (register indirect) */
  	      {
  		int src  = inst & 0xf;
  		int dest = (inst >> 4) & 0xf;
  		int xv;
  
  		MOXIE_TRACE_INSN ("ld.l");
  		xv = cpu.asregs.regs[src];
  		cpu.asregs.regs[dest] = rlat (scpu, opc, xv);
  	      }
  	      break;
  	    case 0x0b: /* st.l */
  	      {
  		int dest = (inst >> 4) & 0xf;
  		int val  = inst & 0xf;
  
  		MOXIE_TRACE_INSN ("st.l");
  		wlat (scpu, opc, cpu.asregs.regs[dest], cpu.asregs.regs[val]);
  	      }
  	      break;
  	    case 0x0c: /* ldo.l */
  	      {
  		unsigned int addr = EXTRACT_OFFSET(pc+2);
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  
  		MOXIE_TRACE_INSN ("ldo.l");
  		addr += cpu.asregs.regs[b];
  		cpu.asregs.regs[a] = rlat (scpu, opc, addr);
  		pc += 2;
  	      }
  	      break;
  	    case 0x0d: /* sto.l */
  	      {
  		unsigned int addr = EXTRACT_OFFSET(pc+2);
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  
  		MOXIE_TRACE_INSN ("sto.l");
  		addr += cpu.asregs.regs[a];
  		wlat (scpu, opc, addr, cpu.asregs.regs[b]);
  		pc += 2;
  	      }
  	      break;
  	    case 0x0e: /* cmp */
  	      {
  		int a  = (inst >> 4) & 0xf;
  		int b  = inst & 0xf;
  		int cc = 0;
  		int va = cpu.asregs.regs[a];
  		int vb = cpu.asregs.regs[b]; 
  
  		MOXIE_TRACE_INSN ("cmp");
  		if (va == vb)
  		  cc = CC_EQ;
  		else
  		  {
  		    cc |= (va < vb ? CC_LT : 0);
  		    cc |= (va > vb ? CC_GT : 0);
  		    cc |= ((unsigned int) va < (unsigned int) vb ? CC_LTU : 0);
  		    cc |= ((unsigned int) va > (unsigned int) vb ? CC_GTU : 0);
  		  }
  
  		cpu.asregs.cc = cc;
  	      }
  	      break;
  	    case 0x0f: /* nop */
  	      break;
  	    case 0x10: /* sex.b */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		signed char bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("sex.b");
  		cpu.asregs.regs[a] = (int) bv;
  	      }
  	      break;
  	    case 0x11: /* sex.s */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		signed short bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("sex.s");
  		cpu.asregs.regs[a] = (int) bv;
  	      }
  	      break;
  	    case 0x12: /* zex.b */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		signed char bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("zex.b");
  		cpu.asregs.regs[a] = (int) bv & 0xff;
  	      }
  	      break;
  	    case 0x13: /* zex.s */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		signed short bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("zex.s");
  		cpu.asregs.regs[a] = (int) bv & 0xffff;
  	      }
  	      break;
  	    case 0x14: /* umul.x */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		unsigned av = cpu.asregs.regs[a];
  		unsigned bv = cpu.asregs.regs[b];
  		unsigned long long r = 
  		  (unsigned long long) av * (unsigned long long) bv;
  
  		MOXIE_TRACE_INSN ("umul.x");
  		cpu.asregs.regs[a] = r >> 32;
  	      }
  	      break;
  	    case 0x15: /* mul.x */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		unsigned av = cpu.asregs.regs[a];
  		unsigned bv = cpu.asregs.regs[b];
  		signed long long r = 
  		  (signed long long) av * (signed long long) bv;
  
  		MOXIE_TRACE_INSN ("mul.x");
  		cpu.asregs.regs[a] = r >> 32;
  	      }
  	      break;
  	    case 0x16: /* bad */
  	    case 0x17: /* bad */
  	    case 0x18: /* bad */
  	      {
  		opc = opcode;
  		MOXIE_TRACE_INSN ("SIGILL0");
  		sim_engine_halt (sd, scpu, NULL, pc, sim_stopped, SIM_SIGILL);
  		break;
  	      }
  	    case 0x19: /* jsr */
  	      {
  		unsigned int fn = cpu.asregs.regs[(inst >> 4) & 0xf];
  		unsigned int sp = cpu.asregs.regs[1];
  
  		MOXIE_TRACE_INSN ("jsr");
  
   		/* Save a slot for the static chain.  */
  		sp -= 4;
  
  		/* Push the return address.  */
  		sp -= 4;
  		wlat (scpu, opc, sp, pc + 2);
  		
  		/* Push the current frame pointer.  */
  		sp -= 4;
  		wlat (scpu, opc, sp, cpu.asregs.regs[0]);
  
  		/* Uncache the stack pointer and set the fp & pc.  */
  		cpu.asregs.regs[1] = sp;
  		cpu.asregs.regs[0] = sp;
  		pc = fn - 2;
  	      }
  	      break;
  	    case 0x1a: /* jmpa */
  	      {
  		unsigned int tgt = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("jmpa");
  		pc = tgt - 2;
  	      }
  	      break;
  	    case 0x1b: /* ldi.b (immediate) */
  	      {
  		int reg = (inst >> 4) & 0xf;
  		unsigned int val = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("ldi.b");
  		cpu.asregs.regs[reg] = val;
  		pc += 4;
  	      }
  	      break;
  	    case 0x1c: /* ld.b (register indirect) */
  	      {
  		int src  = inst & 0xf;
  		int dest = (inst >> 4) & 0xf;
  		int xv;
  
  		MOXIE_TRACE_INSN ("ld.b");
  		xv = cpu.asregs.regs[src];
  		cpu.asregs.regs[dest] = rbat (scpu, opc, xv);
  	      }
  	      break;
  	    case 0x1d: /* lda.b */
  	      {
  		int reg = (inst >> 4) & 0xf;
  		unsigned int addr = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("lda.b");
  		cpu.asregs.regs[reg] = rbat (scpu, opc, addr);
  		pc += 4;
  	      }
  	      break;
  	    case 0x1e: /* st.b */
  	      {
  		int dest = (inst >> 4) & 0xf;
  		int val  = inst & 0xf;
  
  		MOXIE_TRACE_INSN ("st.b");
  		wbat (scpu, opc, cpu.asregs.regs[dest], cpu.asregs.regs[val]);
  	      }
  	      break;
  	    case 0x1f: /* sta.b */
  	      {
  		int reg = (inst >> 4) & 0xf;
  		unsigned int addr = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("sta.b");
  		wbat (scpu, opc, addr, cpu.asregs.regs[reg]);
  		pc += 4;
  	      }
  	      break;
  	    case 0x20: /* ldi.s (immediate) */
  	      {
  		int reg = (inst >> 4) & 0xf;
  
  		unsigned int val = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("ldi.s");
  		cpu.asregs.regs[reg] = val;
  		pc += 4;
  	      }
  	      break;
  	    case 0x21: /* ld.s (register indirect) */
  	      {
  		int src  = inst & 0xf;
  		int dest = (inst >> 4) & 0xf;
  		int xv;
  
  		MOXIE_TRACE_INSN ("ld.s");
  		xv = cpu.asregs.regs[src];
  		cpu.asregs.regs[dest] = rsat (scpu, opc, xv);
  	      }
  	      break;
  	    case 0x22: /* lda.s */
  	      {
  		int reg = (inst >> 4) & 0xf;
  		unsigned int addr = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("lda.s");
  		cpu.asregs.regs[reg] = rsat (scpu, opc, addr);
  		pc += 4;
  	      }
  	      break;
  	    case 0x23: /* st.s */
  	      {
  		int dest = (inst >> 4) & 0xf;
  		int val  = inst & 0xf;
  
  		MOXIE_TRACE_INSN ("st.s");
  		wsat (scpu, opc, cpu.asregs.regs[dest], cpu.asregs.regs[val]);
  	      }
  	      break;
  	    case 0x24: /* sta.s */
  	      {
  		int reg = (inst >> 4) & 0xf;
  		unsigned int addr = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("sta.s");
  		wsat (scpu, opc, addr, cpu.asregs.regs[reg]);
  		pc += 4;
  	      }
  	      break;
  	    case 0x25: /* jmp */
  	      {
  		int reg = (inst >> 4) & 0xf;
  
  		MOXIE_TRACE_INSN ("jmp");
  		pc = cpu.asregs.regs[reg] - 2;
  	      }
  	      break;
  	    case 0x26: /* and */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		int av, bv;
  
  		MOXIE_TRACE_INSN ("and");
  		av = cpu.asregs.regs[a];
  		bv = cpu.asregs.regs[b];
  		cpu.asregs.regs[a] = av & bv;
  	      }
  	      break;
  	    case 0x27: /* lshr */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		int av = cpu.asregs.regs[a];
  		int bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("lshr");
  		cpu.asregs.regs[a] = (unsigned) ((unsigned) av >> bv);
  	      }
  	      break;
  	    case 0x28: /* ashl */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		int av = cpu.asregs.regs[a];
  		int bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("ashl");
  		cpu.asregs.regs[a] = av << bv;
  	      }
  	      break;
  	    case 0x29: /* sub.l */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		unsigned av = cpu.asregs.regs[a];
  		unsigned bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("sub.l");
  		cpu.asregs.regs[a] = av - bv;
  	      }
  	      break;
  	    case 0x2a: /* neg */
  	      {
  		int a  = (inst >> 4) & 0xf;
  		int b  = inst & 0xf;
  		int bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("neg");
  		cpu.asregs.regs[a] = - bv;
  	      }
  	      break;
  	    case 0x2b: /* or */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		int av, bv;
  
  		MOXIE_TRACE_INSN ("or");
  		av = cpu.asregs.regs[a];
  		bv = cpu.asregs.regs[b];
  		cpu.asregs.regs[a] = av | bv;
  	      }
  	      break;
  	    case 0x2c: /* not */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		int bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("not");
  		cpu.asregs.regs[a] = 0xffffffff ^ bv;
  	      }
  	      break;
  	    case 0x2d: /* ashr */
  	      {
  		int a  = (inst >> 4) & 0xf;
  		int b  = inst & 0xf;
  		int av = cpu.asregs.regs[a];
  		int bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("ashr");
  		cpu.asregs.regs[a] = av >> bv;
  	      }
  	      break;
  	    case 0x2e: /* xor */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		int av, bv;
  
  		MOXIE_TRACE_INSN ("xor");
  		av = cpu.asregs.regs[a];
  		bv = cpu.asregs.regs[b];
  		cpu.asregs.regs[a] = av ^ bv;
  	      }
  	      break;
  	    case 0x2f: /* mul.l */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		unsigned av = cpu.asregs.regs[a];
  		unsigned bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("mul.l");
  		cpu.asregs.regs[a] = av * bv;
  	      }
  	      break;
  	    case 0x30: /* swi */
  	      {
  		unsigned int inum = EXTRACT_WORD(pc+2);
  
  		MOXIE_TRACE_INSN ("swi");
  		/* Set the special registers appropriately.  */
  		cpu.asregs.sregs[2] = 3; /* MOXIE_EX_SWI */
  	        cpu.asregs.sregs[3] = inum;
  		switch (inum)
  		  {
  		  case TARGET_SYS_exit:
  		    {
  		      sim_engine_halt (sd, scpu, NULL, pc, sim_exited,
  				       cpu.asregs.regs[2]);
  		      break;
  		    }
  		  case TARGET_SYS_open:
  		    {
  		      char fname[1024];
  		      int mode = (int) convert_target_flags ((unsigned) cpu.asregs.regs[3]);
  		      int perm = (int) cpu.asregs.regs[4];
  		      int fd;
  		      sim_core_read_buffer (sd, scpu, read_map, fname,
  					    cpu.asregs.regs[2], 1024);
  		      fd = sim_io_open (sd, fname, mode);
  		      /* FIXME - set errno */
  		      cpu.asregs.regs[2] = fd;
  		      break;
  		    }
  		  case TARGET_SYS_read:
  		    {
  		      int fd = cpu.asregs.regs[2];
  		      unsigned len = (unsigned) cpu.asregs.regs[4];
  		      char *buf = malloc (len);
  		      cpu.asregs.regs[2] = sim_io_read (sd, fd, buf, len);
  		      sim_core_write_buffer (sd, scpu, write_map, buf,
  					     cpu.asregs.regs[3], len);
  		      free (buf);
  		      break;
  		    }
  		  case TARGET_SYS_write:
  		    {
  		      char *str;
  		      /* String length is at 0x12($fp) */
  		      unsigned count, len = (unsigned) cpu.asregs.regs[4];
  		      str = malloc (len);
  		      sim_core_read_buffer (sd, scpu, read_map, str,
  					    cpu.asregs.regs[3], len);
  		      count = sim_io_write (sd, cpu.asregs.regs[2], str, len);
  		      free (str);
  		      cpu.asregs.regs[2] = count;
  		      break;
  		    }
  		  case TARGET_SYS_unlink:
  		    {
  		      char fname[1024];
  		      int fd;
  		      sim_core_read_buffer (sd, scpu, read_map, fname,
  					    cpu.asregs.regs[2], 1024);
  		      fd = sim_io_unlink (sd, fname);
  		      /* FIXME - set errno */
  		      cpu.asregs.regs[2] = fd;
  		      break;
  		    }
  		  case 0xffffffff: /* Linux System Call */
  		    {
  		      unsigned int handler = cpu.asregs.sregs[1];
  		      unsigned int sp = cpu.asregs.regs[1];
  
  		      /* Save a slot for the static chain.  */
  		      sp -= 4;
  
  		      /* Push the return address.  */
  		      sp -= 4;
  		      wlat (scpu, opc, sp, pc + 6);
  		
  		      /* Push the current frame pointer.  */
  		      sp -= 4;
  		      wlat (scpu, opc, sp, cpu.asregs.regs[0]);
  
  		      /* Uncache the stack pointer and set the fp & pc.  */
  		      cpu.asregs.regs[1] = sp;
  		      cpu.asregs.regs[0] = sp;
  		      pc = handler - 6;
  		    }
  		  default:
  		    break;
  		  }
  		pc += 4;
  	      }
  	      break;
  	    case 0x31: /* div.l */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		int av = cpu.asregs.regs[a];
  		int bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("div.l");
  		cpu.asregs.regs[a] = av / bv;
  	      }
  	      break;
  	    case 0x32: /* udiv.l */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		unsigned int av = cpu.asregs.regs[a];
  		unsigned int bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("udiv.l");
  		cpu.asregs.regs[a] = (av / bv);
  	      }
  	      break;
  	    case 0x33: /* mod.l */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		int av = cpu.asregs.regs[a];
  		int bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("mod.l");
  		cpu.asregs.regs[a] = av % bv;
  	      }
  	      break;
  	    case 0x34: /* umod.l */
  	      {
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  		unsigned int av = cpu.asregs.regs[a];
  		unsigned int bv = cpu.asregs.regs[b];
  
  		MOXIE_TRACE_INSN ("umod.l");
  		cpu.asregs.regs[a] = (av % bv);
  	      }
  	      break;
  	    case 0x35: /* brk */
  	      MOXIE_TRACE_INSN ("brk");
  	      sim_engine_halt (sd, scpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
  	      pc -= 2; /* Adjust pc */
  	      break;
  	    case 0x36: /* ldo.b */
  	      {
  		unsigned int addr = EXTRACT_OFFSET(pc+2);
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  
  		MOXIE_TRACE_INSN ("ldo.b");
  		addr += cpu.asregs.regs[b];
  		cpu.asregs.regs[a] = rbat (scpu, opc, addr);
  		pc += 2;
  	      }
  	      break;
  	    case 0x37: /* sto.b */
  	      {
  		unsigned int addr = EXTRACT_OFFSET(pc+2);
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  
  		MOXIE_TRACE_INSN ("sto.b");
  		addr += cpu.asregs.regs[a];
  		wbat (scpu, opc, addr, cpu.asregs.regs[b]);
  		pc += 2;
  	      }
  	      break;
  	    case 0x38: /* ldo.s */
  	      {
  		unsigned int addr = EXTRACT_OFFSET(pc+2);
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  
  		MOXIE_TRACE_INSN ("ldo.s");
  		addr += cpu.asregs.regs[b];
  		cpu.asregs.regs[a] = rsat (scpu, opc, addr);
  		pc += 2;
  	      }
  	      break;
  	    case 0x39: /* sto.s */
  	      {
  		unsigned int addr = EXTRACT_OFFSET(pc+2);
  		int a = (inst >> 4) & 0xf;
  		int b = inst & 0xf;
  
  		MOXIE_TRACE_INSN ("sto.s");
  		addr += cpu.asregs.regs[a];
  		wsat (scpu, opc, addr, cpu.asregs.regs[b]);
  		pc += 2;
  	      }
  	      break;
  	    default:
  	      opc = opcode;
  	      MOXIE_TRACE_INSN ("SIGILL1");
  	      sim_engine_halt (sd, scpu, NULL, pc, sim_stopped, SIM_SIGILL);
  	      break;
  	    }
  	}
  
        cpu.asregs.insts++;
        pc += 2;
        cpu.asregs.regs[PC_REGNO] = pc;
  
        if (sim_events_tick (sd))
  	sim_events_process (sd);
  
      } while (1);
  }
  
  static int
  moxie_reg_store (SIM_CPU *scpu, int rn, unsigned char *memory, int length)
  {
    if (rn < NUM_MOXIE_REGS && rn >= 0)
      {
        if (length == 4)
  	{
  	  long ival;
  	  
  	  /* misalignment safe */
  	  ival = moxie_extract_unsigned_integer (memory, 4);
  	  cpu.asints[rn] = ival;
  	}
  
        return 4;
      }
    else
      return 0;
  }
  
  static int
  moxie_reg_fetch (SIM_CPU *scpu, int rn, unsigned char *memory, int length)
  {
    if (rn < NUM_MOXIE_REGS && rn >= 0)
      {
        if (length == 4)
  	{
  	  long ival = cpu.asints[rn];
  
  	  /* misalignment-safe */
  	  moxie_store_unsigned_integer (memory, 4, ival);
  	}
        
        return 4;
      }
    else
      return 0;
  }
  
  static sim_cia
  moxie_pc_get (sim_cpu *cpu)
  {
    return cpu->registers[PCIDX];
  }
  
  static void
  moxie_pc_set (sim_cpu *cpu, sim_cia pc)
  {
    cpu->registers[PCIDX] = 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 * const *argv)
  {
    int i;
    SIM_DESC sd = sim_state_alloc (kind, cb);
    SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
  
    /* Set default options before parsing user options.  */
    current_target_byte_order = BFD_ENDIAN_BIG;
  
    /* The cpu data is kept in a separately allocated chunk of memory.  */
    if (sim_cpu_alloc_all (sd, 1) != SIM_RC_OK)
      {
        free_state (sd);
        return 0;
      }
  
    if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
      {
        free_state (sd);
        return 0;
      }
  
    /* The parser will print an error message for us, so we silently return.  */
    if (sim_parse_args (sd, argv) != SIM_RC_OK)
      {
        free_state (sd);
        return 0;
      }
  
    sim_do_command(sd," memory region 0x00000000,0x4000000") ; 
    sim_do_command(sd," memory region 0xE0000000,0x10000") ; 
  
    /* 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) = moxie_reg_fetch;
        CPU_REG_STORE (cpu) = moxie_reg_store;
        CPU_PC_FETCH (cpu) = moxie_pc_get;
        CPU_PC_STORE (cpu) = moxie_pc_set;
  
        set_initial_gprs ();	/* Reset the GPR registers.  */
      }
  
    return sd;
  }
  
  /* Load the device tree blob.  */
  
  static void
  load_dtb (SIM_DESC sd, const char *filename)
  {
    int size = 0;
    FILE *f = fopen (filename, "rb");
    char *buf;
    sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */ 
  
    /* Don't warn as the sim works fine w/out a device tree.  */
    if (f == NULL)
      return;
    fseek (f, 0, SEEK_END);
    size = ftell(f);
    fseek (f, 0, SEEK_SET);
    buf = alloca (size);
    if (size != fread (buf, 1, size, f))
      {
        sim_io_eprintf (sd, "ERROR: error reading ``%s''.\n", filename);
        fclose (f);
        return;
      }
    sim_core_write_buffer (sd, scpu, write_map, buf, 0xE0000000, size);
    cpu.asregs.sregs[9] = 0xE0000000;
    fclose (f);
  }
  
  SIM_RC
  sim_create_inferior (SIM_DESC sd, struct bfd *prog_bfd,
  		     char * const *argv, char * const *env)
  {
    char * const *avp;
    int l, argc, i, tp;
    sim_cpu *scpu = STATE_CPU (sd, 0); /* FIXME */
  
    if (prog_bfd != NULL)
      cpu.asregs.regs[PC_REGNO] = bfd_get_start_address (prog_bfd);
  
    /* Copy args into target memory.  */
    avp = argv;
    for (argc = 0; avp && *avp; avp++)
      argc++;
  
    /* Target memory looks like this:
       0x00000000 zero word
       0x00000004 argc word
       0x00000008 start of argv
       .
       0x0000???? end of argv
       0x0000???? zero word 
       0x0000???? start of data pointed to by argv  */
  
    wlat (scpu, 0, 0, 0);
    wlat (scpu, 0, 4, argc);
  
    /* tp is the offset of our first argv data.  */
    tp = 4 + 4 + argc * 4 + 4;
  
    for (i = 0; i < argc; i++)
      {
        /* Set the argv value.  */
        wlat (scpu, 0, 4 + 4 + i * 4, tp);
  
        /* Store the string.  */
        sim_core_write_buffer (sd, scpu, write_map, argv[i],
  			     tp, strlen(argv[i])+1);
        tp += strlen (argv[i]) + 1;
      }
  
    wlat (scpu, 0, 4 + 4 + i * 4, 0);
  
    load_dtb (sd, DTB);
  
    return SIM_RC_OK;
  }
  