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