/* Simulator for the moxie processor Copyright (C) 2008-2015 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 . */ #include "config.h" #include #include #include #include #include #include #include #include "bfd.h" #include "libiberty.h" #include "gdb/remote-sim.h" #include "sim-main.h" #include "sim-base.h" #include "sim-options.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, NULL, 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, NULL, 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, NULL, 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, NULL, 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 0x1: /* SYS_exit */ { sim_engine_halt (sd, NULL, NULL, pc, sim_exited, cpu.asregs.regs[2]); break; } case 0x2: /* 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 = open (fname, mode, perm); sim_core_read_buffer (sd, scpu, read_map, fname, cpu.asregs.regs[2], 1024); /* FIXME - set errno */ cpu.asregs.regs[2] = fd; break; } case 0x4: /* SYS_read */ { int fd = cpu.asregs.regs[2]; unsigned len = (unsigned) cpu.asregs.regs[4]; char *buf = malloc (len); cpu.asregs.regs[2] = read (fd, buf, len); sim_core_write_buffer (sd, scpu, write_map, buf, cpu.asregs.regs[3], len); free (buf); break; } case 0x5: /* 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 = write (cpu.asregs.regs[2], str, len); free (str); cpu.asregs.regs[2] = count; 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, NULL, 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, NULL, NULL, pc, sim_stopped, SIM_SIGILL); break; } } cpu.asregs.insts++; pc += 2; cpu.asregs.regs[PC_REGNO] = pc; } while (1); } int sim_store_register (SIM_DESC sd, 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; } int sim_fetch_register (SIM_DESC sd, 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 **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; } STATE_WATCHPOINTS (sd)->pc = &cpu.asregs.regs[PC_REGNO]; STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (word); 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; } 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_PC_FETCH (cpu) = moxie_pc_get; CPU_PC_STORE (cpu) = moxie_pc_set; set_initial_gprs (); /* Reset the GPR registers. */ } return sd; } void sim_close (SIM_DESC sd, int quitting) { /* nothing to do */ } /* 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 **argv, char **env) { char ** 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; }