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