nios2_vic.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. * Vectored Interrupt Controller for nios2 processor
  3. *
  4. * Copyright (c) 2022 Neuroblade
  5. *
  6. * Interface:
  7. * QOM property "cpu": link to the Nios2 CPU (must be set)
  8. * Unnamed GPIO inputs 0..NIOS2_VIC_MAX_IRQ-1: input IRQ lines
  9. * IRQ should be connected to nios2 IRQ0.
  10. *
  11. * Reference: "Embedded Peripherals IP User Guide
  12. * for Intel® Quartus® Prime Design Suite: 21.4"
  13. * Chapter 38 "Vectored Interrupt Controller Core"
  14. * See: https://www.intel.com/content/www/us/en/docs/programmable/683130/21-4/vectored-interrupt-controller-core.html
  15. *
  16. * Permission is hereby granted, free of charge, to any person obtaining a copy
  17. * of this software and associated documentation files (the "Software"), to deal
  18. * in the Software without restriction, including without limitation the rights
  19. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  20. * copies of the Software, and to permit persons to whom the Software is
  21. * furnished to do so, subject to the following conditions:
  22. *
  23. * The above copyright notice and this permission notice shall be included in
  24. * all copies or substantial portions of the Software.
  25. *
  26. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  27. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  28. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  29. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  30. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  31. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  32. * THE SOFTWARE.
  33. */
  34. #include "qemu/osdep.h"
  35. #include "hw/irq.h"
  36. #include "hw/qdev-properties.h"
  37. #include "hw/sysbus.h"
  38. #include "migration/vmstate.h"
  39. #include "qapi/error.h"
  40. #include "qemu/bitops.h"
  41. #include "qemu/log.h"
  42. #include "qom/object.h"
  43. #include "hw/intc/nios2_vic.h"
  44. #include "cpu.h"
  45. enum {
  46. INT_CONFIG0 = 0,
  47. INT_CONFIG31 = 31,
  48. INT_ENABLE = 32,
  49. INT_ENABLE_SET = 33,
  50. INT_ENABLE_CLR = 34,
  51. INT_PENDING = 35,
  52. INT_RAW_STATUS = 36,
  53. SW_INTERRUPT = 37,
  54. SW_INTERRUPT_SET = 38,
  55. SW_INTERRUPT_CLR = 39,
  56. VIC_CONFIG = 40,
  57. VIC_STATUS = 41,
  58. VEC_TBL_BASE = 42,
  59. VEC_TBL_ADDR = 43,
  60. CSR_COUNT /* Last! */
  61. };
  62. /* Requested interrupt level (INT_CONFIG[0:5]) */
  63. static inline uint32_t vic_int_config_ril(const Nios2VIC *vic, int irq_num)
  64. {
  65. return extract32(vic->int_config[irq_num], 0, 6);
  66. }
  67. /* Requested NMI (INT_CONFIG[6]) */
  68. static inline uint32_t vic_int_config_rnmi(const Nios2VIC *vic, int irq_num)
  69. {
  70. return extract32(vic->int_config[irq_num], 6, 1);
  71. }
  72. /* Requested register set (INT_CONFIG[7:12]) */
  73. static inline uint32_t vic_int_config_rrs(const Nios2VIC *vic, int irq_num)
  74. {
  75. return extract32(vic->int_config[irq_num], 7, 6);
  76. }
  77. static inline uint32_t vic_config_vec_size(const Nios2VIC *vic)
  78. {
  79. return 1 << (2 + extract32(vic->vic_config, 0, 3));
  80. }
  81. static inline uint32_t vic_int_pending(const Nios2VIC *vic)
  82. {
  83. return (vic->int_raw_status | vic->sw_int) & vic->int_enable;
  84. }
  85. static void vic_update_irq(Nios2VIC *vic)
  86. {
  87. Nios2CPU *cpu = NIOS2_CPU(vic->cpu);
  88. uint32_t pending = vic_int_pending(vic);
  89. int irq = -1;
  90. int max_ril = 0;
  91. /* Note that if RIL is 0 for an interrupt it is effectively disabled */
  92. vic->vec_tbl_addr = 0;
  93. vic->vic_status = 0;
  94. if (pending == 0) {
  95. qemu_irq_lower(vic->output_int);
  96. return;
  97. }
  98. for (int i = 0; i < NIOS2_VIC_MAX_IRQ; i++) {
  99. if (pending & BIT(i)) {
  100. int ril = vic_int_config_ril(vic, i);
  101. if (ril > max_ril) {
  102. irq = i;
  103. max_ril = ril;
  104. }
  105. }
  106. }
  107. if (irq < 0) {
  108. qemu_irq_lower(vic->output_int);
  109. return;
  110. }
  111. vic->vec_tbl_addr = irq * vic_config_vec_size(vic) + vic->vec_tbl_base;
  112. vic->vic_status = irq | BIT(31);
  113. /*
  114. * In hardware, the interface between the VIC and the CPU is via the
  115. * External Interrupt Controller interface, where the interrupt controller
  116. * presents the CPU with a packet of data containing:
  117. * - Requested Handler Address (RHA): 32 bits
  118. * - Requested Register Set (RRS) : 6 bits
  119. * - Requested Interrupt Level (RIL) : 6 bits
  120. * - Requested NMI flag (RNMI) : 1 bit
  121. * In our emulation, we implement this by writing the data directly to
  122. * fields in the CPU object and then raising the IRQ line to tell
  123. * the CPU that we've done so.
  124. */
  125. cpu->rha = vic->vec_tbl_addr;
  126. cpu->ril = max_ril;
  127. cpu->rrs = vic_int_config_rrs(vic, irq);
  128. cpu->rnmi = vic_int_config_rnmi(vic, irq);
  129. qemu_irq_raise(vic->output_int);
  130. }
  131. static void vic_set_irq(void *opaque, int irq_num, int level)
  132. {
  133. Nios2VIC *vic = opaque;
  134. vic->int_raw_status = deposit32(vic->int_raw_status, irq_num, 1, !!level);
  135. vic_update_irq(vic);
  136. }
  137. static void nios2_vic_reset(DeviceState *dev)
  138. {
  139. Nios2VIC *vic = NIOS2_VIC(dev);
  140. memset(&vic->int_config, 0, sizeof(vic->int_config));
  141. vic->vic_config = 0;
  142. vic->int_raw_status = 0;
  143. vic->int_enable = 0;
  144. vic->sw_int = 0;
  145. vic->vic_status = 0;
  146. vic->vec_tbl_base = 0;
  147. vic->vec_tbl_addr = 0;
  148. }
  149. static uint64_t nios2_vic_csr_read(void *opaque, hwaddr offset, unsigned size)
  150. {
  151. Nios2VIC *vic = opaque;
  152. int index = offset / 4;
  153. switch (index) {
  154. case INT_CONFIG0 ... INT_CONFIG31:
  155. return vic->int_config[index - INT_CONFIG0];
  156. case INT_ENABLE:
  157. return vic->int_enable;
  158. case INT_PENDING:
  159. return vic_int_pending(vic);
  160. case INT_RAW_STATUS:
  161. return vic->int_raw_status;
  162. case SW_INTERRUPT:
  163. return vic->sw_int;
  164. case VIC_CONFIG:
  165. return vic->vic_config;
  166. case VIC_STATUS:
  167. return vic->vic_status;
  168. case VEC_TBL_BASE:
  169. return vic->vec_tbl_base;
  170. case VEC_TBL_ADDR:
  171. return vic->vec_tbl_addr;
  172. default:
  173. return 0;
  174. }
  175. }
  176. static void nios2_vic_csr_write(void *opaque, hwaddr offset, uint64_t value,
  177. unsigned size)
  178. {
  179. Nios2VIC *vic = opaque;
  180. int index = offset / 4;
  181. switch (index) {
  182. case INT_CONFIG0 ... INT_CONFIG31:
  183. vic->int_config[index - INT_CONFIG0] = value;
  184. break;
  185. case INT_ENABLE:
  186. vic->int_enable = value;
  187. break;
  188. case INT_ENABLE_SET:
  189. vic->int_enable |= value;
  190. break;
  191. case INT_ENABLE_CLR:
  192. vic->int_enable &= ~value;
  193. break;
  194. case SW_INTERRUPT:
  195. vic->sw_int = value;
  196. break;
  197. case SW_INTERRUPT_SET:
  198. vic->sw_int |= value;
  199. break;
  200. case SW_INTERRUPT_CLR:
  201. vic->sw_int &= ~value;
  202. break;
  203. case VIC_CONFIG:
  204. vic->vic_config = value;
  205. break;
  206. case VEC_TBL_BASE:
  207. vic->vec_tbl_base = value;
  208. break;
  209. default:
  210. qemu_log_mask(LOG_GUEST_ERROR,
  211. "nios2-vic: write to invalid CSR address %#"
  212. HWADDR_PRIx "\n", offset);
  213. }
  214. vic_update_irq(vic);
  215. }
  216. static const MemoryRegionOps nios2_vic_csr_ops = {
  217. .read = nios2_vic_csr_read,
  218. .write = nios2_vic_csr_write,
  219. .endianness = DEVICE_LITTLE_ENDIAN,
  220. .valid = { .min_access_size = 4, .max_access_size = 4 }
  221. };
  222. static void nios2_vic_realize(DeviceState *dev, Error **errp)
  223. {
  224. Nios2VIC *vic = NIOS2_VIC(dev);
  225. if (!vic->cpu) {
  226. /* This is a programming error in the code using this device */
  227. error_setg(errp, "nios2-vic 'cpu' link property was not set");
  228. return;
  229. }
  230. sysbus_init_irq(SYS_BUS_DEVICE(dev), &vic->output_int);
  231. qdev_init_gpio_in(dev, vic_set_irq, NIOS2_VIC_MAX_IRQ);
  232. memory_region_init_io(&vic->csr, OBJECT(dev), &nios2_vic_csr_ops, vic,
  233. "nios2.vic.csr", CSR_COUNT * sizeof(uint32_t));
  234. sysbus_init_mmio(SYS_BUS_DEVICE(dev), &vic->csr);
  235. }
  236. static Property nios2_vic_properties[] = {
  237. DEFINE_PROP_LINK("cpu", Nios2VIC, cpu, TYPE_CPU, CPUState *),
  238. DEFINE_PROP_END_OF_LIST()
  239. };
  240. static const VMStateDescription nios2_vic_vmstate = {
  241. .name = "nios2-vic",
  242. .version_id = 1,
  243. .minimum_version_id = 1,
  244. .fields = (VMStateField[]){
  245. VMSTATE_UINT32_ARRAY(int_config, Nios2VIC, 32),
  246. VMSTATE_UINT32(vic_config, Nios2VIC),
  247. VMSTATE_UINT32(int_raw_status, Nios2VIC),
  248. VMSTATE_UINT32(int_enable, Nios2VIC),
  249. VMSTATE_UINT32(sw_int, Nios2VIC),
  250. VMSTATE_UINT32(vic_status, Nios2VIC),
  251. VMSTATE_UINT32(vec_tbl_base, Nios2VIC),
  252. VMSTATE_UINT32(vec_tbl_addr, Nios2VIC),
  253. VMSTATE_END_OF_LIST()
  254. },
  255. };
  256. static void nios2_vic_class_init(ObjectClass *klass, void *data)
  257. {
  258. DeviceClass *dc = DEVICE_CLASS(klass);
  259. dc->reset = nios2_vic_reset;
  260. dc->realize = nios2_vic_realize;
  261. dc->vmsd = &nios2_vic_vmstate;
  262. device_class_set_props(dc, nios2_vic_properties);
  263. }
  264. static const TypeInfo nios2_vic_info = {
  265. .name = TYPE_NIOS2_VIC,
  266. .parent = TYPE_SYS_BUS_DEVICE,
  267. .instance_size = sizeof(Nios2VIC),
  268. .class_init = nios2_vic_class_init,
  269. };
  270. static void nios2_vic_register_types(void)
  271. {
  272. type_register_static(&nios2_vic_info);
  273. }
  274. type_init(nios2_vic_register_types);