Home | History | Annotate | Line # | Download | only in cris
      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