xref: /netbsd-src/external/gpl3/gdb/dist/sim/lm32/traps.c (revision 71f621822dbfd5073a314948bec169b7bb05f7be)
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