/* IQ2000 simulator support code Copyright (C) 2000-2019 Free Software Foundation, Inc. Contributed by Cygnus Support. This file is part of the GNU simulators. 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 . */ #define WANT_CPU #define WANT_CPU_IQ2000BF #include "sim-main.h" #include "cgen-mem.h" #include "cgen-ops.h" enum { GPR0_REGNUM = 0, NR_GPR = 32, PC_REGNUM = 32 }; enum libgloss_syscall { SYS_exit = 1, SYS_open = 2, SYS_close = 3, SYS_read = 4, SYS_write = 5, SYS_lseek = 6, SYS_unlink = 7, SYS_getpid = 8, SYS_kill = 9, SYS_fstat = 10, SYS_argvlen = 12, SYS_argv = 13, SYS_chdir = 14, SYS_stat = 15, SYS_chmod = 16, SYS_utime = 17, SYS_time = 18, SYS_gettimeofday = 19, SYS_times = 20 }; /* Read a null terminated string from memory, return in a buffer */ static char * fetch_str (current_cpu, pc, addr) SIM_CPU *current_cpu; PCADDR pc; DI addr; { char *buf; int nr = 0; while (sim_core_read_1 (current_cpu, pc, read_map, CPU2DATA(addr + nr)) != 0) nr++; buf = NZALLOC (char, nr + 1); sim_read (CPU_STATE (current_cpu), CPU2DATA(addr), buf, nr); return buf; } void do_syscall (SIM_CPU *current_cpu, PCADDR pc) { #if 0 int syscall = H2T_4 (iq2000bf_h_gr_get (current_cpu, 11)); #endif int syscall_function = iq2000bf_h_gr_get (current_cpu, 4); int i; char *buf; int PARM1 = iq2000bf_h_gr_get (current_cpu, 5); int PARM2 = iq2000bf_h_gr_get (current_cpu, 6); int PARM3 = iq2000bf_h_gr_get (current_cpu, 7); const int ret_reg = 2; switch (syscall_function) { case 0: switch (H2T_4 (iq2000bf_h_gr_get (current_cpu, 11))) { case 0: /* Pass. */ puts ("pass"); exit (0); case 1: /* Fail. */ puts ("fail"); exit (1); } case SYS_write: buf = zalloc (PARM3); sim_read (CPU_STATE (current_cpu), CPU2DATA(PARM2), buf, PARM3); SET_H_GR (ret_reg, sim_io_write (CPU_STATE (current_cpu), PARM1, buf, PARM3)); free (buf); break; case SYS_lseek: SET_H_GR (ret_reg, sim_io_lseek (CPU_STATE (current_cpu), PARM1, PARM2, PARM3)); break; case SYS_exit: sim_engine_halt (CPU_STATE (current_cpu), current_cpu, NULL, pc, sim_exited, PARM1); break; case SYS_read: buf = zalloc (PARM3); SET_H_GR (ret_reg, sim_io_read (CPU_STATE (current_cpu), PARM1, buf, PARM3)); sim_write (CPU_STATE (current_cpu), CPU2DATA(PARM2), buf, PARM3); free (buf); break; case SYS_open: buf = fetch_str (current_cpu, pc, PARM1); SET_H_GR (ret_reg, sim_io_open (CPU_STATE (current_cpu), buf, PARM2)); free (buf); break; case SYS_close: SET_H_GR (ret_reg, sim_io_close (CPU_STATE (current_cpu), PARM1)); break; case SYS_time: SET_H_GR (ret_reg, time (0)); break; default: SET_H_GR (ret_reg, -1); } } void do_break (SIM_CPU *current_cpu, PCADDR pc) { SIM_DESC sd = CPU_STATE (current_cpu); sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP); } /* The semantic code invokes this for invalid (unrecognized) instructions. */ SEM_PC sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc) { SIM_DESC sd = CPU_STATE (current_cpu); sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL); return vpc; } /* Process an address exception. */ void iq2000_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia, unsigned int map, int nr_bytes, address_word addr, transfer_type transfer, sim_core_signals sig) { sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr, transfer, sig); } /* Initialize cycle counting for an insn. FIRST_P is non-zero if this is the first insn in a set of parallel insns. */ void iq2000bf_model_insn_before (SIM_CPU *cpu, int first_p) { /* Do nothing. */ } /* Record the cycles computed for an insn. LAST_P is non-zero if this is the last insn in a set of parallel insns, and we update the total cycle count. CYCLES is the cycle count of the insn. */ void iq2000bf_model_insn_after(SIM_CPU *cpu, int last_p, int cycles) { /* Do nothing. */ } int iq2000bf_model_iq2000_u_exec (SIM_CPU *cpu, const IDESC *idesc, int unit_num, int referenced) { return idesc->timing->units[unit_num].done; } PCADDR get_h_pc (SIM_CPU *cpu) { return CPU_CGEN_HW(cpu)->h_pc; } void set_h_pc (SIM_CPU *cpu, PCADDR addr) { CPU_CGEN_HW(cpu)->h_pc = addr | IQ2000_INSN_MASK; } int iq2000bf_fetch_register (SIM_CPU *cpu, int nr, unsigned char *buf, int len) { if (nr >= GPR0_REGNUM && nr < (GPR0_REGNUM + NR_GPR) && len == 4) { *((unsigned32*)buf) = H2T_4 (iq2000bf_h_gr_get (cpu, nr - GPR0_REGNUM)); return 4; } else if (nr == PC_REGNUM && len == 4) { *((unsigned32*)buf) = H2T_4 (get_h_pc (cpu)); return 4; } else return 0; } int iq2000bf_store_register (SIM_CPU *cpu, int nr, unsigned char *buf, int len) { if (nr >= GPR0_REGNUM && nr < (GPR0_REGNUM + NR_GPR) && len == 4) { iq2000bf_h_gr_set (cpu, nr - GPR0_REGNUM, T2H_4 (*((unsigned32*)buf))); return 4; } else if (nr == PC_REGNUM && len == 4) { set_h_pc (cpu, T2H_4 (*((unsigned32*)buf))); return 4; } else return 0; }