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