xref: /netbsd-src/external/gpl3/gdb.old/dist/sim/lm32/traps.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1a5a4af3bSchristos /* Lattice Mico32 exception and system call support.
2a5a4af3bSchristos    Contributed by Jon Beniston <jon@beniston.com>
3a5a4af3bSchristos 
4*8b657b07Schristos    Copyright (C) 2009-2023 Free Software Foundation, Inc.
5a5a4af3bSchristos 
6a5a4af3bSchristos    This file is part of GDB.
7a5a4af3bSchristos 
8a5a4af3bSchristos    This program is free software; you can redistribute it and/or modify
9a5a4af3bSchristos    it under the terms of the GNU General Public License as published by
10a5a4af3bSchristos    the Free Software Foundation; either version 3 of the License, or
11a5a4af3bSchristos    (at your option) any later version.
12a5a4af3bSchristos 
13a5a4af3bSchristos    This program is distributed in the hope that it will be useful,
14a5a4af3bSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
15a5a4af3bSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16a5a4af3bSchristos    GNU General Public License for more details.
17a5a4af3bSchristos 
18a5a4af3bSchristos    You should have received a copy of the GNU General Public License
19a5a4af3bSchristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20a5a4af3bSchristos 
21*8b657b07Schristos /* This must come before any other includes.  */
22*8b657b07Schristos #include "defs.h"
23*8b657b07Schristos 
24a5a4af3bSchristos #define WANT_CPU lm32bf
25a5a4af3bSchristos #define WANT_CPU_LM32BF
26a5a4af3bSchristos 
27a5a4af3bSchristos #include "sim-main.h"
28*8b657b07Schristos #include "sim-signal.h"
29a5a4af3bSchristos #include "sim-syscall.h"
30a5a4af3bSchristos #include "lm32-sim.h"
31*8b657b07Schristos #include "target-newlib-syscall.h"
32a5a4af3bSchristos 
33a5a4af3bSchristos /* Handle invalid instructions.  */
34a5a4af3bSchristos 
35a5a4af3bSchristos SEM_PC
36a5a4af3bSchristos sim_engine_invalid_insn (SIM_CPU * current_cpu, IADDR cia, SEM_PC pc)
37a5a4af3bSchristos {
38a5a4af3bSchristos   SIM_DESC sd = CPU_STATE (current_cpu);
39a5a4af3bSchristos 
40a5a4af3bSchristos   sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
41a5a4af3bSchristos 
42a5a4af3bSchristos   return pc;
43a5a4af3bSchristos }
44a5a4af3bSchristos 
45a5a4af3bSchristos /* Handle divide instructions. */
46a5a4af3bSchristos 
47a5a4af3bSchristos USI
48a5a4af3bSchristos lm32bf_divu_insn (SIM_CPU * current_cpu, IADDR pc, USI r0, USI r1, USI r2)
49a5a4af3bSchristos {
50a5a4af3bSchristos   SIM_DESC sd = CPU_STATE (current_cpu);
51a5a4af3bSchristos   host_callback *cb = STATE_CALLBACK (sd);
52a5a4af3bSchristos 
53a5a4af3bSchristos   /* Check for divide by zero */
54a5a4af3bSchristos   if (GET_H_GR (r1) == 0)
55a5a4af3bSchristos     {
56a5a4af3bSchristos       if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
57a5a4af3bSchristos 	sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGFPE);
58a5a4af3bSchristos       else
59a5a4af3bSchristos 	{
60a5a4af3bSchristos 	  /* Save PC in exception address register.  */
61a5a4af3bSchristos 	  SET_H_GR (30, pc);
62a5a4af3bSchristos 	  /* Save and clear interrupt enable.  */
63a5a4af3bSchristos 	  SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1);
64a5a4af3bSchristos 	  /* Branch to divide by zero exception handler.  */
65a5a4af3bSchristos 	  return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DIVIDE_BY_ZERO * 32;
66a5a4af3bSchristos 	}
67a5a4af3bSchristos     }
68a5a4af3bSchristos   else
69a5a4af3bSchristos     {
70a5a4af3bSchristos       SET_H_GR (r2, (USI) GET_H_GR (r0) / (USI) GET_H_GR (r1));
71a5a4af3bSchristos       return pc + 4;
72a5a4af3bSchristos     }
73a5a4af3bSchristos }
74a5a4af3bSchristos 
75a5a4af3bSchristos USI
76a5a4af3bSchristos lm32bf_modu_insn (SIM_CPU * current_cpu, IADDR pc, USI r0, USI r1, USI r2)
77a5a4af3bSchristos {
78a5a4af3bSchristos   SIM_DESC sd = CPU_STATE (current_cpu);
79a5a4af3bSchristos   host_callback *cb = STATE_CALLBACK (sd);
80a5a4af3bSchristos 
81a5a4af3bSchristos   /* Check for divide by zero.  */
82a5a4af3bSchristos   if (GET_H_GR (r1) == 0)
83a5a4af3bSchristos     {
84a5a4af3bSchristos       if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
85a5a4af3bSchristos 	sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGFPE);
86a5a4af3bSchristos       else
87a5a4af3bSchristos 	{
88a5a4af3bSchristos 	  /* Save PC in exception address register.  */
89a5a4af3bSchristos 	  SET_H_GR (30, pc);
90a5a4af3bSchristos 	  /* Save and clear interrupt enable.  */
91a5a4af3bSchristos 	  SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1);
92a5a4af3bSchristos 	  /* Branch to divide by zero exception handler.  */
93a5a4af3bSchristos 	  return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DIVIDE_BY_ZERO * 32;
94a5a4af3bSchristos 	}
95a5a4af3bSchristos     }
96a5a4af3bSchristos   else
97a5a4af3bSchristos     {
98a5a4af3bSchristos       SET_H_GR (r2, (USI) GET_H_GR (r0) % (USI) GET_H_GR (r1));
99a5a4af3bSchristos       return pc + 4;
100a5a4af3bSchristos     }
101a5a4af3bSchristos }
102a5a4af3bSchristos 
103a5a4af3bSchristos /* Handle break instructions.  */
104a5a4af3bSchristos 
105a5a4af3bSchristos USI
106a5a4af3bSchristos lm32bf_break_insn (SIM_CPU * current_cpu, IADDR pc)
107a5a4af3bSchristos {
108a5a4af3bSchristos   SIM_DESC sd = CPU_STATE (current_cpu);
109a5a4af3bSchristos   host_callback *cb = STATE_CALLBACK (sd);
110a5a4af3bSchristos   /* Breakpoint.  */
111a5a4af3bSchristos   if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
112a5a4af3bSchristos     {
113a5a4af3bSchristos       sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
114a5a4af3bSchristos       return pc;
115a5a4af3bSchristos     }
116a5a4af3bSchristos   else
117a5a4af3bSchristos     {
118a5a4af3bSchristos       /* Save PC in breakpoint address register.  */
119a5a4af3bSchristos       SET_H_GR (31, pc);
120a5a4af3bSchristos       /* Save and clear interrupt enable.  */
121a5a4af3bSchristos       SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 2);
122a5a4af3bSchristos       /* Branch to breakpoint exception handler.  */
123a5a4af3bSchristos       return GET_H_CSR (LM32_CSR_DEBA) + LM32_EID_BREAKPOINT * 32;
124a5a4af3bSchristos     }
125a5a4af3bSchristos }
126a5a4af3bSchristos 
127a5a4af3bSchristos /* Handle scall instructions.  */
128a5a4af3bSchristos 
129a5a4af3bSchristos USI
130a5a4af3bSchristos lm32bf_scall_insn (SIM_CPU * current_cpu, IADDR pc)
131a5a4af3bSchristos {
132a5a4af3bSchristos   SIM_DESC sd = CPU_STATE (current_cpu);
133a5a4af3bSchristos   host_callback *cb = STATE_CALLBACK (sd);
134a5a4af3bSchristos 
135a5a4af3bSchristos   if ((STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT)
136*8b657b07Schristos       || (GET_H_GR (8) == TARGET_NEWLIB_SYS_exit))
137a5a4af3bSchristos     {
138a5a4af3bSchristos       /* Delegate system call to host O/S.  */
139a5a4af3bSchristos       long result, result2;
140a5a4af3bSchristos       int errcode;
141a5a4af3bSchristos 
142a5a4af3bSchristos       /* Perform the system call.  */
143a5a4af3bSchristos       sim_syscall_multi (current_cpu, GET_H_GR (8), GET_H_GR (1), GET_H_GR (2),
144a5a4af3bSchristos 			 GET_H_GR (3), GET_H_GR (4), &result, &result2,
145a5a4af3bSchristos 			 &errcode);
146a5a4af3bSchristos       /* Store the return value in the CPU's registers.  */
147a5a4af3bSchristos       SET_H_GR (1, result);
148a5a4af3bSchristos       SET_H_GR (2, result2);
149a5a4af3bSchristos       SET_H_GR (3, errcode);
150a5a4af3bSchristos 
151a5a4af3bSchristos       /* Skip over scall instruction.  */
152a5a4af3bSchristos       return pc + 4;
153a5a4af3bSchristos     }
154a5a4af3bSchristos   else
155a5a4af3bSchristos     {
156a5a4af3bSchristos       /* Save PC in exception address register.  */
157a5a4af3bSchristos       SET_H_GR (30, pc);
158a5a4af3bSchristos       /* Save and clear interrupt enable */
159a5a4af3bSchristos       SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1);
160a5a4af3bSchristos       /* Branch to system call exception handler.  */
161a5a4af3bSchristos       return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_SYSTEM_CALL * 32;
162a5a4af3bSchristos     }
163a5a4af3bSchristos }
164a5a4af3bSchristos 
165a5a4af3bSchristos /* Handle b instructions.  */
166a5a4af3bSchristos 
167a5a4af3bSchristos USI
168a5a4af3bSchristos lm32bf_b_insn (SIM_CPU * current_cpu, USI r0, USI f_r0)
169a5a4af3bSchristos {
170a5a4af3bSchristos   SIM_DESC sd = CPU_STATE (current_cpu);
171a5a4af3bSchristos   host_callback *cb = STATE_CALLBACK (sd);
172a5a4af3bSchristos 
173a5a4af3bSchristos   /* Restore interrupt enable.  */
174a5a4af3bSchristos   if (f_r0 == 30)
175a5a4af3bSchristos     SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 2) >> 1);
176a5a4af3bSchristos   else if (f_r0 == 31)
177a5a4af3bSchristos     SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 4) >> 2);
178a5a4af3bSchristos   return r0;
179a5a4af3bSchristos }
180a5a4af3bSchristos 
181a5a4af3bSchristos /* Handle wcsr instructions.  */
182a5a4af3bSchristos 
183a5a4af3bSchristos void
184a5a4af3bSchristos lm32bf_wcsr_insn (SIM_CPU * current_cpu, USI f_csr, USI r1)
185a5a4af3bSchristos {
186a5a4af3bSchristos   SIM_DESC sd = CPU_STATE (current_cpu);
187a5a4af3bSchristos   host_callback *cb = STATE_CALLBACK (sd);
188a5a4af3bSchristos 
189a5a4af3bSchristos   /* Writing a 1 to IP CSR clears a bit, writing 0 has no effect.  */
190a5a4af3bSchristos   if (f_csr == LM32_CSR_IP)
191a5a4af3bSchristos     SET_H_CSR (f_csr, GET_H_CSR (f_csr) & ~r1);
192a5a4af3bSchristos   else
193a5a4af3bSchristos     SET_H_CSR (f_csr, r1);
194a5a4af3bSchristos }
195a5a4af3bSchristos 
196a5a4af3bSchristos /* Handle signals.  */
197a5a4af3bSchristos 
198a5a4af3bSchristos void
199a5a4af3bSchristos lm32_core_signal (SIM_DESC sd,
200a5a4af3bSchristos 		  sim_cpu * cpu,
201a5a4af3bSchristos 		  sim_cia cia,
202a5a4af3bSchristos 		  unsigned map,
203a5a4af3bSchristos 		  int nr_bytes,
204a5a4af3bSchristos 		  address_word addr,
205a5a4af3bSchristos 		  transfer_type transfer, sim_core_signals sig)
206a5a4af3bSchristos {
207a5a4af3bSchristos   const char *copy = (transfer == read_transfer ? "read" : "write");
208a5a4af3bSchristos   address_word ip = CIA_ADDR (cia);
209a5a4af3bSchristos   SIM_CPU *current_cpu = cpu;
210a5a4af3bSchristos 
211a5a4af3bSchristos   switch (sig)
212a5a4af3bSchristos     {
213a5a4af3bSchristos     case sim_core_unmapped_signal:
214a5a4af3bSchristos       sim_io_eprintf (sd,
215a5a4af3bSchristos 		      "core: %d byte %s to unmapped address 0x%lx at 0x%lx\n",
216a5a4af3bSchristos 		      nr_bytes, copy, (unsigned long) addr,
217a5a4af3bSchristos 		      (unsigned long) ip);
218a5a4af3bSchristos       SET_H_GR (30, ip);
219a5a4af3bSchristos       /* Save and clear interrupt enable.  */
220a5a4af3bSchristos       SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1);
221a5a4af3bSchristos       CPU_PC_SET (cpu, GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DATA_BUS_ERROR * 32);
222a5a4af3bSchristos       sim_engine_halt (sd, cpu, NULL, LM32_EID_DATA_BUS_ERROR * 32,
223a5a4af3bSchristos 		       sim_stopped, SIM_SIGSEGV);
224a5a4af3bSchristos       break;
225a5a4af3bSchristos     case sim_core_unaligned_signal:
226a5a4af3bSchristos       sim_io_eprintf (sd,
227a5a4af3bSchristos 		      "core: %d byte misaligned %s to address 0x%lx at 0x%lx\n",
228a5a4af3bSchristos 		      nr_bytes, copy, (unsigned long) addr,
229a5a4af3bSchristos 		      (unsigned long) ip);
230a5a4af3bSchristos       SET_H_GR (30, ip);
231a5a4af3bSchristos       /* Save and clear interrupt enable.  */
232a5a4af3bSchristos       SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1);
233a5a4af3bSchristos       CPU_PC_SET (cpu, GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DATA_BUS_ERROR * 32);
234a5a4af3bSchristos       sim_engine_halt (sd, cpu, NULL, LM32_EID_DATA_BUS_ERROR * 32,
235a5a4af3bSchristos 		       sim_stopped, SIM_SIGBUS);
236a5a4af3bSchristos       break;
237a5a4af3bSchristos     default:
238a5a4af3bSchristos       sim_engine_abort (sd, cpu, cia,
239a5a4af3bSchristos 			"sim_core_signal - internal error - bad switch");
240a5a4af3bSchristos     }
241a5a4af3bSchristos }
242