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