plic.cpp 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*******************************************************************************
  2. * Copyright (C) 2017, 2018 MINRES Technologies GmbH
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice,
  9. * this list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * 3. Neither the name of the copyright holder nor the names of its contributors
  16. * may be used to endorse or promote products derived from this software
  17. * without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  20. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  23. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  27. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  28. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  29. * POSSIBILITY OF SUCH DAMAGE.
  30. *
  31. *******************************************************************************/
  32. #include <sysc/SiFive/plic.h>
  33. #include <scc/report.h>
  34. #include <scc/utilities.h>
  35. #include <sysc/SiFive/gen/plic_regs.h>
  36. namespace sysc {
  37. plic::plic(sc_core::sc_module_name nm)
  38. : sc_core::sc_module(nm)
  39. , tlm_target<>(clk)
  40. , NAMED(clk_i)
  41. , NAMED(rst_i)
  42. , NAMED(global_interrupts_i, 256)
  43. , NAMED(core_interrupt_o)
  44. , NAMEDD(regs, plic_regs)
  45. {
  46. regs->registerResources(*this);
  47. // register callbacks
  48. regs->claim_complete.set_write_cb([this](scc::sc_register<uint32_t>& reg, const uint32_t& v, sc_core::sc_time d) -> bool {
  49. reg.put(v);
  50. reset_pending_int(v);
  51. // std::cout << "Value of register: 0x" << std::hex << reg << std::endl;
  52. // todo: reset related interrupt and find next high-prio interrupt
  53. return true;
  54. });
  55. // port callbacks
  56. SC_METHOD(global_int_port_cb);
  57. for (uint8_t i = 0; i < 255; i++) {
  58. sensitive << global_interrupts_i[i].pos();
  59. }
  60. dont_initialize();
  61. // register event callbacks
  62. SC_METHOD(clock_cb);
  63. sensitive << clk_i;
  64. SC_METHOD(reset_cb);
  65. sensitive << rst_i;
  66. dont_initialize();
  67. }
  68. plic::~plic() {}// NOLINT
  69. void plic::clock_cb() { this->clk = clk_i.read(); }
  70. void plic::reset_cb() {
  71. if (rst_i.read())
  72. regs->reset_start();
  73. else
  74. regs->reset_stop();
  75. }
  76. // Functional handling of interrupts:
  77. // - global_int_port_cb()
  78. // - set pending register bits
  79. // - called by: incoming global_int
  80. // - handle_pending_int()
  81. // - update claim register content
  82. // - generate core-interrupt pulse
  83. // - called by:
  84. // - incoming global_int
  85. // - complete-register write access
  86. // - reset_pending_int(int-id)
  87. // - reset pending bit
  88. // - call next handle_pending_int()
  89. // - called by:
  90. // - complete-reg write register content
  91. void plic::global_int_port_cb() {
  92. auto handle_pending = false;
  93. // set related pending bit if enable is set for incoming global_interrupt
  94. for (uint32_t i = 1; i < 256; i++) {
  95. auto reg_idx = i >> 5;
  96. auto bit_ofs = i & 0x1F;
  97. bool enable = regs->r_enabled[reg_idx] & (0x1 << bit_ofs); // read enable bit
  98. if (enable && global_interrupts_i[i].read() == 1) {
  99. regs->r_pending[reg_idx] = regs->r_pending[reg_idx] | (0x1 << bit_ofs);
  100. handle_pending = true;
  101. SCDEBUG(this->name()) << "pending interrupt identified: " << i;
  102. }
  103. }
  104. if (handle_pending) handle_pending_int();
  105. }
  106. void plic::handle_pending_int() {
  107. // identify high-prio pending interrupt and raise a core-interrupt
  108. auto claim_int = 0U; // claim interrupt
  109. auto claim_prio = 0U; // related priority (highest prio interrupt wins the race)
  110. auto raise_int = false;
  111. auto thold = regs->r_threshold.threshold; // threshold value
  112. for (size_t i = 1; i < 255; i++) {
  113. auto reg_idx = i >> 5;
  114. auto bit_ofs = i & 0x1F;
  115. bool pending = (regs->r_pending[reg_idx] & (0x1 << bit_ofs)) ? true : false;
  116. auto prio = regs->r_priority[i].priority; // read priority value
  117. if (pending && thold < prio) {
  118. // below condition ensures implicitly that lowest id is selected in case of multiple identical
  119. // priority-interrupts
  120. if (prio > claim_prio) {
  121. claim_prio = prio;
  122. claim_int = i;
  123. raise_int = true;
  124. SCDEBUG(this->name()) << "pending interrupt activated: " << i;
  125. }
  126. }
  127. }
  128. if (raise_int) {
  129. regs->r_claim_complete = claim_int;
  130. core_interrupt_o.write(true);
  131. // todo: evluate clock period
  132. } else {
  133. regs->r_claim_complete = 0;
  134. SCDEBUG(this->name()) << "no further pending interrupt.";
  135. }
  136. }
  137. void plic::reset_pending_int(uint32_t irq) {
  138. // todo: evaluate enable register (see spec)
  139. // todo: make sure that pending is set, otherwise don't reset irq ... read spec.
  140. SCTRACE(this->name()) << "reset pending interrupt: " << irq;
  141. // reset related pending bit
  142. auto reg_idx = irq >> 5;
  143. auto bit_ofs = irq & 0x1F;
  144. regs->r_pending[reg_idx] &= ~(0x1 << bit_ofs);
  145. core_interrupt_o.write(false);
  146. // evaluate next pending interrupt
  147. handle_pending_int();
  148. }
  149. } /* namespace sysc */