1/* IQ2000 simulator support code
2   Copyright (C) 2000, 2004, 2007, 2008, 2009, 2010, 2011
3   Free Software Foundation, Inc.
4   Contributed by Cygnus Support.
5
6   This file is part of the GNU simulators.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21#define WANT_CPU
22#define WANT_CPU_IQ2000BF
23
24#include "sim-main.h"
25#include "cgen-mem.h"
26#include "cgen-ops.h"
27
28enum
29{
30  GPR0_REGNUM = 0,
31  NR_GPR = 32,
32  PC_REGNUM = 32
33};
34
35enum libgloss_syscall
36{
37  SYS_exit = 1,
38  SYS_open = 2,
39  SYS_close = 3,
40  SYS_read = 4,
41  SYS_write = 5,
42  SYS_lseek = 6,
43  SYS_unlink = 7,
44  SYS_getpid = 8,
45  SYS_kill = 9,
46  SYS_fstat = 10,
47  SYS_argvlen = 12,
48  SYS_argv = 13,
49  SYS_chdir = 14,
50  SYS_stat = 15,
51  SYS_chmod = 16,
52  SYS_utime = 17,
53  SYS_time = 18,
54  SYS_gettimeofday = 19,
55  SYS_times = 20
56};
57
58/* Read a null terminated string from memory, return in a buffer */
59static char *
60fetch_str (current_cpu, pc, addr)
61     SIM_CPU *current_cpu;
62     PCADDR pc;
63     DI addr;
64{
65  char *buf;
66  int nr = 0;
67  while (sim_core_read_1 (current_cpu,
68                          pc, read_map, CPU2DATA(addr + nr)) != 0)
69    nr++;
70  buf = NZALLOC (char, nr + 1);
71  sim_read (CPU_STATE (current_cpu), CPU2DATA(addr), buf, nr);
72  return buf;
73}
74
75void
76do_syscall (SIM_CPU *current_cpu, PCADDR pc)
77{
78#if 0
79  int syscall = H2T_4 (iq2000bf_h_gr_get (current_cpu, 11));
80#endif
81  int syscall_function = iq2000bf_h_gr_get (current_cpu, 4);
82  int i;
83  char *buf;
84  int PARM1 = iq2000bf_h_gr_get (current_cpu, 5);
85  int PARM2 = iq2000bf_h_gr_get (current_cpu, 6);
86  int PARM3 = iq2000bf_h_gr_get (current_cpu, 7);
87  const int ret_reg = 2;
88
89  switch (syscall_function)
90    {
91    case 0:
92      switch (H2T_4 (iq2000bf_h_gr_get (current_cpu, 11)))
93	{
94	case 0:
95	  /* Pass.  */
96	  puts ("pass");
97	  exit (0);
98	case 1:
99	  /* Fail.  */
100	  puts ("fail");
101	  exit (1);
102	}
103
104    case SYS_write:
105      buf = zalloc (PARM3);
106      sim_read (CPU_STATE (current_cpu), CPU2DATA(PARM2), buf, PARM3);
107      SET_H_GR (ret_reg,
108		sim_io_write (CPU_STATE (current_cpu),
109			      PARM1, buf, PARM3));
110      free (buf);
111      break;
112
113    case SYS_lseek:
114      SET_H_GR (ret_reg,
115		sim_io_lseek (CPU_STATE (current_cpu),
116			      PARM1, PARM2, PARM3));
117      break;
118
119    case SYS_exit:
120      sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
121		       NULL, pc, sim_exited, PARM1);
122      break;
123
124    case SYS_read:
125      buf = zalloc (PARM3);
126      SET_H_GR (ret_reg,
127		sim_io_read (CPU_STATE (current_cpu),
128			     PARM1, buf, PARM3));
129      sim_write (CPU_STATE (current_cpu), CPU2DATA(PARM2), buf, PARM3);
130      free (buf);
131      break;
132
133    case SYS_open:
134      buf = fetch_str (current_cpu, pc, PARM1);
135      SET_H_GR (ret_reg,
136		sim_io_open (CPU_STATE (current_cpu),
137			     buf, PARM2));
138      free (buf);
139      break;
140
141    case SYS_close:
142      SET_H_GR (ret_reg,
143		sim_io_close (CPU_STATE (current_cpu), PARM1));
144      break;
145
146    case SYS_time:
147      SET_H_GR (ret_reg, time (0));
148      break;
149
150    default:
151      SET_H_GR (ret_reg, -1);
152    }
153}
154
155void
156do_break (SIM_CPU *current_cpu, PCADDR pc)
157{
158  SIM_DESC sd = CPU_STATE (current_cpu);
159  sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
160}
161
162/* The semantic code invokes this for invalid (unrecognized) instructions.  */
163
164SEM_PC
165sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
166{
167  SIM_DESC sd = CPU_STATE (current_cpu);
168  sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
169
170  return vpc;
171}
172
173
174/* Process an address exception.  */
175
176void
177iq2000_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia,
178                  unsigned int map, int nr_bytes, address_word addr,
179                  transfer_type transfer, sim_core_signals sig)
180{
181  sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr,
182		   transfer, sig);
183}
184
185
186/* Initialize cycle counting for an insn.
187   FIRST_P is non-zero if this is the first insn in a set of parallel
188   insns.  */
189
190void
191iq2000bf_model_insn_before (SIM_CPU *cpu, int first_p)
192{
193  /* Do nothing.  */
194}
195
196
197/* Record the cycles computed for an insn.
198   LAST_P is non-zero if this is the last insn in a set of parallel insns,
199   and we update the total cycle count.
200   CYCLES is the cycle count of the insn.  */
201
202void
203iq2000bf_model_insn_after(SIM_CPU *cpu, int last_p, int cycles)
204{
205  /* Do nothing.  */
206}
207
208
209int
210iq2000bf_model_iq2000_u_exec (SIM_CPU *cpu, const IDESC *idesc,
211			    int unit_num, int referenced)
212{
213  return idesc->timing->units[unit_num].done;
214}
215
216PCADDR
217get_h_pc (SIM_CPU *cpu)
218{
219  return CPU_CGEN_HW(cpu)->h_pc;
220}
221
222void
223set_h_pc (SIM_CPU *cpu, PCADDR addr)
224{
225  CPU_CGEN_HW(cpu)->h_pc = addr | IQ2000_INSN_MASK;
226}
227
228int
229iq2000bf_fetch_register (SIM_CPU *cpu, int nr, unsigned char *buf, int len)
230{
231  if (nr >= GPR0_REGNUM
232      && nr < (GPR0_REGNUM + NR_GPR)
233      && len == 4)
234    {
235      *((unsigned32*)buf) =
236	H2T_4 (iq2000bf_h_gr_get (cpu, nr - GPR0_REGNUM));
237      return 4;
238    }
239  else if (nr == PC_REGNUM
240	   && len == 4)
241    {
242      *((unsigned32*)buf) = H2T_4 (get_h_pc (cpu));
243      return 4;
244    }
245  else
246    return 0;
247}
248
249int
250iq2000bf_store_register (SIM_CPU *cpu, int nr, unsigned char *buf, int len)
251{
252  if (nr >= GPR0_REGNUM
253      && nr < (GPR0_REGNUM + NR_GPR)
254      && len == 4)
255    {
256      iq2000bf_h_gr_set (cpu, nr - GPR0_REGNUM, T2H_4 (*((unsigned32*)buf)));
257      return 4;
258    }
259  else if (nr == PC_REGNUM
260	   && len == 4)
261    {
262      set_h_pc (cpu, T2H_4 (*((unsigned32*)buf)));
263      return 4;
264    }
265  else
266    return 0;
267}
268