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 104 105 /* FIXME: Some of these should be inline or macros. Later. */ 106 107 /* Initialize cycle counting for an insn. 108 FIRST_P is non-zero if this is the first insn in a set of parallel 109 insns. */ 110 111 void 112 MY (f_model_insn_before) (SIM_CPU *current_cpu, int first_p ATTRIBUTE_UNUSED) 113 { 114 /* To give the impression that we actually know what PC is, we have to 115 dump register contents *before* the *next* insn, not after the 116 *previous* insn. Uhh... */ 117 118 /* FIXME: Move this to separate, overridable function. */ 119 if ((CPU_CRIS_MISC_PROFILE (current_cpu)->flags 120 & FLAG_CRIS_MISC_PROFILE_XSIM_TRACE) 121 #ifdef GET_H_INSN_PREFIXED_P 122 /* For versions with prefixed insns, trace the combination as 123 one insn. */ 124 && !GET_H_INSN_PREFIXED_P () 125 #endif 126 && 1) 127 { 128 int i; 129 char flags[7]; 130 uint64_t cycle_count; 131 132 SIM_DESC sd = CPU_STATE (current_cpu); 133 134 cris_trace_printf (sd, current_cpu, "%lx ", 135 0xffffffffUL & (unsigned long) (CPU (h_pc))); 136 137 for (i = 0; i < 15; i++) 138 cris_trace_printf (sd, current_cpu, "%lx ", 139 0xffffffffUL 140 & (unsigned long) (XCONCAT3(crisv,BASENUM, 141 f_h_gr_get) (current_cpu, 142 i))); 143 flags[0] = GET_H_IBIT () != 0 ? 'I' : 'i'; 144 flags[1] = GET_H_XBIT () != 0 ? 'X' : 'x'; 145 flags[2] = GET_H_NBIT () != 0 ? 'N' : 'n'; 146 flags[3] = GET_H_ZBIT () != 0 ? 'Z' : 'z'; 147 flags[4] = GET_H_VBIT () != 0 ? 'V' : 'v'; 148 flags[5] = GET_H_CBIT () != 0 ? 'C' : 'c'; 149 flags[6] = 0; 150 151 /* For anything else than basic tracing we'd add stall cycles for 152 e.g. unaligned accesses. FIXME: add --cris-trace=x options to 153 match --cris-cycles=x. */ 154 cycle_count 155 = (CPU_CRIS_MISC_PROFILE (current_cpu)->basic_cycle_count 156 - CPU_CRIS_PREV_MISC_PROFILE (current_cpu)->basic_cycle_count); 157 158 /* Emit ACR after flags and cycle count for this insn. */ 159 if (BASENUM == 32) 160 cris_trace_printf (sd, current_cpu, "%s %d %lx\n", flags, 161 (int) cycle_count, 162 0xffffffffUL 163 & (unsigned long) (XCONCAT3(crisv,BASENUM, 164 f_h_gr_get) (current_cpu, 165 15))); 166 else 167 cris_trace_printf (sd, current_cpu, "%s %d\n", flags, 168 (int) cycle_count); 169 170 CPU_CRIS_PREV_MISC_PROFILE (current_cpu)[0] 171 = CPU_CRIS_MISC_PROFILE (current_cpu)[0]; 172 } 173 } 174 175 /* Record the cycles computed for an insn. 176 LAST_P is non-zero if this is the last insn in a set of parallel insns, 177 and we update the total cycle count. 178 CYCLES is the cycle count of the insn. */ 179 180 void 181 MY (f_model_insn_after) (SIM_CPU *current_cpu, int last_p ATTRIBUTE_UNUSED, 182 int cycles) 183 { 184 PROFILE_DATA *p = CPU_PROFILE_DATA (current_cpu); 185 186 PROFILE_MODEL_TOTAL_CYCLES (p) += cycles; 187 CPU_CRIS_MISC_PROFILE (current_cpu)->basic_cycle_count += cycles; 188 PROFILE_MODEL_CUR_INSN_CYCLES (p) = cycles; 189 190 #if WITH_HW 191 /* For some reason, we don't get to the sim_events_tick call in 192 cgen-run.c:engine_run_1. Besides, more than one cycle has 193 passed, so we want sim_events_tickn anyway. The "events we want 194 to process" is usually to initiate an interrupt, but might also 195 be other events. We can't do the former until the main loop is 196 at point where it accepts changing the PC without internal 197 inconsistency, so just set a flag and wait. */ 198 if (sim_events_tickn (CPU_STATE (current_cpu), cycles)) 199 STATE_EVENTS (CPU_STATE (current_cpu))->work_pending = 1; 200 #endif 201 } 202 203 #if 0 204 /* Initialize cycle counting for an insn. 205 FIRST_P is non-zero if this is the first insn in a set of parallel 206 insns. */ 207 208 void 209 MY (f_model_init_insn_cycles) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 210 int first_p ATTRIBUTE_UNUSED) 211 { 212 abort (); 213 } 214 215 /* Record the cycles computed for an insn. 216 LAST_P is non-zero if this is the last insn in a set of parallel insns, 217 and we update the total cycle count. */ 218 219 void 220 MY (f_model_update_insn_cycles) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 221 int last_p ATTRIBUTE_UNUSED) 222 { 223 abort (); 224 } 225 226 void 227 MY (f_model_record_cycles) (SIM_CPU *current_cpu, unsigned long cycles) 228 { 229 abort (); 230 } 231 232 void 233 MY (f_model_mark_get_h_gr) (SIM_CPU *current_cpu, ARGBUF *abuf) 234 { 235 abort (); 236 } 237 238 void 239 MY (f_model_mark_set_h_gr) (SIM_CPU *current_cpu, ARGBUF *abuf) 240 { 241 abort (); 242 } 243 #endif 244 245 /* Set the thread register contents. */ 246 247 static void 248 MY (set_target_thread_data) (SIM_CPU *current_cpu, USI val) 249 { 250 (CPU (XCONCAT2 (h_sr_v, BASENUM) [CRIS_TLS_REGISTER])) = val; 251 } 252 253 /* Create the context for a thread. */ 254 255 static void * 256 MY (make_thread_cpu_data) (SIM_CPU *current_cpu, void *context) 257 { 258 struct cris_sim_cpu *cris_cpu = CRIS_SIM_CPU (current_cpu); 259 void *info = xmalloc (cris_cpu->thread_cpu_data_size); 260 261 if (context != NULL) 262 memcpy (info, context, cris_cpu->thread_cpu_data_size); 263 else 264 memset (info, 0, cris_cpu->thread_cpu_data_size),abort(); 265 return info; 266 } 267 268 /* Placate -Wmissing-prototypes when mloop.in isn't used. */ 269 void MY (f_specific_init) (SIM_CPU *current_cpu); 270 271 /* Hook function for per-cpu simulator initialization. */ 272 273 void 274 MY (f_specific_init) (SIM_CPU *current_cpu) 275 { 276 struct cris_sim_cpu *cris_cpu = CRIS_SIM_CPU (current_cpu); 277 278 cris_cpu->make_thread_cpu_data = MY (make_thread_cpu_data); 279 cris_cpu->thread_cpu_data_size = sizeof (cris_cpu->cpu_data); 280 cris_cpu->set_target_thread_data = MY (set_target_thread_data); 281 #if WITH_HW 282 cris_cpu->deliver_interrupt = MY (deliver_interrupt); 283 #endif 284 } 285 286 /* Placate -Wmissing-prototypes when mloop.in isn't used. */ 287 int MY (XCONCAT3 (f_model_crisv,BASENUM, _u_stall)) 288 (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 289 const IDESC *idesc, 290 int unit_num, 291 int referenced ATTRIBUTE_UNUSED); 292 293 /* Model function for arbitrary single stall cycles. */ 294 295 int 296 MY (XCONCAT3 (f_model_crisv,BASENUM, 297 _u_stall)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 298 const IDESC *idesc, 299 int unit_num, 300 int referenced ATTRIBUTE_UNUSED) 301 { 302 return idesc->timing->units[unit_num].done; 303 } 304 305 #ifndef SPECIFIC_U_SKIP4_FN 306 307 /* Model function for u-skip4 unit. */ 308 309 int 310 MY (XCONCAT3 (f_model_crisv,BASENUM, 311 _u_skip4)) (SIM_CPU *current_cpu, 312 const IDESC *idesc, 313 int unit_num, 314 int referenced ATTRIBUTE_UNUSED) 315 { 316 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ 317 CPU (h_pc) += 4; 318 return idesc->timing->units[unit_num].done; 319 } 320 321 #endif 322 323 #ifndef SPECIFIC_U_EXEC_FN 324 325 /* Model function for u-exec unit. */ 326 327 int 328 MY (XCONCAT3 (f_model_crisv,BASENUM, 329 _u_exec)) (SIM_CPU *current_cpu, 330 const IDESC *idesc, 331 int unit_num, int referenced ATTRIBUTE_UNUSED) 332 { 333 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ 334 CPU (h_pc) += 2; 335 return idesc->timing->units[unit_num].done; 336 } 337 #endif 338 339 #ifndef SPECIFIC_U_MEM_FN 340 341 /* Model function for u-mem unit. */ 342 343 int 344 MY (XCONCAT3 (f_model_crisv,BASENUM, 345 _u_mem)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 346 const IDESC *idesc, 347 int unit_num, 348 int referenced ATTRIBUTE_UNUSED) 349 { 350 return idesc->timing->units[unit_num].done; 351 } 352 #endif 353 354 #ifndef SPECIFIC_U_CONST16_FN 355 356 /* Model function for u-const16 unit. */ 357 358 int 359 MY (XCONCAT3 (f_model_crisv,BASENUM, 360 _u_const16)) (SIM_CPU *current_cpu, 361 const IDESC *idesc, 362 int unit_num, 363 int referenced ATTRIBUTE_UNUSED) 364 { 365 CPU (h_pc) += 2; 366 return idesc->timing->units[unit_num].done; 367 } 368 #endif /* SPECIFIC_U_CONST16_FN */ 369 370 #ifndef SPECIFIC_U_CONST32_FN 371 372 /* This will be incorrect for early models, where a dword always take 373 two cycles. */ 374 #define CRIS_MODEL_MASK_PC_STALL 2 375 376 /* Model function for u-const32 unit. */ 377 378 int 379 MY (XCONCAT3 (f_model_crisv,BASENUM, 380 _u_const32)) (SIM_CPU *current_cpu, 381 const IDESC *idesc, 382 int unit_num, 383 int referenced ATTRIBUTE_UNUSED) 384 { 385 int unaligned_extra 386 = (((CPU (h_pc) + 2) & CRIS_MODEL_MASK_PC_STALL) 387 == CRIS_MODEL_MASK_PC_STALL); 388 389 /* Handle PC not being updated with pbb. FIXME: What if not pbb? */ 390 CPU_CRIS_MISC_PROFILE (current_cpu)->unaligned_mem_dword_count 391 += unaligned_extra; 392 393 CPU (h_pc) += 4; 394 return idesc->timing->units[unit_num].done; 395 } 396 #endif /* SPECIFIC_U_CONST32_FN */ 397 398 #ifndef SPECIFIC_U_MOVEM_FN 399 400 /* Model function for u-movem unit. */ 401 402 int 403 MY (XCONCAT3 (f_model_crisv,BASENUM, 404 _u_movem)) (SIM_CPU *current_cpu ATTRIBUTE_UNUSED, 405 const IDESC *idesc ATTRIBUTE_UNUSED, 406 int unit_num ATTRIBUTE_UNUSED, 407 int referenced ATTRIBUTE_UNUSED, 408 INT limreg) 409 { 410 /* FIXME: Add cycles for misalignment. */ 411 412 if (limreg == -1) 413 abort (); 414 415 /* We don't record movem move cycles in movemsrc_stall_count since 416 those cycles have historically been handled as ordinary cycles. */ 417 return limreg + 1; 418 } 419 #endif /* SPECIFIC_U_MOVEM_FN */ 420 421 #endif /* WITH_PROFILE_MODEL_P */ 422