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