14e98e3e1Schristos /* Lattice Mico32 exception and system call support. 24e98e3e1Schristos Contributed by Jon Beniston <jon@beniston.com> 34e98e3e1Schristos 4*71f62182Schristos Copyright (C) 2009-2024 Free Software Foundation, Inc. 54e98e3e1Schristos 64e98e3e1Schristos This file is part of GDB. 74e98e3e1Schristos 84e98e3e1Schristos This program is free software; you can redistribute it and/or modify 94e98e3e1Schristos it under the terms of the GNU General Public License as published by 104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 114e98e3e1Schristos (at your option) any later version. 124e98e3e1Schristos 134e98e3e1Schristos This program is distributed in the hope that it will be useful, 144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 164e98e3e1Schristos GNU General Public License for more details. 174e98e3e1Schristos 184e98e3e1Schristos You should have received a copy of the GNU General Public License 194e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 204e98e3e1Schristos 214b169a6bSchristos /* This must come before any other includes. */ 224b169a6bSchristos #include "defs.h" 234b169a6bSchristos 244e98e3e1Schristos #define WANT_CPU lm32bf 254e98e3e1Schristos #define WANT_CPU_LM32BF 264e98e3e1Schristos 274e98e3e1Schristos #include "sim-main.h" 284b169a6bSchristos #include "sim-signal.h" 29212397c6Schristos #include "sim-syscall.h" 304e98e3e1Schristos #include "lm32-sim.h" 314b169a6bSchristos #include "target-newlib-syscall.h" 324e98e3e1Schristos 334e98e3e1Schristos /* Handle invalid instructions. */ 344e98e3e1Schristos 354e98e3e1Schristos SEM_PC 364e98e3e1Schristos sim_engine_invalid_insn (SIM_CPU * current_cpu, IADDR cia, SEM_PC pc) 374e98e3e1Schristos { 384e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 394e98e3e1Schristos 404e98e3e1Schristos sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL); 414e98e3e1Schristos 424e98e3e1Schristos return pc; 434e98e3e1Schristos } 444e98e3e1Schristos 454e98e3e1Schristos /* Handle divide instructions. */ 464e98e3e1Schristos 474e98e3e1Schristos USI 484e98e3e1Schristos lm32bf_divu_insn (SIM_CPU * current_cpu, IADDR pc, USI r0, USI r1, USI r2) 494e98e3e1Schristos { 504e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 514e98e3e1Schristos 524e98e3e1Schristos /* Check for divide by zero */ 534e98e3e1Schristos if (GET_H_GR (r1) == 0) 544e98e3e1Schristos { 554e98e3e1Schristos if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT) 564e98e3e1Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGFPE); 574e98e3e1Schristos else 584e98e3e1Schristos { 594e98e3e1Schristos /* Save PC in exception address register. */ 604e98e3e1Schristos SET_H_GR (30, pc); 614e98e3e1Schristos /* Save and clear interrupt enable. */ 624e98e3e1Schristos SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1); 634e98e3e1Schristos /* Branch to divide by zero exception handler. */ 644e98e3e1Schristos return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DIVIDE_BY_ZERO * 32; 654e98e3e1Schristos } 664e98e3e1Schristos } 674e98e3e1Schristos else 684e98e3e1Schristos { 694e98e3e1Schristos SET_H_GR (r2, (USI) GET_H_GR (r0) / (USI) GET_H_GR (r1)); 704e98e3e1Schristos return pc + 4; 714e98e3e1Schristos } 724e98e3e1Schristos } 734e98e3e1Schristos 744e98e3e1Schristos USI 754e98e3e1Schristos lm32bf_modu_insn (SIM_CPU * current_cpu, IADDR pc, USI r0, USI r1, USI r2) 764e98e3e1Schristos { 774e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 784e98e3e1Schristos 794e98e3e1Schristos /* Check for divide by zero. */ 804e98e3e1Schristos if (GET_H_GR (r1) == 0) 814e98e3e1Schristos { 824e98e3e1Schristos if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT) 834e98e3e1Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGFPE); 844e98e3e1Schristos else 854e98e3e1Schristos { 864e98e3e1Schristos /* Save PC in exception address register. */ 874e98e3e1Schristos SET_H_GR (30, pc); 884e98e3e1Schristos /* Save and clear interrupt enable. */ 894e98e3e1Schristos SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1); 904e98e3e1Schristos /* Branch to divide by zero exception handler. */ 914e98e3e1Schristos return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DIVIDE_BY_ZERO * 32; 924e98e3e1Schristos } 934e98e3e1Schristos } 944e98e3e1Schristos else 954e98e3e1Schristos { 964e98e3e1Schristos SET_H_GR (r2, (USI) GET_H_GR (r0) % (USI) GET_H_GR (r1)); 974e98e3e1Schristos return pc + 4; 984e98e3e1Schristos } 994e98e3e1Schristos } 1004e98e3e1Schristos 1014e98e3e1Schristos /* Handle break instructions. */ 1024e98e3e1Schristos 1034e98e3e1Schristos USI 1044e98e3e1Schristos lm32bf_break_insn (SIM_CPU * current_cpu, IADDR pc) 1054e98e3e1Schristos { 1064e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 107*71f62182Schristos 1084e98e3e1Schristos /* Breakpoint. */ 1094e98e3e1Schristos if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT) 1104e98e3e1Schristos { 1114e98e3e1Schristos sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP); 1124e98e3e1Schristos return pc; 1134e98e3e1Schristos } 1144e98e3e1Schristos else 1154e98e3e1Schristos { 1164e98e3e1Schristos /* Save PC in breakpoint address register. */ 1174e98e3e1Schristos SET_H_GR (31, pc); 1184e98e3e1Schristos /* Save and clear interrupt enable. */ 1194e98e3e1Schristos SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 2); 1204e98e3e1Schristos /* Branch to breakpoint exception handler. */ 1214e98e3e1Schristos return GET_H_CSR (LM32_CSR_DEBA) + LM32_EID_BREAKPOINT * 32; 1224e98e3e1Schristos } 1234e98e3e1Schristos } 1244e98e3e1Schristos 1254e98e3e1Schristos /* Handle scall instructions. */ 1264e98e3e1Schristos 1274e98e3e1Schristos USI 1284e98e3e1Schristos lm32bf_scall_insn (SIM_CPU * current_cpu, IADDR pc) 1294e98e3e1Schristos { 1304e98e3e1Schristos SIM_DESC sd = CPU_STATE (current_cpu); 1314e98e3e1Schristos 1324e98e3e1Schristos if ((STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT) 1334b169a6bSchristos || (GET_H_GR (8) == TARGET_NEWLIB_SYS_exit)) 1344e98e3e1Schristos { 1354e98e3e1Schristos /* Delegate system call to host O/S. */ 136212397c6Schristos long result, result2; 137212397c6Schristos int errcode; 138212397c6Schristos 1394e98e3e1Schristos /* Perform the system call. */ 140212397c6Schristos sim_syscall_multi (current_cpu, GET_H_GR (8), GET_H_GR (1), GET_H_GR (2), 141212397c6Schristos GET_H_GR (3), GET_H_GR (4), &result, &result2, 142212397c6Schristos &errcode); 1434e98e3e1Schristos /* Store the return value in the CPU's registers. */ 144212397c6Schristos SET_H_GR (1, result); 145212397c6Schristos SET_H_GR (2, result2); 146212397c6Schristos SET_H_GR (3, errcode); 147212397c6Schristos 1484e98e3e1Schristos /* Skip over scall instruction. */ 1494e98e3e1Schristos return pc + 4; 1504e98e3e1Schristos } 1514e98e3e1Schristos else 1524e98e3e1Schristos { 1534e98e3e1Schristos /* Save PC in exception address register. */ 1544e98e3e1Schristos SET_H_GR (30, pc); 1554e98e3e1Schristos /* Save and clear interrupt enable */ 1564e98e3e1Schristos SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1); 1574e98e3e1Schristos /* Branch to system call exception handler. */ 1584e98e3e1Schristos return GET_H_CSR (LM32_CSR_EBA) + LM32_EID_SYSTEM_CALL * 32; 1594e98e3e1Schristos } 1604e98e3e1Schristos } 1614e98e3e1Schristos 1624e98e3e1Schristos /* Handle b instructions. */ 1634e98e3e1Schristos 1644e98e3e1Schristos USI 1654e98e3e1Schristos lm32bf_b_insn (SIM_CPU * current_cpu, USI r0, USI f_r0) 1664e98e3e1Schristos { 1674e98e3e1Schristos /* Restore interrupt enable. */ 1684e98e3e1Schristos if (f_r0 == 30) 1694e98e3e1Schristos SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 2) >> 1); 1704e98e3e1Schristos else if (f_r0 == 31) 1714e98e3e1Schristos SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 4) >> 2); 1724e98e3e1Schristos return r0; 1734e98e3e1Schristos } 1744e98e3e1Schristos 1754e98e3e1Schristos /* Handle wcsr instructions. */ 1764e98e3e1Schristos 1774e98e3e1Schristos void 1784e98e3e1Schristos lm32bf_wcsr_insn (SIM_CPU * current_cpu, USI f_csr, USI r1) 1794e98e3e1Schristos { 1804e98e3e1Schristos /* Writing a 1 to IP CSR clears a bit, writing 0 has no effect. */ 1814e98e3e1Schristos if (f_csr == LM32_CSR_IP) 1824e98e3e1Schristos SET_H_CSR (f_csr, GET_H_CSR (f_csr) & ~r1); 1834e98e3e1Schristos else 1844e98e3e1Schristos SET_H_CSR (f_csr, r1); 1854e98e3e1Schristos } 1864e98e3e1Schristos 1874e98e3e1Schristos /* Handle signals. */ 1884e98e3e1Schristos 1894e98e3e1Schristos void 1904e98e3e1Schristos lm32_core_signal (SIM_DESC sd, 1914e98e3e1Schristos sim_cpu * cpu, 1924e98e3e1Schristos sim_cia cia, 1934e98e3e1Schristos unsigned map, 1944e98e3e1Schristos int nr_bytes, 1954e98e3e1Schristos address_word addr, 1964e98e3e1Schristos transfer_type transfer, sim_core_signals sig) 1974e98e3e1Schristos { 1984e98e3e1Schristos const char *copy = (transfer == read_transfer ? "read" : "write"); 1994e98e3e1Schristos address_word ip = CIA_ADDR (cia); 2004e98e3e1Schristos SIM_CPU *current_cpu = cpu; 2014e98e3e1Schristos 2024e98e3e1Schristos switch (sig) 2034e98e3e1Schristos { 2044e98e3e1Schristos case sim_core_unmapped_signal: 2054e98e3e1Schristos sim_io_eprintf (sd, 2064e98e3e1Schristos "core: %d byte %s to unmapped address 0x%lx at 0x%lx\n", 2074e98e3e1Schristos nr_bytes, copy, (unsigned long) addr, 2084e98e3e1Schristos (unsigned long) ip); 2094e98e3e1Schristos SET_H_GR (30, ip); 2104e98e3e1Schristos /* Save and clear interrupt enable. */ 2114e98e3e1Schristos SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1); 212212397c6Schristos CPU_PC_SET (cpu, GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DATA_BUS_ERROR * 32); 2134e98e3e1Schristos sim_engine_halt (sd, cpu, NULL, LM32_EID_DATA_BUS_ERROR * 32, 2144e98e3e1Schristos sim_stopped, SIM_SIGSEGV); 2154e98e3e1Schristos break; 2164e98e3e1Schristos case sim_core_unaligned_signal: 2174e98e3e1Schristos sim_io_eprintf (sd, 2184e98e3e1Schristos "core: %d byte misaligned %s to address 0x%lx at 0x%lx\n", 2194e98e3e1Schristos nr_bytes, copy, (unsigned long) addr, 2204e98e3e1Schristos (unsigned long) ip); 2214e98e3e1Schristos SET_H_GR (30, ip); 2224e98e3e1Schristos /* Save and clear interrupt enable. */ 2234e98e3e1Schristos SET_H_CSR (LM32_CSR_IE, (GET_H_CSR (LM32_CSR_IE) & 1) << 1); 224212397c6Schristos CPU_PC_SET (cpu, GET_H_CSR (LM32_CSR_EBA) + LM32_EID_DATA_BUS_ERROR * 32); 2254e98e3e1Schristos sim_engine_halt (sd, cpu, NULL, LM32_EID_DATA_BUS_ERROR * 32, 2264e98e3e1Schristos sim_stopped, SIM_SIGBUS); 2274e98e3e1Schristos break; 2284e98e3e1Schristos default: 2294e98e3e1Schristos sim_engine_abort (sd, cpu, cia, 2304e98e3e1Schristos "sim_core_signal - internal error - bad switch"); 2314e98e3e1Schristos } 2324e98e3e1Schristos } 233