sim: replace CIA_{GET,SET} with CPU_PC_{GET,SET}
[external/binutils.git] / sim / lm32 / traps.c
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       CPU_PC_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       CPU_PC_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 }