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