blob: f54618069e6de8afdb66315bd0217926cd6631af [file] [log] [blame] [view]
Garret Kelly9eebde02019-10-22 15:36:49 -04001---
2title: "Interrupt Controller Technical Specification"
3---
lowRISC Contributors802543a2019-08-31 12:12:56 +01004
Garret Kelly9eebde02019-10-22 15:36:49 -04005# Overview
lowRISC Contributors802543a2019-08-31 12:12:56 +01006
7This document specifies the Interrupt Controller (RV_PLIC) functionality. This
8module conforms to the
Timothy Chene4648992019-11-02 17:58:54 -07009[Comportable guideline for peripheral functionality]({{< relref "doc/rm/comportability_specification" >}}).
lowRISC Contributors802543a2019-08-31 12:12:56 +010010See that document for integration overview within the broader top level system.
11
lowRISC Contributors802543a2019-08-31 12:12:56 +010012
Garret Kelly9eebde02019-10-22 15:36:49 -040013## Features
lowRISC Contributors802543a2019-08-31 12:12:56 +010014
15- RISC-V Platform-Level Interrupt Controller (PLIC) compliant interrupt controller
16- Support arbitrary number of interrupt vectors (up to 256) and targets
17- Support interrupt enable, interrupt status registers
Greg Chadwick828e9d12019-10-23 11:37:24 +010018- Memory-mapped MSIP register per HART for software interrupt control.
lowRISC Contributors802543a2019-08-31 12:12:56 +010019
Garret Kelly9eebde02019-10-22 15:36:49 -040020## Description
lowRISC Contributors802543a2019-08-31 12:12:56 +010021
22The RV_PLIC module is designed to manage various interrupt sources from the
Greg Chadwick828e9d12019-10-23 11:37:24 +010023peripherals. It receives interrupt events as either edge or level of the
24incoming interrupt signals (``intr_src_i``) and can notify multiple targets.
lowRISC Contributors802543a2019-08-31 12:12:56 +010025
Garret Kelly9eebde02019-10-22 15:36:49 -040026## Compatibility
lowRISC Contributors802543a2019-08-31 12:12:56 +010027
28The RV_PLIC is compatible with any RISC-V core implementing the RISC-V privilege specification.
29
Garret Kelly9eebde02019-10-22 15:36:49 -040030# Theory of Operations
lowRISC Contributors802543a2019-08-31 12:12:56 +010031
Garret Kelly9eebde02019-10-22 15:36:49 -040032## Block Diagram
lowRISC Contributors802543a2019-08-31 12:12:56 +010033
34![RV_PLIC Block Diagram](block_diagram.svg)
35
Timothy Chene4648992019-11-02 17:58:54 -070036## Hardware Interfaces
37
Sam Elliottd834c702020-02-12 11:18:47 +000038{{< hwcfg "hw/top_earlgrey/ip/rv_plic/data/autogen/rv_plic.hjson" >}}
Timothy Chene4648992019-11-02 17:58:54 -070039
40## Design Details
lowRISC Contributors802543a2019-08-31 12:12:56 +010041
42### Identifier
43
44Each interrupt source has a unique ID assigned based upon its bit position
Greg Chadwick828e9d12019-10-23 11:37:24 +010045within the input `intr_src_i`. ID ranges from 0 to N, the number of interrupt
46sources. ID 0 is reserved and represents no interrupt. The `intr_src_i[i]` bit
47has an ID of `i+1`. This ID is used when targets "claim" the interrupt and to
48"complete" the interrupt event.
lowRISC Contributors802543a2019-08-31 12:12:56 +010049
50### Priority and Threshold
51
Greg Chadwick828e9d12019-10-23 11:37:24 +010052Interrupt sources have configurable priority values. The maximum value of the
53priority is configurable through the localparam `MAX_PRIO` in the rv_plic
Garret Kelly9eebde02019-10-22 15:36:49 -040054top-level module. For each target there is a threshold value ({{< regref "THRESHOLD0" >}} for
Greg Chadwick828e9d12019-10-23 11:37:24 +010055target 0). RV_PLIC notifies a target of an interrupt only if it's priority is
56strictly greater than the target's threshold. Note this means an interrupt with
57a priority is 0 is effectively prevented from causing an interrupt at any target
58and a target can suppress all interrupts by setting it's threshold to the max
59priority value.
lowRISC Contributors802543a2019-08-31 12:12:56 +010060
61`MAX_PRIO` parameter is most area contributing option in RV_PLIC. If `MAX_PRIO`
Timothy Chene4648992019-11-02 17:58:54 -070062is big, then finding the highest priority in Process module may consume a lot of
lowRISC Contributors802543a2019-08-31 12:12:56 +010063logic gates.
64
65### Interrupt Gateways
66
Greg Chadwick828e9d12019-10-23 11:37:24 +010067The Gateway observes incoming interrupt sources and converts them to a common
68interrupt format used internally by RV_PLIC. It can be configured to detect
69interrupts events on an edge (when the signal changes from **0** to **1**) or
70level basis (where the signal remains at **1**).
71
72When the gateway detects an interrupt event it raises the interrupt pending bit
Garret Kelly9eebde02019-10-22 15:36:49 -040073({{< regref "IP" >}}) for that interrupt source. When an interrupt is claimed by a target the
Timothy Chene4648992019-11-02 17:58:54 -070074relevant bit of {{< regref "IP" >}} is cleared. A bit in {{< regref "IP" >}} will not be reasserted until the
Greg Chadwick828e9d12019-10-23 11:37:24 +010075target signals completion of the interrupt. Any new interrupt event between a
Garret Kelly9eebde02019-10-22 15:36:49 -040076bit in {{< regref "IP" >}} asserting and completing that interrupt is ignored. In particular
Greg Chadwick828e9d12019-10-23 11:37:24 +010077this means that for edge triggered interrupts if a new edge is seen after the
Timothy Chene4648992019-11-02 17:58:54 -070078source's {{< regref "IP" >}} bit is asserted but before completion, that edge will be ignored
Greg Chadwick828e9d12019-10-23 11:37:24 +010079(counting missed edges as discussed in the RISC-V PLIC specification is not
80supported).
81
82Note that there is no ability for a level triggered interrupt to be cancelled.
Garret Kelly9eebde02019-10-22 15:36:49 -040083If the interrupt drops after the gateway has set a bit in {{< regref "IP" >}}, the bit will
Greg Chadwick828e9d12019-10-23 11:37:24 +010084remain set until the interrupt is completed. The SW handler should be conscious
85of this and check the interrupt still requires handling in the handler if this
86behaviour is possible.
lowRISC Contributors802543a2019-08-31 12:12:56 +010087
88### Interrupt Enables
89
Garret Kelly9eebde02019-10-22 15:36:49 -040090Each target has a set of Interrupt Enable ({{< regref "IE0" >}} for target 0) registers. Each
91bit in the {{< regref "IE0" >}} registers controls the corresponding interrupt source. If an
Greg Chadwick828e9d12019-10-23 11:37:24 +010092interrupt source is disabled for a target, then interrupt events from that
93source won't trigger an interrupt at the target. RV_PLIC doesn't have a global
94interrupt disable feature.
lowRISC Contributors802543a2019-08-31 12:12:56 +010095
96### Interrupt Claims
97
98"Claiming" an interrupt is done by a target reading the associated
Garret Kelly9eebde02019-10-22 15:36:49 -040099Claim/Completion register for the target ({{< regref "CC0" >}} for target 0). The return value
100of the {{< regref "CC0" >}} read represents the ID of the pending interrupt that has the
Greg Chadwick828e9d12019-10-23 11:37:24 +0100101highest priority. If two or more pending interrupts have the same priority,
102RV_PLIC chooses the one with lowest ID. Only interrupts that that are enabled
103for the target can be claimed. The target priority threshold doesn't matter
104(this only factors into whether an interrupt is signalled to the target) so
Garret Kelly9eebde02019-10-22 15:36:49 -0400105lower priority interrupt IDs can be returned on a read from {{< regref "CC0" >}}. If no
Greg Chadwick828e9d12019-10-23 11:37:24 +0100106interrupt is pending (or all pending interrupts are disabled for the target) a
Garret Kelly9eebde02019-10-22 15:36:49 -0400107read of {{< regref "CC0" >}} returns an ID of 0.
lowRISC Contributors802543a2019-08-31 12:12:56 +0100108
109### Interrupt Completion
110
Garret Kelly9eebde02019-10-22 15:36:49 -0400111After an interrupt is claimed, the relevant bit of interrupt pending ({{< regref "IP" >}}) is
Greg Chadwick828e9d12019-10-23 11:37:24 +0100112cleared, regardless of the status of the `intr_src_i` input value. Until a
113target "completes" the interrupt, it won't be re-asserted if a new event for the
114interrupt occurs. A target completes the interrupt by writing the ID of the
Garret Kelly9eebde02019-10-22 15:36:49 -0400115interrupt to the Claim/Complete register ({{< regref "CC0" >}} for target 0). The write event
Greg Chadwick828e9d12019-10-23 11:37:24 +0100116is forwarded to the Gateway logic, which resets the interrupt status to accept a
117new interrupt event. The assumption is that the processor has cleaned up the
118originating interrupt event during the time between claim and complete such that
119`intr_src_i[ID-1]` will have de-asserted (unless a new interrupt has occurred).
lowRISC Contributors802543a2019-08-31 12:12:56 +0100120
121~~~~wavejson
122{ signal: [
123 { name: 'clk', wave: 'p...........' },
Greg Chadwick828e9d12019-10-23 11:37:24 +0100124 { name: 'intr_src_i[i]', wave: '01....0.1...', node:'.a....e.f...'},
125 { name: 'irq_o', wave: '0.1.0......1', node:'..b.d......h'},
lowRISC Contributors802543a2019-08-31 12:12:56 +0100126 { name: 'irq_id_o', wave: '=.=.=......=',
127 data: ["0","i+1","0","i+1"] },
Greg Chadwick828e9d12019-10-23 11:37:24 +0100128 { name: 'claim', wave: '0..10.......', node:'...c........'},
129 { name: 'complete', wave: '0.........10', node:'..........g.'},
lowRISC Contributors802543a2019-08-31 12:12:56 +0100130 ],
131 head:{
132 text: 'Interrupt Flow',
133 tick: 0,
134 },
135}
136~~~~
137
Greg Chadwick828e9d12019-10-23 11:37:24 +0100138In the example above an interrupt for source ID `i+1` is configured as a level
139interrupt and is raised at a, this results in the target being notified of the
140interrupt at b. The target claims the interrupt at c (reading `i+1` from it's
141Claim/Complete register) so `irq_o` deasserts though `intr_src_i[i]` remains
142raised. The SW handles the interrupt and it drops at e. However a new interrupt
143quickly occurs at f. As complete hasn't been signaled yet `irq_o` isn't
144asserted. At g the interrupt is completed (by writing `i+1` to it's
145Claim/Complete register) so at h `irq_o` is asserted due to the new interrupt.
lowRISC Contributors802543a2019-08-31 12:12:56 +0100146
lowRISC Contributors802543a2019-08-31 12:12:56 +0100147
Garret Kelly9eebde02019-10-22 15:36:49 -0400148# Programmers Guide
lowRISC Contributors802543a2019-08-31 12:12:56 +0100149
Garret Kelly9eebde02019-10-22 15:36:49 -0400150## Initialization
lowRISC Contributors802543a2019-08-31 12:12:56 +0100151
152After reset, RV_PLIC doesn't generate any interrupts to any targets even if
Greg Chadwick828e9d12019-10-23 11:37:24 +0100153interrupt sources are set, as all priorities and thresholds are 0 by default and
154all ``IE`` values are 0. Software should configure the above three registers and the
Garret Kelly9eebde02019-10-22 15:36:49 -0400155interrupt source type {{< regref "LE" >}} .
lowRISC Contributors802543a2019-08-31 12:12:56 +0100156
Garret Kelly9eebde02019-10-22 15:36:49 -0400157{{< regref "LE" >}} and {{< regref "PRIO0" >}} .. {{< regref "PRIO31" >}} registers are unique. So, only one of the targets
lowRISC Contributors802543a2019-08-31 12:12:56 +0100158shall configure them.
159
Garret Kelly9eebde02019-10-22 15:36:49 -0400160```c
lowRISC Contributors802543a2019-08-31 12:12:56 +0100161// Pseudo-code below
162void plic_init() {
163 // Set to level-triggered for interrupt sources
Alex Bradburya78ae462020-01-03 17:24:12 +0000164 for (int i = 0; i < ceil(N_SOURCE / 32); ++i) {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600165 *(LE + i) = 0;
166 }
lowRISC Contributors802543a2019-08-31 12:12:56 +0100167
168 // Configure priority
Alex Bradburya78ae462020-01-03 17:24:12 +0000169 for (int i = 0; i < N_SOURCE; ++i) {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600170 *(PRIO + i) = value(i);
171 }
lowRISC Contributors802543a2019-08-31 12:12:56 +0100172}
173
174void plic_threshold(tid, threshold) {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600175 *(THRESHOLD + tid) = threshold;
lowRISC Contributors802543a2019-08-31 12:12:56 +0100176}
177
178void plic_enable(tid, iid) {
179 // iid: 0-based ID
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600180 int offset = ceil(N_SOURCE / 32) * tid + (iid >> 5);
lowRISC Contributors802543a2019-08-31 12:12:56 +0100181
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600182 *(IE + offset) = *(IE + offset) | (1 << (iid % 32));
lowRISC Contributors802543a2019-08-31 12:12:56 +0100183}
Garret Kelly9eebde02019-10-22 15:36:49 -0400184```
lowRISC Contributors802543a2019-08-31 12:12:56 +0100185
Garret Kelly9eebde02019-10-22 15:36:49 -0400186## Handling Interrupt Request Events
lowRISC Contributors802543a2019-08-31 12:12:56 +0100187
188If software receives an interrupt request, it is recommended to follow the steps
Garret Kelly9eebde02019-10-22 15:36:49 -0400189shown below (assuming target 0 which uses {{< regref "CC0" >}} for claim/complete).
lowRISC Contributors802543a2019-08-31 12:12:56 +0100190
Greg Chadwick828e9d12019-10-23 11:37:24 +01001911. Claim the interrupts right after entering to the interrupt service routine
Garret Kelly9eebde02019-10-22 15:36:49 -0400192 by reading the {{< regref "CC0" >}} register.
Greg Chadwick828e9d12019-10-23 11:37:24 +01001932. Determine which interrupt should be serviced based on the values read from
Garret Kelly9eebde02019-10-22 15:36:49 -0400194 the {{< regref "CC0" >}} register.
Greg Chadwick828e9d12019-10-23 11:37:24 +01001953. Execute ISR, clearing the originating peripheral interrupt.
Garret Kelly9eebde02019-10-22 15:36:49 -04001964. Write Interrupt ID to {{< regref "CC0" >}}
lowRISC Contributors802543a2019-08-31 12:12:56 +01001975. Repeat as necessary for other pending interrupts.
198
199It is possible to have multiple interrupt events claimed. If software claims one
200interrupt request, then the process module advertises any pending interrupts
201with lower priority unless new higher priority interrupt events occur. If a
202higher interrupt event occurs after previous interrupt is claimed, the RV_PLIC
203IP advertises the higher priority interrupt. Software may utilize an event
204manager inside a loop so that interrupt claiming and completion can be
205separated.
206
207~~~~c
208void interrupt_service() {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600209 uint32_t tid = /* ... */;
210 uint32_t iid = *(CC + tid);
lowRISC Contributors802543a2019-08-31 12:12:56 +0100211 if (iid == 0) {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600212 // Interrupt is claimed by one of other targets.
213 return;
214 }
lowRISC Contributors802543a2019-08-31 12:12:56 +0100215
216 do {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600217 // Process interrupts...
lowRISC Contributors802543a2019-08-31 12:12:56 +0100218 // ...
219
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600220 // Finish.
lowRISC Contributors802543a2019-08-31 12:12:56 +0100221 *(CC + tid) = iid;
222 iid = *(CC + tid);
223 } while (iid != 0);
224}
225~~~~
226
Garret Kelly9eebde02019-10-22 15:36:49 -0400227## Registers
lowRISC Contributors802543a2019-08-31 12:12:56 +0100228
Sam Elliottd834c702020-02-12 11:18:47 +0000229The register description below matches the instance in the [Earl Grey top level
230design]({{< relref "hw/top_earlgrey/doc" >}}).
lowRISC Contributors802543a2019-08-31 12:12:56 +0100231
Sam Elliottd834c702020-02-12 11:18:47 +0000232A similar register description can be generated with `reg_rv_plic.py` script.
233The reason another script for register generation is that RV_PLIC is
234configurable to the number of input sources and output targets. To implement it,
235some of the registers (see below **IE**) should be double nested in register
236description file. As of Jan. 2019, `regtool.py` supports only one nested
237multiple register format `multireg`.
238
239The RV_PLIC in the top level is generated by topgen tool so that the number of
Timothy Chene4648992019-11-02 17:58:54 -0700240interrupt sources may be different.
lowRISC Contributors802543a2019-08-31 12:12:56 +0100241
242- LE: CEILING(N_SOURCE / DW)
243 Value 1 indicates the interrupt source's behavior is edge-triggered It is
244 used in the gateways module.
245- IE: CEILING(N_SOURCE / DW) X N_TARGET
246 Each bit enables corresponding interrupt source. Each target has IE set.
247- PRIO: N_SOURCE
248 Universal set across all targets. Lower n bits are valid. n is determined by
249 MAX_PRIO parameter
250- THRESHOLD: N_TARGET
251 Priority threshold per target. Only priority of the interrupt greater than
252 threshold can raise interrupt notification to the target.
253- IP: CEILING(N_SOURCE / DW)
254 Pending bits right after the gateways. Read-only
255- CC: N_TARGET
256 Claim by read, complete by write
257
Sam Elliottd834c702020-02-12 11:18:47 +0000258{{< registers "hw/top_earlgrey/ip/rv_plic/data/autogen/rv_plic.hjson" >}}