1 /* Lattice Mico32 exception and system call support. 2 Contributed by Jon Beniston <jon@beniston.com> 3 4 Copyright (C) 2009-2019 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 "sim-syscall.h" 26 #include "lm32-sim.h" 27 #include "targ-vals.h" 28 29 /* Handle invalid instructions. */ 30 31 SEM_PC 32 sim_engine_invalid_insn (SIM_CPU * current_cpu, IADDR cia, SEM_PC pc) 33 { 34 SIM_DESC sd = CPU_STATE (current_cpu); 35 36 sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL); 37 38 return pc; 39 } 40 41 /* Handle divide instructions. */ 42 43 USI 44 lm32bf_divu_insn (SIM_CPU * current_cpu, IADDR pc, USI r0, USI r1, USI r2) 45 { 46 SIM_DESC sd = CPU_STATE (current_cpu); 47 host_callback *cb = STATE_CALLBACK (sd); 48 49 /* Check for divide by zero */ 50 if (GET_H_GR (r1) == 0) 51 { 52 if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT) 53 sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGFPE); 54 else 55 { 56 /* Save PC in exception address register. */ 57 SET_H_GR (30, pc); 58 /* Save and clear interrupt enable. */ 59 SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1); 60 /* Branch to divide by zero exception handler. */ 61 return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DIVIDE_BY_ZERO * 32; 62 } 63 } 64 else 65 { 66 SET_H_GR (r2, (USI) GET_H_GR (r0) / (USI) GET_H_GR (r1)); 67 return pc + 4; 68 } 69 } 70 71 USI 72 lm32bf_modu_insn (SIM_CPU * current_cpu, IADDR pc, USI r0, USI r1, USI r2) 73 { 74 SIM_DESC sd = CPU_STATE (current_cpu); 75 host_callback *cb = STATE_CALLBACK (sd); 76 77 /* Check for divide by zero. */ 78 if (GET_H_GR (r1) == 0) 79 { 80 if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT) 81 sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGFPE); 82 else 83 { 84 /* Save PC in exception address register. */ 85 SET_H_GR (30, pc); 86 /* Save and clear interrupt enable. */ 87 SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1); 88 /* Branch to divide by zero exception handler. */ 89 return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DIVIDE_BY_ZERO * 32; 90 } 91 } 92 else 93 { 94 SET_H_GR (r2, (USI) GET_H_GR (r0) % (USI) GET_H_GR (r1)); 95 return pc + 4; 96 } 97 } 98 99 /* Handle break instructions. */ 100 101 USI 102 lm32bf_break_insn (SIM_CPU * current_cpu, IADDR pc) 103 { 104 SIM_DESC sd = CPU_STATE (current_cpu); 105 host_callback *cb = STATE_CALLBACK (sd); 106 /* Breakpoint. */ 107 if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT) 108 { 109 sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP); 110 return pc; 111 } 112 else 113 { 114 /* Save PC in breakpoint address register. */ 115 SET_H_GR (31, pc); 116 /* Save and clear interrupt enable. */ 117 SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 2); 118 /* Branch to breakpoint exception handler. */ 119 return GET_H_CSR (LM32_CSR_DEBA) + LM32_EID_BREAKPOINT * 32; 120 } 121 } 122 123 /* Handle scall instructions. */ 124 125 USI 126 lm32bf_scall_insn (SIM_CPU * current_cpu, IADDR pc) 127 { 128 SIM_DESC sd = CPU_STATE (current_cpu); 129 host_callback *cb = STATE_CALLBACK (sd); 130 131 if ((STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT) 132 || (GET_H_GR (8) == TARGET_SYS_exit)) 133 { 134 /* Delegate system call to host O/S. */ 135 long result, result2; 136 int errcode; 137 138 /* Perform the system call. */ 139 sim_syscall_multi (current_cpu, GET_H_GR (8), GET_H_GR (1), GET_H_GR (2), 140 GET_H_GR (3), GET_H_GR (4), &result, &result2, 141 &errcode); 142 /* Store the return value in the CPU's registers. */ 143 SET_H_GR (1, result); 144 SET_H_GR (2, result2); 145 SET_H_GR (3, errcode); 146 147 /* Skip over scall instruction. */ 148 return pc + 4; 149 } 150 else 151 { 152 /* Save PC in exception address register. */ 153 SET_H_GR (30, pc); 154 /* Save and clear interrupt enable */ 155 SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1); 156 /* Branch to system call exception handler. */ 157 return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_SYSTEM_CALL * 32; 158 } 159 } 160 161 /* Handle b instructions. */ 162 163 USI 164 lm32bf_b_insn (SIM_CPU * current_cpu, USI r0, USI f_r0) 165 { 166 SIM_DESC sd = CPU_STATE (current_cpu); 167 host_callback *cb = STATE_CALLBACK (sd); 168 169 /* Restore interrupt enable. */ 170 if (f_r0 == 30) 171 SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 2) >> 1); 172 else if (f_r0 == 31) 173 SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 4) >> 2); 174 return r0; 175 } 176 177 /* Handle wcsr instructions. */ 178 179 void 180 lm32bf_wcsr_insn (SIM_CPU * current_cpu, USI f_csr, USI r1) 181 { 182 SIM_DESC sd = CPU_STATE (current_cpu); 183 host_callback *cb = STATE_CALLBACK (sd); 184 185 /* Writing a 1 to IP CSR clears a bit, writing 0 has no effect. */ 186 if (f_csr == LM32_CSR_IP) 187 SET_H_CSR (f_csr, GET_H_CSR (f_csr) & ~r1); 188 else 189 SET_H_CSR (f_csr, r1); 190 } 191 192 /* Handle signals. */ 193 194 void 195 lm32_core_signal (SIM_DESC sd, 196 sim_cpu * cpu, 197 sim_cia cia, 198 unsigned map, 199 int nr_bytes, 200 address_word addr, 201 transfer_type transfer, sim_core_signals sig) 202 { 203 const char *copy = (transfer == read_transfer ? "read" : "write"); 204 address_word ip = CIA_ADDR (cia); 205 SIM_CPU *current_cpu = cpu; 206 207 switch (sig) 208 { 209 case sim_core_unmapped_signal: 210 sim_io_eprintf (sd, 211 "core: %d byte %s to unmapped address 0x%lx at 0x%lx\n", 212 nr_bytes, copy, (unsigned long) addr, 213 (unsigned long) ip); 214 SET_H_GR (30, ip); 215 /* Save and clear interrupt enable. */ 216 SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1); 217 CPU_PC_SET (cpu, GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DATA_BUS_ERROR * 32); 218 sim_engine_halt (sd, cpu, NULL, LM32_EID_DATA_BUS_ERROR * 32, 219 sim_stopped, SIM_SIGSEGV); 220 break; 221 case sim_core_unaligned_signal: 222 sim_io_eprintf (sd, 223 "core: %d byte misaligned %s to address 0x%lx at 0x%lx\n", 224 nr_bytes, copy, (unsigned long) addr, 225 (unsigned long) ip); 226 SET_H_GR (30, ip); 227 /* Save and clear interrupt enable. */ 228 SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1); 229 CPU_PC_SET (cpu, GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DATA_BUS_ERROR * 32); 230 sim_engine_halt (sd, cpu, NULL, LM32_EID_DATA_BUS_ERROR * 32, 231 sim_stopped, SIM_SIGBUS); 232 break; 233 default: 234 sim_engine_abort (sd, cpu, cia, 235 "sim_core_signal - internal error - bad switch"); 236 } 237 } 238