Home | History | Annotate | Line # | Download | only in or1k
traps.c revision 1.1.1.3
      1      1.1  christos /* OpenRISC exception, interrupts, syscall and trap support
      2  1.1.1.3  christos    Copyright (C) 2017-2023 Free Software Foundation, Inc.
      3      1.1  christos 
      4      1.1  christos    This file is part of GDB, the GNU debugger.
      5      1.1  christos 
      6      1.1  christos    This program is free software; you can redistribute it and/or modify
      7      1.1  christos    it under the terms of the GNU General Public License as published by
      8      1.1  christos    the Free Software Foundation; either version 3 of the License, or
      9      1.1  christos    (at your option) any later version.
     10      1.1  christos 
     11      1.1  christos    This program is distributed in the hope that it will be useful,
     12      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14      1.1  christos    GNU General Public License for more details.
     15      1.1  christos 
     16      1.1  christos    You should have received a copy of the GNU General Public License
     17      1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     18      1.1  christos 
     19  1.1.1.3  christos /* This must come before any other includes.  */
     20  1.1.1.3  christos #include "defs.h"
     21  1.1.1.3  christos 
     22      1.1  christos #define WANT_CPU_OR1K32BF
     23      1.1  christos #define WANT_CPU
     24      1.1  christos 
     25      1.1  christos #include "sim-main.h"
     26  1.1.1.3  christos #include "sim-signal.h"
     27      1.1  christos #include "cgen-ops.h"
     28      1.1  christos 
     29      1.1  christos /* Implement the sim invalid instruction function.  This will set the error
     30      1.1  christos    effective address to that of the invalid instruction then call the
     31      1.1  christos    exception handler.  */
     32      1.1  christos 
     33      1.1  christos SEM_PC
     34      1.1  christos sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
     35      1.1  christos {
     36      1.1  christos   SET_H_SYS_EEAR0 (cia);
     37      1.1  christos 
     38      1.1  christos #ifdef WANT_CPU_OR1K32BF
     39      1.1  christos   or1k32bf_exception (current_cpu, cia, EXCEPT_ILLEGAL);
     40      1.1  christos #endif
     41      1.1  christos 
     42      1.1  christos   return vpc;
     43      1.1  christos }
     44      1.1  christos 
     45      1.1  christos /* Generate the appropriate OpenRISC fpu exception based on the status code from
     46      1.1  christos    the sim fpu.  */
     47      1.1  christos void
     48      1.1  christos or1k32bf_fpu_error (CGEN_FPU* fpu, int status)
     49      1.1  christos {
     50      1.1  christos   SIM_CPU *current_cpu = (SIM_CPU *)fpu->owner;
     51      1.1  christos 
     52      1.1  christos   /* If floating point exceptions are enabled.  */
     53      1.1  christos   if (GET_H_SYS_FPCSR_FPEE() != 0)
     54      1.1  christos     {
     55      1.1  christos       /* Set all of the status flag bits.  */
     56      1.1  christos       if (status
     57      1.1  christos 	  & (sim_fpu_status_invalid_snan
     58      1.1  christos 	     | sim_fpu_status_invalid_qnan
     59      1.1  christos 	     | sim_fpu_status_invalid_isi
     60      1.1  christos 	     | sim_fpu_status_invalid_idi
     61      1.1  christos 	     | sim_fpu_status_invalid_zdz
     62      1.1  christos 	     | sim_fpu_status_invalid_imz
     63      1.1  christos 	     | sim_fpu_status_invalid_cvi
     64      1.1  christos 	     | sim_fpu_status_invalid_cmp
     65      1.1  christos 	     | sim_fpu_status_invalid_sqrt))
     66      1.1  christos 	SET_H_SYS_FPCSR_IVF (1);
     67      1.1  christos 
     68      1.1  christos       if (status & sim_fpu_status_invalid_snan)
     69      1.1  christos 	SET_H_SYS_FPCSR_SNF (1);
     70      1.1  christos 
     71      1.1  christos       if (status & sim_fpu_status_invalid_qnan)
     72      1.1  christos 	SET_H_SYS_FPCSR_QNF (1);
     73      1.1  christos 
     74      1.1  christos       if (status & sim_fpu_status_overflow)
     75      1.1  christos 	SET_H_SYS_FPCSR_OVF (1);
     76      1.1  christos 
     77      1.1  christos       if (status & sim_fpu_status_underflow)
     78      1.1  christos 	SET_H_SYS_FPCSR_UNF (1);
     79      1.1  christos 
     80      1.1  christos       if (status
     81      1.1  christos 	  & (sim_fpu_status_invalid_isi
     82      1.1  christos 	     | sim_fpu_status_invalid_idi))
     83      1.1  christos 	SET_H_SYS_FPCSR_INF (1);
     84      1.1  christos 
     85      1.1  christos       if (status & sim_fpu_status_invalid_div0)
     86      1.1  christos 	SET_H_SYS_FPCSR_DZF (1);
     87      1.1  christos 
     88      1.1  christos       if (status & sim_fpu_status_inexact)
     89      1.1  christos 	SET_H_SYS_FPCSR_IXF (1);
     90      1.1  christos 
     91      1.1  christos       /* If any of the exception bits were actually set.  */
     92      1.1  christos       if (GET_H_SYS_FPCSR()
     93      1.1  christos 	  & (SPR_FIELD_MASK_SYS_FPCSR_IVF
     94      1.1  christos 	     | SPR_FIELD_MASK_SYS_FPCSR_SNF
     95      1.1  christos 	     | SPR_FIELD_MASK_SYS_FPCSR_QNF
     96      1.1  christos 	     | SPR_FIELD_MASK_SYS_FPCSR_OVF
     97      1.1  christos 	     | SPR_FIELD_MASK_SYS_FPCSR_UNF
     98      1.1  christos 	     | SPR_FIELD_MASK_SYS_FPCSR_INF
     99      1.1  christos 	     | SPR_FIELD_MASK_SYS_FPCSR_DZF
    100      1.1  christos 	     | SPR_FIELD_MASK_SYS_FPCSR_IXF))
    101      1.1  christos 	{
    102      1.1  christos 	  SIM_DESC sd = CPU_STATE (current_cpu);
    103      1.1  christos 
    104      1.1  christos 	  /* If the sim is running in fast mode, i.e. not profiling,
    105      1.1  christos 	     per-instruction callbacks are not triggered which would allow
    106      1.1  christos 	     us to track the PC.  This means we cannot track which
    107      1.1  christos 	     instruction caused the FPU error.  */
    108  1.1.1.3  christos 	  if (!PROFILE_ANY_P (current_cpu) && !TRACE_ANY_P (current_cpu))
    109      1.1  christos 	    sim_io_eprintf
    110      1.1  christos 	      (sd, "WARNING: ignoring fpu error caught in fast mode.\n");
    111      1.1  christos 	  else
    112      1.1  christos 	    or1k32bf_exception (current_cpu, GET_H_SYS_PPC (), EXCEPT_FPE);
    113      1.1  christos 	}
    114      1.1  christos     }
    115      1.1  christos }
    116      1.1  christos 
    117      1.1  christos 
    118      1.1  christos /* Implement the OpenRISC exception function.  This is mostly used by the
    119      1.1  christos    CGEN generated files.  For example, this is used when handling a
    120      1.1  christos    overflow exception during a multiplication instruction. */
    121      1.1  christos 
    122      1.1  christos void
    123      1.1  christos or1k32bf_exception (sim_cpu *current_cpu, USI pc, USI exnum)
    124      1.1  christos {
    125      1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    126      1.1  christos 
    127      1.1  christos   if (exnum == EXCEPT_TRAP)
    128      1.1  christos     {
    129      1.1  christos       /* Trap, used for breakpoints, sends control back to gdb breakpoint
    130      1.1  christos 	 handling.  */
    131      1.1  christos       sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
    132      1.1  christos     }
    133      1.1  christos   else
    134      1.1  christos     {
    135  1.1.1.3  christos       IADDR handler_pc;
    136      1.1  christos 
    137      1.1  christos       /* Calculate the exception program counter.  */
    138      1.1  christos       switch (exnum)
    139      1.1  christos 	{
    140      1.1  christos 	case EXCEPT_RESET:
    141      1.1  christos 	  break;
    142      1.1  christos 
    143      1.1  christos 	case EXCEPT_FPE:
    144      1.1  christos 	case EXCEPT_SYSCALL:
    145      1.1  christos 	  SET_H_SYS_EPCR0 (pc + 4 - (current_cpu->delay_slot ? 4 : 0));
    146      1.1  christos 	  break;
    147      1.1  christos 
    148      1.1  christos 	case EXCEPT_BUSERR:
    149      1.1  christos 	case EXCEPT_ALIGN:
    150      1.1  christos 	case EXCEPT_ILLEGAL:
    151      1.1  christos 	case EXCEPT_RANGE:
    152      1.1  christos 	  SET_H_SYS_EPCR0 (pc - (current_cpu->delay_slot ? 4 : 0));
    153      1.1  christos 	  break;
    154      1.1  christos 
    155      1.1  christos 	default:
    156      1.1  christos 	  sim_io_error (sd, "unexpected exception 0x%x raised at PC 0x%08x",
    157      1.1  christos 			exnum, pc);
    158      1.1  christos 	  break;
    159      1.1  christos 	}
    160      1.1  christos 
    161      1.1  christos       /* Store the current SR into ESR0.  */
    162      1.1  christos       SET_H_SYS_ESR0 (GET_H_SYS_SR ());
    163      1.1  christos 
    164      1.1  christos       /* Indicate in SR if the failed instruction is in delay slot or not.  */
    165      1.1  christos       SET_H_SYS_SR_DSX (current_cpu->delay_slot);
    166      1.1  christos 
    167      1.1  christos       current_cpu->next_delay_slot = 0;
    168      1.1  christos 
    169      1.1  christos       /* Jump program counter into handler.  */
    170  1.1.1.3  christos       handler_pc =
    171  1.1.1.3  christos 	(GET_H_SYS_SR_EPH () ? 0xf0000000 : 0x00000000) + (exnum << 8);
    172      1.1  christos 
    173      1.1  christos       sim_engine_restart (sd, current_cpu, NULL, handler_pc);
    174      1.1  christos     }
    175      1.1  christos }
    176      1.1  christos 
    177      1.1  christos /* Implement the return from exception instruction.  This is used to return
    178      1.1  christos    the CPU to its previous state from within an exception handler.  */
    179      1.1  christos 
    180      1.1  christos void
    181      1.1  christos or1k32bf_rfe (sim_cpu *current_cpu)
    182      1.1  christos {
    183      1.1  christos   SET_H_SYS_SR (GET_H_SYS_ESR0 ());
    184      1.1  christos   SET_H_SYS_SR_FO (1);
    185      1.1  christos 
    186      1.1  christos   current_cpu->next_delay_slot = 0;
    187      1.1  christos 
    188      1.1  christos   sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL,
    189      1.1  christos 		      GET_H_SYS_EPCR0 ());
    190      1.1  christos }
    191      1.1  christos 
    192      1.1  christos /* Implement the move from SPR instruction.  This is used to read from the
    193      1.1  christos    CPU's special purpose registers.  */
    194      1.1  christos 
    195      1.1  christos USI
    196      1.1  christos or1k32bf_mfspr (sim_cpu *current_cpu, USI addr)
    197      1.1  christos {
    198      1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    199  1.1.1.3  christos   SI val;
    200      1.1  christos 
    201      1.1  christos   if (!GET_H_SYS_SR_SM () && !GET_H_SYS_SR_SUMRA ())
    202      1.1  christos     {
    203      1.1  christos       sim_io_eprintf (sd, "WARNING: l.mfspr in user mode (SR 0x%x)\n",
    204      1.1  christos 		      GET_H_SYS_SR ());
    205      1.1  christos       return 0;
    206      1.1  christos     }
    207      1.1  christos 
    208      1.1  christos   if (addr >= NUM_SPR)
    209      1.1  christos     goto bad_address;
    210      1.1  christos 
    211  1.1.1.3  christos   val = GET_H_SPR (addr);
    212      1.1  christos 
    213      1.1  christos   switch (addr)
    214      1.1  christos     {
    215      1.1  christos 
    216      1.1  christos     case SPR_ADDR (SYS, VR):
    217      1.1  christos     case SPR_ADDR (SYS, UPR):
    218      1.1  christos     case SPR_ADDR (SYS, CPUCFGR):
    219      1.1  christos     case SPR_ADDR (SYS, SR):
    220      1.1  christos     case SPR_ADDR (SYS, PPC):
    221      1.1  christos     case SPR_ADDR (SYS, FPCSR):
    222      1.1  christos     case SPR_ADDR (SYS, EPCR0):
    223      1.1  christos     case SPR_ADDR (MAC, MACLO):
    224      1.1  christos     case SPR_ADDR (MAC, MACHI):
    225      1.1  christos       break;
    226      1.1  christos 
    227      1.1  christos     default:
    228      1.1  christos       if (addr < SPR_ADDR (SYS, GPR0) || addr > SPR_ADDR (SYS, GPR511))
    229      1.1  christos 	goto bad_address;
    230      1.1  christos       break;
    231      1.1  christos 
    232      1.1  christos     }
    233      1.1  christos 
    234      1.1  christos   return val;
    235      1.1  christos 
    236      1.1  christos bad_address:
    237      1.1  christos   sim_io_eprintf (sd, "WARNING: l.mfspr with invalid SPR address 0x%x\n", addr);
    238      1.1  christos   return 0;
    239      1.1  christos 
    240      1.1  christos }
    241      1.1  christos 
    242      1.1  christos /* Implement the move to SPR instruction.  This is used to write too the
    243      1.1  christos    CPU's special purpose registers.  */
    244      1.1  christos 
    245      1.1  christos void
    246      1.1  christos or1k32bf_mtspr (sim_cpu *current_cpu, USI addr, USI val)
    247      1.1  christos {
    248      1.1  christos   SIM_DESC sd = CPU_STATE (current_cpu);
    249      1.1  christos 
    250      1.1  christos   if (!GET_H_SYS_SR_SM () && !GET_H_SYS_SR_SUMRA ())
    251      1.1  christos     {
    252      1.1  christos       sim_io_eprintf
    253      1.1  christos 	(sd, "WARNING: l.mtspr with address 0x%x in user mode (SR 0x%x)\n",
    254      1.1  christos 	 addr, GET_H_SYS_SR ());
    255      1.1  christos       return;
    256      1.1  christos     }
    257      1.1  christos 
    258      1.1  christos   if (addr >= NUM_SPR)
    259      1.1  christos     goto bad_address;
    260      1.1  christos 
    261      1.1  christos   switch (addr)
    262      1.1  christos     {
    263      1.1  christos 
    264      1.1  christos     case SPR_ADDR (SYS, FPCSR):
    265      1.1  christos     case SPR_ADDR (SYS, EPCR0):
    266      1.1  christos     case SPR_ADDR (SYS, ESR0):
    267      1.1  christos     case SPR_ADDR (MAC, MACHI):
    268      1.1  christos     case SPR_ADDR (MAC, MACLO):
    269      1.1  christos       SET_H_SPR (addr, val);
    270      1.1  christos       break;
    271      1.1  christos 
    272      1.1  christos     case SPR_ADDR (SYS, SR):
    273      1.1  christos       SET_H_SPR (addr, val);
    274      1.1  christos       SET_H_SYS_SR_FO (1);
    275      1.1  christos       break;
    276      1.1  christos 
    277      1.1  christos     case SPR_ADDR (SYS, NPC):
    278      1.1  christos       current_cpu->next_delay_slot = 0;
    279      1.1  christos 
    280      1.1  christos       sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL, val);
    281      1.1  christos       break;
    282      1.1  christos 
    283      1.1  christos     case SPR_ADDR (TICK, TTMR):
    284      1.1  christos       /* Allow some registers to be silently cleared.  */
    285      1.1  christos       if (val != 0)
    286      1.1  christos 	sim_io_eprintf
    287      1.1  christos 	  (sd, "WARNING: l.mtspr to SPR address 0x%x with invalid value 0x%x\n",
    288      1.1  christos 	   addr, val);
    289      1.1  christos       break;
    290      1.1  christos 
    291      1.1  christos     default:
    292      1.1  christos       if (addr >= SPR_ADDR (SYS, GPR0) && addr <= SPR_ADDR (SYS, GPR511))
    293      1.1  christos 	SET_H_SPR (addr, val);
    294      1.1  christos       else
    295      1.1  christos 	goto bad_address;
    296      1.1  christos       break;
    297      1.1  christos 
    298      1.1  christos     }
    299      1.1  christos 
    300      1.1  christos   return;
    301      1.1  christos 
    302      1.1  christos bad_address:
    303      1.1  christos   sim_io_eprintf (sd, "WARNING: l.mtspr with invalid SPR address 0x%x\n", addr);
    304      1.1  christos 
    305      1.1  christos }
    306