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