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