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