binutils-gdb/sim/iq2000/iq2000.c
2007-01-09 17:59:20 +00:00

268 lines
6.0 KiB
C

/* IQ2000 simulator support code
Copyright (C) 2000, 2004, 2007 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 2, 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, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#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));
zfree (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);
zfree (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));
zfree (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;
}