1 /* IQ2000 simulator support code
2    Copyright (C) 2000-2024 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 /* This must come before any other includes.  */
21 #include "defs.h"
22 
23 #define WANT_CPU
24 #define WANT_CPU_IQ2000BF
25 
26 #include "sim-main.h"
27 #include "sim-signal.h"
28 #include "cgen-mem.h"
29 #include "cgen-ops.h"
30 #include "target-newlib-syscall.h"
31 #include <stdlib.h>
32 
33 enum
34 {
35   GPR0_REGNUM = 0,
36   NR_GPR = 32,
37   PC_REGNUM = 32
38 };
39 
40 /* Read a null terminated string from memory, return in a buffer */
41 static char *
fetch_str(SIM_CPU * current_cpu,PCADDR pc,DI addr)42 fetch_str (SIM_CPU *current_cpu, PCADDR pc, DI addr)
43 {
44   char *buf;
45   int nr = 0;
46   while (sim_core_read_1 (current_cpu,
47                           pc, read_map, CPU2DATA(addr + nr)) != 0)
48     nr++;
49   buf = NZALLOC (char, nr + 1);
50   sim_read (CPU_STATE (current_cpu), CPU2DATA(addr), buf, nr);
51   return buf;
52 }
53 
54 void
do_syscall(SIM_CPU * current_cpu,PCADDR pc)55 do_syscall (SIM_CPU *current_cpu, PCADDR pc)
56 {
57 #if 0
58   int syscall = H2T_4 (iq2000bf_h_gr_get (current_cpu, 11));
59 #endif
60   int syscall_function = iq2000bf_h_gr_get (current_cpu, 4);
61   char *buf;
62   int PARM1 = iq2000bf_h_gr_get (current_cpu, 5);
63   int PARM2 = iq2000bf_h_gr_get (current_cpu, 6);
64   int PARM3 = iq2000bf_h_gr_get (current_cpu, 7);
65   const int ret_reg = 2;
66 
67   switch (syscall_function)
68     {
69     case 0:
70       switch (H2T_4 (iq2000bf_h_gr_get (current_cpu, 11)))
71           {
72           case 0:
73             /* Pass.  */
74             puts ("pass");
75             exit (0);
76           case 1:
77             /* Fail.  */
78             puts ("fail");
79             exit (1);
80           default:
81             puts ("unknown exit");
82             exit (2);
83           }
84 
85     case TARGET_NEWLIB_SYS_write:
86       buf = zalloc (PARM3);
87       sim_read (CPU_STATE (current_cpu), CPU2DATA(PARM2), buf, PARM3);
88       SET_H_GR (ret_reg,
89                     sim_io_write (CPU_STATE (current_cpu),
90                                     PARM1, buf, PARM3));
91       free (buf);
92       break;
93 
94     case TARGET_NEWLIB_SYS_lseek:
95       SET_H_GR (ret_reg,
96                     sim_io_lseek (CPU_STATE (current_cpu),
97                                     PARM1, PARM2, PARM3));
98       break;
99 
100     case TARGET_NEWLIB_SYS_exit:
101       sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
102                            NULL, pc, sim_exited, PARM1);
103       break;
104 
105     case TARGET_NEWLIB_SYS_read:
106       buf = zalloc (PARM3);
107       SET_H_GR (ret_reg,
108                     sim_io_read (CPU_STATE (current_cpu),
109                                    PARM1, buf, PARM3));
110       sim_write (CPU_STATE (current_cpu), CPU2DATA(PARM2),
111                      (unsigned char *) buf, PARM3);
112       free (buf);
113       break;
114 
115     case TARGET_NEWLIB_SYS_open:
116       buf = fetch_str (current_cpu, pc, PARM1);
117       SET_H_GR (ret_reg,
118                     sim_io_open (CPU_STATE (current_cpu),
119                                    buf, PARM2));
120       free (buf);
121       break;
122 
123     case TARGET_NEWLIB_SYS_close:
124       SET_H_GR (ret_reg,
125                     sim_io_close (CPU_STATE (current_cpu), PARM1));
126       break;
127 
128     case TARGET_NEWLIB_SYS_time:
129       SET_H_GR (ret_reg, time (0));
130       break;
131 
132     default:
133       SET_H_GR (ret_reg, -1);
134     }
135 }
136 
137 void
do_break(SIM_CPU * current_cpu,PCADDR pc)138 do_break (SIM_CPU *current_cpu, PCADDR pc)
139 {
140   SIM_DESC sd = CPU_STATE (current_cpu);
141   sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
142 }
143 
144 /* The semantic code invokes this for invalid (unrecognized) instructions.  */
145 
146 SEM_PC
sim_engine_invalid_insn(SIM_CPU * current_cpu,IADDR cia,SEM_PC vpc)147 sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
148 {
149   SIM_DESC sd = CPU_STATE (current_cpu);
150   sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
151 
152   return vpc;
153 }
154 
155 
156 /* Process an address exception.  */
157 
158 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)159 iq2000_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia,
160                   unsigned int map, int nr_bytes, address_word addr,
161                   transfer_type transfer, sim_core_signals sig)
162 {
163   sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr,
164                        transfer, sig);
165 }
166 
167 
168 /* Initialize cycle counting for an insn.
169    FIRST_P is non-zero if this is the first insn in a set of parallel
170    insns.  */
171 
172 void
iq2000bf_model_insn_before(SIM_CPU * cpu,int first_p)173 iq2000bf_model_insn_before (SIM_CPU *cpu, int first_p)
174 {
175   /* Do nothing.  */
176 }
177 
178 
179 /* Record the cycles computed for an insn.
180    LAST_P is non-zero if this is the last insn in a set of parallel insns,
181    and we update the total cycle count.
182    CYCLES is the cycle count of the insn.  */
183 
184 void
iq2000bf_model_insn_after(SIM_CPU * cpu,int last_p,int cycles)185 iq2000bf_model_insn_after(SIM_CPU *cpu, int last_p, int cycles)
186 {
187   /* Do nothing.  */
188 }
189 
190 
191 int
iq2000bf_model_iq2000_u_exec(SIM_CPU * cpu,const IDESC * idesc,int unit_num,int referenced)192 iq2000bf_model_iq2000_u_exec (SIM_CPU *cpu, const IDESC *idesc,
193                                   int unit_num, int referenced)
194 {
195   return idesc->timing->units[unit_num].done;
196 }
197 
198 PCADDR
get_h_pc(SIM_CPU * cpu)199 get_h_pc (SIM_CPU *cpu)
200 {
201   return CPU_CGEN_HW(cpu)->h_pc;
202 }
203 
204 void
set_h_pc(SIM_CPU * cpu,PCADDR addr)205 set_h_pc (SIM_CPU *cpu, PCADDR addr)
206 {
207   CPU_CGEN_HW(cpu)->h_pc = addr | IQ2000_INSN_MASK;
208 }
209 
210 int
iq2000bf_fetch_register(SIM_CPU * cpu,int nr,void * buf,int len)211 iq2000bf_fetch_register (SIM_CPU *cpu, int nr, void *buf, int len)
212 {
213   if (nr >= GPR0_REGNUM
214       && nr < (GPR0_REGNUM + NR_GPR)
215       && len == 4)
216     {
217       *((uint32_t*)buf) =
218           H2T_4 (iq2000bf_h_gr_get (cpu, nr - GPR0_REGNUM));
219       return 4;
220     }
221   else if (nr == PC_REGNUM
222              && len == 4)
223     {
224       *((uint32_t*)buf) = H2T_4 (get_h_pc (cpu));
225       return 4;
226     }
227   else
228     return 0;
229 }
230 
231 int
iq2000bf_store_register(SIM_CPU * cpu,int nr,const void * buf,int len)232 iq2000bf_store_register (SIM_CPU *cpu, int nr, const void *buf, int len)
233 {
234   if (nr >= GPR0_REGNUM
235       && nr < (GPR0_REGNUM + NR_GPR)
236       && len == 4)
237     {
238       iq2000bf_h_gr_set (cpu, nr - GPR0_REGNUM, T2H_4 (*((uint32_t*)buf)));
239       return 4;
240     }
241   else if (nr == PC_REGNUM
242              && len == 4)
243     {
244       set_h_pc (cpu, T2H_4 (*((uint32_t*)buf)));
245       return 4;
246     }
247   else
248     return 0;
249 }
250