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