1 /* CRIS base simulator support code 2 Copyright (C) 2004-2024 Free Software Foundation, Inc. 3 Contributed by Axis Communications. 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 /* The infrastructure is based on that of i960.c. */ 21 22 /* This must come before any other includes. */ 23 #include "defs.h" 24 25 #define WANT_CPU 26 27 #include "sim-main.h" 28 #include "cgen-mem.h" 29 #include "cgen-ops.h" 30 31 #include <stdlib.h> 32 33 #define MY(f) XCONCAT3(crisv,BASENUM,f) 34 35 /* Dispatcher for break insn. */ 36 37 USI 38 MY (f_break_handler) (SIM_CPU *cpu, USI breaknum, USI pc) 39 { 40 SIM_DESC sd = CPU_STATE (cpu); 41 USI ret = pc + 2; 42 43 MY (f_h_pc_set) (cpu, ret); 44 45 /* FIXME: Error out if IBR or ERP set. */ 46 switch (breaknum) 47 { 48 case 13: 49 MY (f_h_gr_set (cpu, 10, 50 cris_break_13_handler (cpu, 51 MY (f_h_gr_get (cpu, 9)), 52 MY (f_h_gr_get (cpu, 10)), 53 MY (f_h_gr_get (cpu, 11)), 54 MY (f_h_gr_get (cpu, 12)), 55 MY (f_h_gr_get (cpu, 13)), 56 MY (f_h_sr_get (cpu, 7)), 57 MY (f_h_sr_get (cpu, 11)), 58 pc))); 59 break; 60 61 case 14: 62 sim_io_printf (sd, "%x\n", MY (f_h_gr_get (cpu, 3))); 63 break; 64 65 case 15: 66 /* Re-use the Linux exit call. */ 67 cris_break_13_handler (cpu, /* TARGET_SYS_exit */ 1, 0, 68 0, 0, 0, 0, 0, pc); 69 70 /* This shouldn't be reached, but we can't mark break 13 as noreturn 71 since there are some calls which should return. */ 72 ATTRIBUTE_FALLTHROUGH; 73 74 default: 75 abort (); 76 } 77 78 return MY (f_h_pc_get) (cpu); 79 } 80 81 /* Accessor function for simulator internal use. 82 Note the contents of BUF are in target byte order. */ 83 84 int 85 MY (f_fetch_register) (SIM_CPU *current_cpu, int rn, void *buf, 86 int len ATTRIBUTE_UNUSED) 87 { 88 SETTSI (buf, XCONCAT3(crisv,BASENUM,f_h_gr_get) (current_cpu, rn)); 89 return -1; 90 } 91 92 /* Accessor function for simulator internal use. 93 Note the contents of BUF are in target byte order. */ 94 95 int 96 MY (f_store_register) (SIM_CPU *current_cpu, int rn, const void *buf, 97 int len ATTRIBUTE_UNUSED) 98 { 99 XCONCAT3(crisv,BASENUM,f_h_gr_set) (current_cpu, rn, GETTSI (buf)); 100 return -1; 101 } 102 103 #if WITH_PROFILE_MODEL_P 105 106 /* FIXME: Some of these should be inline or macros. Later. */ 107 108 /* Initialize cycle counting for an insn. 109 FIRST_P is non-zero if this is the first insn in a set of parallel 110 insns. */ 111 112 void 113 MY (f_model_insn_before) (SIM_CPU *current_cpu, int first_p ATTRIBUTE_UNUSED) 114 { 115 /* To give the impression that we actually know what PC is, we have to 116 dump register contents *before* the *next* insn, not after the 117 *previous* insn. Uhh... */ 118 119 /* FIXME: Move this to separate, overridable function. */ 120 if ((CPU_CRIS_MISC_PROFILE (current_cpu)->flags 121 & FLAG_CRIS_MISC_PROFILE_XSIM_TRACE) 122 #ifdef GET_H_INSN_PREFIXED_P 123 /* For versions with prefixed insns, trace the combination as 124 one insn. */ 125 && !GET_H_INSN_PREFIXED_P () 126 #endif 127 && 1) 128 { 129 int i; 130 char flags[7]; 131 uint64_t cycle_count; 132 133 SIM_DESC sd = CPU_STATE (current_cpu); 134 135 cris_trace_printf (sd, current_cpu, "%lx ", 136 0xffffffffUL & (unsigned long) (CPU (h_pc))); 137 138 for (i = 0; i < 15; i++) 139 cris_trace_printf (sd, current_cpu, "%lx ", 140 0xffffffffUL 141 & (unsigned long) (XCONCAT3(crisv,BASENUM, 142 f_h_gr_get) (current_cpu, 143 i))); 144 flags[0] = GET_H_IBIT () != 0 ? 'I' : 'i'; 145 flags[1] = GET_H_XBIT () != 0 ? 'X' : 'x'; 146 flags[2] = GET_H_NBIT () != 0 ? 'N' : 'n'; 147 flags[3] = GET_H_ZBIT () != 0 ? 'Z' : 'z'; 148 flags[4] = GET_H_VBIT () != 0 ? 'V' : 'v'; 149 flags[5] = GET_H_CBIT () != 0 ? 'C' : 'c'; 150 flags[6] = 0; 151 152 /* For anything else than basic tracing we'd add stall cycles for 153 e.g. unaligned accesses. FIXME: add --cris-trace=x options to 154 match --cris-cycles=x. */ 155 cycle_count 156 = (CPU_CRIS_MISC_PROFILE (current_cpu)->basic_cycle_count 157 - CPU_CRIS_PREV_MISC_PROFILE (current_cpu)->basic_cycle_count); 158 159 /* Emit ACR after flags and cycle count for this insn. */ 160 if (BASENUM == 32) 161 cris_trace_printf (sd, current_cpu, "%s %d %lx\n", flags, 162 (int) cycle_count, 163 0xffffffffUL 164 & (unsigned long) (XCONCAT3(crisv,BASENUM, 165 f_h_gr_get) (current_cpu, 166 15))); 167 else 168 cris_trace_printf (sd, current_cpu, "%s %d\n", flags, 169 (int) cycle_count); 170 171 CPU_CRIS_PREV_MISC_PROFILE (current_cpu)[0] 172 = CPU_CRIS_MISC_PROFILE (current_cpu)[0]; 173 } 174 } 175 176 /* Record the cycles computed for an insn. 177 LAST_P is non-zero if this is the last insn in a set of parallel insns, 178 and we update the total cycle count. 179 CYCLES is the cycle count of the insn. */ 180 181 void 182 MY (f_model_insn_after) (SIM_CPU *current_cpu, int last_p ATTRIBUTE_UNUSED, 183 int cycles) 184 { 185 PROFILE_DATA *p = CPU_PROFILE_DATA (current_cpu); 186 187 PROFILE_MODEL_TOTAL_CYCLES (p) += cycles; 188 CPU_CRIS_MISC_PROFILE (current_cpu)->basic_cycle_count += cycles; 189 PROFILE_MODEL_CUR_INSN_CYCLES (p) = cycles; 190 191 #if WITH_HW 192 /* For some reason, we don't get to the sim_events_tick call in 193 cgen-run.c:engine_run_1. Besides, more than one cycle has 194 passed, so we want sim_events_tickn anyway. The "events we want 195 to process" is usually to initiate an interrupt, but might also 196 be other events. We can't do the former until the main loop is 197 at point where it accepts changing the PC without internal 198 inconsistency, so just set a flag and wait. */ 199 if (sim_events_tickn (CPU_STATE (current_cpu), cycles)) 200 STATE_EVENTS (CPU_STATE (current_cpu))->work_pending = 1; 201 #endif 202 } 203 204 #if 0 205 /* Initialize cycle counting for an insn. 206 FIRST_P is non-zero if this is the first insn in a set of parallel 207 insns. */ 208 209 void 210 MY (f_model_init_insn_cycles) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 211 int first_p ATTRIBUTE_UNUSED) 212 { 213 abort (); 214 } 215 216 /* Record the cycles computed for an insn. 217 LAST_P is non-zero if this is the last insn in a set of parallel insns, 218 and we update the total cycle count. */ 219 220 void 221 MY (f_model_update_insn_cycles) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 222 int last_p ATTRIBUTE_UNUSED) 223 { 224 abort (); 225 } 226 227 void 228 MY (f_model_record_cycles) (SIM_CPU *current_cpu, unsigned long cycles) 229 { 230 abort (); 231 } 232 233 void 234 MY (f_model_mark_get_h_gr) (SIM_CPU *current_cpu, ARGBUF *abuf) 235 { 236 abort (); 237 } 238 239 void 240 MY (f_model_mark_set_h_gr) (SIM_CPU *current_cpu, ARGBUF *abuf) 241 { 242 abort (); 243 } 244 #endif 245 246 /* Set the thread register contents. */ 248 249 static void 250 MY (set_target_thread_data) (SIM_CPU *current_cpu, USI val) 251 { 252 (CPU (XCONCAT2 (h_sr_v, BASENUM) [CRIS_TLS_REGISTER])) = val; 253 } 254 255 /* Create the context for a thread. */ 256 257 static void * 258 MY (make_thread_cpu_data) (SIM_CPU *current_cpu, void *context) 259 { 260 struct cris_sim_cpu *cris_cpu = CRIS_SIM_CPU (current_cpu); 261 void *info = xmalloc (cris_cpu->thread_cpu_data_size); 262 263 if (context != NULL) 264 memcpy (info, context, cris_cpu->thread_cpu_data_size); 265 else 266 memset (info, 0, cris_cpu->thread_cpu_data_size),abort(); 267 return info; 268 } 269 270 /* Placate -Wmissing-prototypes when mloop.in isn't used. */ 271 void MY (f_specific_init) (SIM_CPU *current_cpu); 272 273 /* Hook function for per-cpu simulator initialization. */ 274 275 void 276 MY (f_specific_init) (SIM_CPU *current_cpu) 277 { 278 struct cris_sim_cpu *cris_cpu = CRIS_SIM_CPU (current_cpu); 279 280 cris_cpu->make_thread_cpu_data = MY (make_thread_cpu_data); 281 cris_cpu->thread_cpu_data_size = sizeof (cris_cpu->cpu_data); 282 cris_cpu->set_target_thread_data = MY (set_target_thread_data); 283 #if WITH_HW 284 cris_cpu->deliver_interrupt = MY (deliver_interrupt); 285 #endif 286 } 287 288 /* Placate -Wmissing-prototypes when mloop.in isn't used. */ 290 int MY (XCONCAT3 (f_model_crisv,BASENUM, _u_stall)) 291 (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 292 const IDESC *idesc, 293 int unit_num, 294 int referenced ATTRIBUTE_UNUSED); 295 296 /* Model function for arbitrary single stall cycles. */ 297 298 int 299 MY (XCONCAT3 (f_model_crisv,BASENUM, 300 _u_stall)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 301 const IDESC *idesc, 302 int unit_num, 303 int referenced ATTRIBUTE_UNUSED) 304 { 305 return idesc->timing->units[unit_num].done; 306 } 307 308 #ifndef SPECIFIC_U_SKIP4_FN 309 310 /* Model function for u-skip4 unit. */ 311 312 int 313 MY (XCONCAT3 (f_model_crisv,BASENUM, 314 _u_skip4)) (SIM_CPU *current_cpu, 315 const IDESC *idesc, 316 int unit_num, 317 int referenced ATTRIBUTE_UNUSED) 318 { 319 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ 320 CPU (h_pc) += 4; 321 return idesc->timing->units[unit_num].done; 322 } 323 324 #endif 325 326 #ifndef SPECIFIC_U_EXEC_FN 327 328 /* Model function for u-exec unit. */ 329 330 int 331 MY (XCONCAT3 (f_model_crisv,BASENUM, 332 _u_exec)) (SIM_CPU *current_cpu, 333 const IDESC *idesc, 334 int unit_num, int referenced ATTRIBUTE_UNUSED) 335 { 336 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ 337 CPU (h_pc) += 2; 338 return idesc->timing->units[unit_num].done; 339 } 340 #endif 341 342 #ifndef SPECIFIC_U_MEM_FN 343 344 /* Model function for u-mem unit. */ 345 346 int 347 MY (XCONCAT3 (f_model_crisv,BASENUM, 348 _u_mem)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 349 const IDESC *idesc, 350 int unit_num, 351 int referenced ATTRIBUTE_UNUSED) 352 { 353 return idesc->timing->units[unit_num].done; 354 } 355 #endif 356 357 #ifndef SPECIFIC_U_CONST16_FN 358 359 /* Model function for u-const16 unit. */ 360 361 int 362 MY (XCONCAT3 (f_model_crisv,BASENUM, 363 _u_const16)) (SIM_CPU *current_cpu, 364 const IDESC *idesc, 365 int unit_num, 366 int referenced ATTRIBUTE_UNUSED) 367 { 368 CPU (h_pc) += 2; 369 return idesc->timing->units[unit_num].done; 370 } 371 #endif /* SPECIFIC_U_CONST16_FN */ 372 373 #ifndef SPECIFIC_U_CONST32_FN 374 375 /* This will be incorrect for early models, where a dword always take 376 two cycles. */ 377 #define CRIS_MODEL_MASK_PC_STALL 2 378 379 /* Model function for u-const32 unit. */ 380 381 int 382 MY (XCONCAT3 (f_model_crisv,BASENUM, 383 _u_const32)) (SIM_CPU *current_cpu, 384 const IDESC *idesc, 385 int unit_num, 386 int referenced ATTRIBUTE_UNUSED) 387 { 388 int unaligned_extra 389 = (((CPU (h_pc) + 2) & CRIS_MODEL_MASK_PC_STALL) 390 == CRIS_MODEL_MASK_PC_STALL); 391 392 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ 393 CPU_CRIS_MISC_PROFILE (current_cpu)->unaligned_mem_dword_count 394 += unaligned_extra; 395 396 CPU (h_pc) += 4; 397 return idesc->timing->units[unit_num].done; 398 } 399 #endif /* SPECIFIC_U_CONST32_FN */ 400 401 #ifndef SPECIFIC_U_MOVEM_FN 402 403 /* Model function for u-movem unit. */ 404 405 int 406 MY (XCONCAT3 (f_model_crisv,BASENUM, 407 _u_movem)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 408 const IDESC *idesc ATTRIBUTE_UNUSED, 409 int unit_num ATTRIBUTE_UNUSED, 410 int referenced ATTRIBUTE_UNUSED, 411 INT limreg) 412 { 413 /* FIXME: Add cycles for misalignment. */ 414 415 if (limreg == -1) 416 abort (); 417 418 /* We don't record movem move cycles in movemsrc_stall_count since 419 those cycles have historically been handled as ordinary cycles. */ 420 return limreg + 1; 421 } 422 #endif /* SPECIFIC_U_MOVEM_FN */ 423 424 #endif /* WITH_PROFILE_MODEL_P */ 425