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