traps.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /* OpenRISC exception, interrupts, syscall and trap support
  2. Copyright (C) 2017-2022 Free Software Foundation, Inc.
  3. This file is part of GDB, the GNU debugger.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  14. /* This must come before any other includes. */
  15. #include "defs.h"
  16. #define WANT_CPU_OR1K32BF
  17. #define WANT_CPU
  18. #include "sim-main.h"
  19. #include "sim-signal.h"
  20. #include "cgen-ops.h"
  21. /* Implement the sim invalid instruction function. This will set the error
  22. effective address to that of the invalid instruction then call the
  23. exception handler. */
  24. SEM_PC
  25. sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
  26. {
  27. SET_H_SYS_EEAR0 (cia);
  28. #ifdef WANT_CPU_OR1K32BF
  29. or1k32bf_exception (current_cpu, cia, EXCEPT_ILLEGAL);
  30. #endif
  31. return vpc;
  32. }
  33. /* Generate the appropriate OpenRISC fpu exception based on the status code from
  34. the sim fpu. */
  35. void
  36. or1k32bf_fpu_error (CGEN_FPU* fpu, int status)
  37. {
  38. SIM_CPU *current_cpu = (SIM_CPU *)fpu->owner;
  39. /* If floating point exceptions are enabled. */
  40. if (GET_H_SYS_FPCSR_FPEE() != 0)
  41. {
  42. /* Set all of the status flag bits. */
  43. if (status
  44. & (sim_fpu_status_invalid_snan
  45. | sim_fpu_status_invalid_qnan
  46. | sim_fpu_status_invalid_isi
  47. | sim_fpu_status_invalid_idi
  48. | sim_fpu_status_invalid_zdz
  49. | sim_fpu_status_invalid_imz
  50. | sim_fpu_status_invalid_cvi
  51. | sim_fpu_status_invalid_cmp
  52. | sim_fpu_status_invalid_sqrt))
  53. SET_H_SYS_FPCSR_IVF (1);
  54. if (status & sim_fpu_status_invalid_snan)
  55. SET_H_SYS_FPCSR_SNF (1);
  56. if (status & sim_fpu_status_invalid_qnan)
  57. SET_H_SYS_FPCSR_QNF (1);
  58. if (status & sim_fpu_status_overflow)
  59. SET_H_SYS_FPCSR_OVF (1);
  60. if (status & sim_fpu_status_underflow)
  61. SET_H_SYS_FPCSR_UNF (1);
  62. if (status
  63. & (sim_fpu_status_invalid_isi
  64. | sim_fpu_status_invalid_idi))
  65. SET_H_SYS_FPCSR_INF (1);
  66. if (status & sim_fpu_status_invalid_div0)
  67. SET_H_SYS_FPCSR_DZF (1);
  68. if (status & sim_fpu_status_inexact)
  69. SET_H_SYS_FPCSR_IXF (1);
  70. /* If any of the exception bits were actually set. */
  71. if (GET_H_SYS_FPCSR()
  72. & (SPR_FIELD_MASK_SYS_FPCSR_IVF
  73. | SPR_FIELD_MASK_SYS_FPCSR_SNF
  74. | SPR_FIELD_MASK_SYS_FPCSR_QNF
  75. | SPR_FIELD_MASK_SYS_FPCSR_OVF
  76. | SPR_FIELD_MASK_SYS_FPCSR_UNF
  77. | SPR_FIELD_MASK_SYS_FPCSR_INF
  78. | SPR_FIELD_MASK_SYS_FPCSR_DZF
  79. | SPR_FIELD_MASK_SYS_FPCSR_IXF))
  80. {
  81. SIM_DESC sd = CPU_STATE (current_cpu);
  82. /* If the sim is running in fast mode, i.e. not profiling,
  83. per-instruction callbacks are not triggered which would allow
  84. us to track the PC. This means we cannot track which
  85. instruction caused the FPU error. */
  86. if (!PROFILE_ANY_P (current_cpu) && !TRACE_ANY_P (current_cpu))
  87. sim_io_eprintf
  88. (sd, "WARNING: ignoring fpu error caught in fast mode.\n");
  89. else
  90. or1k32bf_exception (current_cpu, GET_H_SYS_PPC (), EXCEPT_FPE);
  91. }
  92. }
  93. }
  94. /* Implement the OpenRISC exception function. This is mostly used by the
  95. CGEN generated files. For example, this is used when handling a
  96. overflow exception during a multiplication instruction. */
  97. void
  98. or1k32bf_exception (sim_cpu *current_cpu, USI pc, USI exnum)
  99. {
  100. SIM_DESC sd = CPU_STATE (current_cpu);
  101. if (exnum == EXCEPT_TRAP)
  102. {
  103. /* Trap, used for breakpoints, sends control back to gdb breakpoint
  104. handling. */
  105. sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
  106. }
  107. else
  108. {
  109. IADDR handler_pc;
  110. /* Calculate the exception program counter. */
  111. switch (exnum)
  112. {
  113. case EXCEPT_RESET:
  114. break;
  115. case EXCEPT_FPE:
  116. case EXCEPT_SYSCALL:
  117. SET_H_SYS_EPCR0 (pc + 4 - (current_cpu->delay_slot ? 4 : 0));
  118. break;
  119. case EXCEPT_BUSERR:
  120. case EXCEPT_ALIGN:
  121. case EXCEPT_ILLEGAL:
  122. case EXCEPT_RANGE:
  123. SET_H_SYS_EPCR0 (pc - (current_cpu->delay_slot ? 4 : 0));
  124. break;
  125. default:
  126. sim_io_error (sd, "unexpected exception 0x%x raised at PC 0x%08x",
  127. exnum, pc);
  128. break;
  129. }
  130. /* Store the current SR into ESR0. */
  131. SET_H_SYS_ESR0 (GET_H_SYS_SR ());
  132. /* Indicate in SR if the failed instruction is in delay slot or not. */
  133. SET_H_SYS_SR_DSX (current_cpu->delay_slot);
  134. current_cpu->next_delay_slot = 0;
  135. /* Jump program counter into handler. */
  136. handler_pc =
  137. (GET_H_SYS_SR_EPH () ? 0xf0000000 : 0x00000000) + (exnum << 8);
  138. sim_engine_restart (sd, current_cpu, NULL, handler_pc);
  139. }
  140. }
  141. /* Implement the return from exception instruction. This is used to return
  142. the CPU to its previous state from within an exception handler. */
  143. void
  144. or1k32bf_rfe (sim_cpu *current_cpu)
  145. {
  146. SET_H_SYS_SR (GET_H_SYS_ESR0 ());
  147. SET_H_SYS_SR_FO (1);
  148. current_cpu->next_delay_slot = 0;
  149. sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL,
  150. GET_H_SYS_EPCR0 ());
  151. }
  152. /* Implement the move from SPR instruction. This is used to read from the
  153. CPU's special purpose registers. */
  154. USI
  155. or1k32bf_mfspr (sim_cpu *current_cpu, USI addr)
  156. {
  157. SIM_DESC sd = CPU_STATE (current_cpu);
  158. SI val;
  159. if (!GET_H_SYS_SR_SM () && !GET_H_SYS_SR_SUMRA ())
  160. {
  161. sim_io_eprintf (sd, "WARNING: l.mfspr in user mode (SR 0x%x)\n",
  162. GET_H_SYS_SR ());
  163. return 0;
  164. }
  165. if (addr >= NUM_SPR)
  166. goto bad_address;
  167. val = GET_H_SPR (addr);
  168. switch (addr)
  169. {
  170. case SPR_ADDR (SYS, VR):
  171. case SPR_ADDR (SYS, UPR):
  172. case SPR_ADDR (SYS, CPUCFGR):
  173. case SPR_ADDR (SYS, SR):
  174. case SPR_ADDR (SYS, PPC):
  175. case SPR_ADDR (SYS, FPCSR):
  176. case SPR_ADDR (SYS, EPCR0):
  177. case SPR_ADDR (MAC, MACLO):
  178. case SPR_ADDR (MAC, MACHI):
  179. break;
  180. default:
  181. if (addr < SPR_ADDR (SYS, GPR0) || addr > SPR_ADDR (SYS, GPR511))
  182. goto bad_address;
  183. break;
  184. }
  185. return val;
  186. bad_address:
  187. sim_io_eprintf (sd, "WARNING: l.mfspr with invalid SPR address 0x%x\n", addr);
  188. return 0;
  189. }
  190. /* Implement the move to SPR instruction. This is used to write too the
  191. CPU's special purpose registers. */
  192. void
  193. or1k32bf_mtspr (sim_cpu *current_cpu, USI addr, USI val)
  194. {
  195. SIM_DESC sd = CPU_STATE (current_cpu);
  196. if (!GET_H_SYS_SR_SM () && !GET_H_SYS_SR_SUMRA ())
  197. {
  198. sim_io_eprintf
  199. (sd, "WARNING: l.mtspr with address 0x%x in user mode (SR 0x%x)\n",
  200. addr, GET_H_SYS_SR ());
  201. return;
  202. }
  203. if (addr >= NUM_SPR)
  204. goto bad_address;
  205. switch (addr)
  206. {
  207. case SPR_ADDR (SYS, FPCSR):
  208. case SPR_ADDR (SYS, EPCR0):
  209. case SPR_ADDR (SYS, ESR0):
  210. case SPR_ADDR (MAC, MACHI):
  211. case SPR_ADDR (MAC, MACLO):
  212. SET_H_SPR (addr, val);
  213. break;
  214. case SPR_ADDR (SYS, SR):
  215. SET_H_SPR (addr, val);
  216. SET_H_SYS_SR_FO (1);
  217. break;
  218. case SPR_ADDR (SYS, NPC):
  219. current_cpu->next_delay_slot = 0;
  220. sim_engine_restart (CPU_STATE (current_cpu), current_cpu, NULL, val);
  221. break;
  222. case SPR_ADDR (TICK, TTMR):
  223. /* Allow some registers to be silently cleared. */
  224. if (val != 0)
  225. sim_io_eprintf
  226. (sd, "WARNING: l.mtspr to SPR address 0x%x with invalid value 0x%x\n",
  227. addr, val);
  228. break;
  229. default:
  230. if (addr >= SPR_ADDR (SYS, GPR0) && addr <= SPR_ADDR (SYS, GPR511))
  231. SET_H_SPR (addr, val);
  232. else
  233. goto bad_address;
  234. break;
  235. }
  236. return;
  237. bad_address:
  238. sim_io_eprintf (sd, "WARNING: l.mtspr with invalid SPR address 0x%x\n", addr);
  239. }