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