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