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 * 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 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 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 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 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 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 185 iq2000bf_model_insn_after(SIM_CPU *cpu, int last_p, int cycles) 186 { 187 /* Do nothing. */ 188 } 189 190 191 int 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 199 get_h_pc (SIM_CPU *cpu) 200 { 201 return CPU_CGEN_HW(cpu)->h_pc; 202 } 203 204 void 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 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 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