blob: 983175c70e302e26dcdb89aea6222f40bbb1afc0 [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
Eunchan Kim88a86152020-04-13 16:12:08 -070016- Support arbitrary number of interrupt vectors (up to 255) and targets
lowRISC Contributors802543a2019-08-31 12:12:56 +010017- 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
Eunchan Kim88a86152020-04-13 16:12:08 -070046sources. ID 0 is reserved and represents no interrupt. The bit 0 of
47`intr_src_i` shall be tied to 0 from the outside of RV_PLIC. The
48`intr_src_i[i]` bit has an ID of `i`. This ID is used when targets "claim" the
49interrupt and to "complete" the interrupt event.
lowRISC Contributors802543a2019-08-31 12:12:56 +010050
51### Priority and Threshold
52
Greg Chadwick828e9d12019-10-23 11:37:24 +010053Interrupt sources have configurable priority values. The maximum value of the
54priority is configurable through the localparam `MAX_PRIO` in the rv_plic
Garret Kelly9eebde02019-10-22 15:36:49 -040055top-level module. For each target there is a threshold value ({{< regref "THRESHOLD0" >}} for
Greg Chadwick828e9d12019-10-23 11:37:24 +010056target 0). RV_PLIC notifies a target of an interrupt only if it's priority is
57strictly greater than the target's threshold. Note this means an interrupt with
58a priority is 0 is effectively prevented from causing an interrupt at any target
59and a target can suppress all interrupts by setting it's threshold to the max
60priority value.
lowRISC Contributors802543a2019-08-31 12:12:56 +010061
62`MAX_PRIO` parameter is most area contributing option in RV_PLIC. If `MAX_PRIO`
Timothy Chene4648992019-11-02 17:58:54 -070063is big, then finding the highest priority in Process module may consume a lot of
lowRISC Contributors802543a2019-08-31 12:12:56 +010064logic gates.
65
66### Interrupt Gateways
67
Greg Chadwick828e9d12019-10-23 11:37:24 +010068The Gateway observes incoming interrupt sources and converts them to a common
69interrupt format used internally by RV_PLIC. It can be configured to detect
70interrupts events on an edge (when the signal changes from **0** to **1**) or
71level basis (where the signal remains at **1**).
72
73When the gateway detects an interrupt event it raises the interrupt pending bit
Garret Kelly9eebde02019-10-22 15:36:49 -040074({{< regref "IP" >}}) for that interrupt source. When an interrupt is claimed by a target the
Timothy Chene4648992019-11-02 17:58:54 -070075relevant bit of {{< regref "IP" >}} is cleared. A bit in {{< regref "IP" >}} will not be reasserted until the
Greg Chadwick828e9d12019-10-23 11:37:24 +010076target signals completion of the interrupt. Any new interrupt event between a
Garret Kelly9eebde02019-10-22 15:36:49 -040077bit in {{< regref "IP" >}} asserting and completing that interrupt is ignored. In particular
Greg Chadwick828e9d12019-10-23 11:37:24 +010078this means that for edge triggered interrupts if a new edge is seen after the
Timothy Chene4648992019-11-02 17:58:54 -070079source's {{< regref "IP" >}} bit is asserted but before completion, that edge will be ignored
Greg Chadwick828e9d12019-10-23 11:37:24 +010080(counting missed edges as discussed in the RISC-V PLIC specification is not
81supported).
82
83Note that there is no ability for a level triggered interrupt to be cancelled.
Garret Kelly9eebde02019-10-22 15:36:49 -040084If the interrupt drops after the gateway has set a bit in {{< regref "IP" >}}, the bit will
Greg Chadwick828e9d12019-10-23 11:37:24 +010085remain set until the interrupt is completed. The SW handler should be conscious
86of this and check the interrupt still requires handling in the handler if this
87behaviour is possible.
lowRISC Contributors802543a2019-08-31 12:12:56 +010088
89### Interrupt Enables
90
Garret Kelly9eebde02019-10-22 15:36:49 -040091Each target has a set of Interrupt Enable ({{< regref "IE0" >}} for target 0) registers. Each
92bit in the {{< regref "IE0" >}} registers controls the corresponding interrupt source. If an
Greg Chadwick828e9d12019-10-23 11:37:24 +010093interrupt source is disabled for a target, then interrupt events from that
94source won't trigger an interrupt at the target. RV_PLIC doesn't have a global
95interrupt disable feature.
lowRISC Contributors802543a2019-08-31 12:12:56 +010096
97### Interrupt Claims
98
99"Claiming" an interrupt is done by a target reading the associated
Garret Kelly9eebde02019-10-22 15:36:49 -0400100Claim/Completion register for the target ({{< regref "CC0" >}} for target 0). The return value
101of the {{< regref "CC0" >}} read represents the ID of the pending interrupt that has the
Greg Chadwick828e9d12019-10-23 11:37:24 +0100102highest priority. If two or more pending interrupts have the same priority,
103RV_PLIC chooses the one with lowest ID. Only interrupts that that are enabled
104for the target can be claimed. The target priority threshold doesn't matter
105(this only factors into whether an interrupt is signalled to the target) so
Garret Kelly9eebde02019-10-22 15:36:49 -0400106lower priority interrupt IDs can be returned on a read from {{< regref "CC0" >}}. If no
Greg Chadwick828e9d12019-10-23 11:37:24 +0100107interrupt is pending (or all pending interrupts are disabled for the target) a
Garret Kelly9eebde02019-10-22 15:36:49 -0400108read of {{< regref "CC0" >}} returns an ID of 0.
lowRISC Contributors802543a2019-08-31 12:12:56 +0100109
110### Interrupt Completion
111
Garret Kelly9eebde02019-10-22 15:36:49 -0400112After an interrupt is claimed, the relevant bit of interrupt pending ({{< regref "IP" >}}) is
Greg Chadwick828e9d12019-10-23 11:37:24 +0100113cleared, regardless of the status of the `intr_src_i` input value. Until a
114target "completes" the interrupt, it won't be re-asserted if a new event for the
115interrupt occurs. A target completes the interrupt by writing the ID of the
Garret Kelly9eebde02019-10-22 15:36:49 -0400116interrupt to the Claim/Complete register ({{< regref "CC0" >}} for target 0). The write event
Greg Chadwick828e9d12019-10-23 11:37:24 +0100117is forwarded to the Gateway logic, which resets the interrupt status to accept a
118new interrupt event. The assumption is that the processor has cleaned up the
119originating interrupt event during the time between claim and complete such that
Eunchan Kim88a86152020-04-13 16:12:08 -0700120`intr_src_i[ID]` will have de-asserted (unless a new interrupt has occurred).
lowRISC Contributors802543a2019-08-31 12:12:56 +0100121
122~~~~wavejson
123{ signal: [
124 { name: 'clk', wave: 'p...........' },
Greg Chadwick828e9d12019-10-23 11:37:24 +0100125 { name: 'intr_src_i[i]', wave: '01....0.1...', node:'.a....e.f...'},
126 { name: 'irq_o', wave: '0.1.0......1', node:'..b.d......h'},
lowRISC Contributors802543a2019-08-31 12:12:56 +0100127 { name: 'irq_id_o', wave: '=.=.=......=',
Eunchan Kim88a86152020-04-13 16:12:08 -0700128 data: ["0","i","0","i"] },
Greg Chadwick828e9d12019-10-23 11:37:24 +0100129 { name: 'claim', wave: '0..10.......', node:'...c........'},
130 { name: 'complete', wave: '0.........10', node:'..........g.'},
lowRISC Contributors802543a2019-08-31 12:12:56 +0100131 ],
132 head:{
133 text: 'Interrupt Flow',
134 tick: 0,
135 },
136}
137~~~~
138
Eunchan Kim88a86152020-04-13 16:12:08 -0700139In the example above an interrupt for source ID `i` is configured as a level
Greg Chadwick828e9d12019-10-23 11:37:24 +0100140interrupt and is raised at a, this results in the target being notified of the
Eunchan Kim88a86152020-04-13 16:12:08 -0700141interrupt at b. The target claims the interrupt at c (reading `i` from it's
Greg Chadwick828e9d12019-10-23 11:37:24 +0100142Claim/Complete register) so `irq_o` deasserts though `intr_src_i[i]` remains
143raised. The SW handles the interrupt and it drops at e. However a new interrupt
144quickly occurs at f. As complete hasn't been signaled yet `irq_o` isn't
Eunchan Kim88a86152020-04-13 16:12:08 -0700145asserted. At g the interrupt is completed (by writing `i` to it's
Greg Chadwick828e9d12019-10-23 11:37:24 +0100146Claim/Complete register) so at h `irq_o` is asserted due to the new interrupt.
lowRISC Contributors802543a2019-08-31 12:12:56 +0100147
lowRISC Contributors802543a2019-08-31 12:12:56 +0100148
Garret Kelly9eebde02019-10-22 15:36:49 -0400149# Programmers Guide
lowRISC Contributors802543a2019-08-31 12:12:56 +0100150
Garret Kelly9eebde02019-10-22 15:36:49 -0400151## Initialization
lowRISC Contributors802543a2019-08-31 12:12:56 +0100152
153After reset, RV_PLIC doesn't generate any interrupts to any targets even if
Greg Chadwick828e9d12019-10-23 11:37:24 +0100154interrupt sources are set, as all priorities and thresholds are 0 by default and
155all ``IE`` values are 0. Software should configure the above three registers and the
Garret Kelly9eebde02019-10-22 15:36:49 -0400156interrupt source type {{< regref "LE" >}} .
lowRISC Contributors802543a2019-08-31 12:12:56 +0100157
Garret Kelly9eebde02019-10-22 15:36:49 -0400158{{< regref "LE" >}} and {{< regref "PRIO0" >}} .. {{< regref "PRIO31" >}} registers are unique. So, only one of the targets
lowRISC Contributors802543a2019-08-31 12:12:56 +0100159shall configure them.
160
Garret Kelly9eebde02019-10-22 15:36:49 -0400161```c
lowRISC Contributors802543a2019-08-31 12:12:56 +0100162// Pseudo-code below
163void plic_init() {
164 // Set to level-triggered for interrupt sources
Alex Bradburya78ae462020-01-03 17:24:12 +0000165 for (int i = 0; i < ceil(N_SOURCE / 32); ++i) {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600166 *(LE + i) = 0;
167 }
lowRISC Contributors802543a2019-08-31 12:12:56 +0100168
169 // Configure priority
Eunchan Kim88a86152020-04-13 16:12:08 -0700170 // Note that PRIO0 register doesn't affect as intr_src_i[0] is tied to 0.
Alex Bradburya78ae462020-01-03 17:24:12 +0000171 for (int i = 0; i < N_SOURCE; ++i) {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600172 *(PRIO + i) = value(i);
173 }
lowRISC Contributors802543a2019-08-31 12:12:56 +0100174}
175
176void plic_threshold(tid, threshold) {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600177 *(THRESHOLD + tid) = threshold;
lowRISC Contributors802543a2019-08-31 12:12:56 +0100178}
179
180void plic_enable(tid, iid) {
181 // iid: 0-based ID
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600182 int offset = ceil(N_SOURCE / 32) * tid + (iid >> 5);
lowRISC Contributors802543a2019-08-31 12:12:56 +0100183
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600184 *(IE + offset) = *(IE + offset) | (1 << (iid % 32));
lowRISC Contributors802543a2019-08-31 12:12:56 +0100185}
Garret Kelly9eebde02019-10-22 15:36:49 -0400186```
lowRISC Contributors802543a2019-08-31 12:12:56 +0100187
Garret Kelly9eebde02019-10-22 15:36:49 -0400188## Handling Interrupt Request Events
lowRISC Contributors802543a2019-08-31 12:12:56 +0100189
190If software receives an interrupt request, it is recommended to follow the steps
Garret Kelly9eebde02019-10-22 15:36:49 -0400191shown below (assuming target 0 which uses {{< regref "CC0" >}} for claim/complete).
lowRISC Contributors802543a2019-08-31 12:12:56 +0100192
Greg Chadwick828e9d12019-10-23 11:37:24 +01001931. Claim the interrupts right after entering to the interrupt service routine
Garret Kelly9eebde02019-10-22 15:36:49 -0400194 by reading the {{< regref "CC0" >}} register.
Greg Chadwick828e9d12019-10-23 11:37:24 +01001952. Determine which interrupt should be serviced based on the values read from
Garret Kelly9eebde02019-10-22 15:36:49 -0400196 the {{< regref "CC0" >}} register.
Greg Chadwick828e9d12019-10-23 11:37:24 +01001973. Execute ISR, clearing the originating peripheral interrupt.
Garret Kelly9eebde02019-10-22 15:36:49 -04001984. Write Interrupt ID to {{< regref "CC0" >}}
lowRISC Contributors802543a2019-08-31 12:12:56 +01001995. Repeat as necessary for other pending interrupts.
200
201It is possible to have multiple interrupt events claimed. If software claims one
202interrupt request, then the process module advertises any pending interrupts
203with lower priority unless new higher priority interrupt events occur. If a
204higher interrupt event occurs after previous interrupt is claimed, the RV_PLIC
205IP advertises the higher priority interrupt. Software may utilize an event
206manager inside a loop so that interrupt claiming and completion can be
207separated.
208
209~~~~c
210void interrupt_service() {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600211 uint32_t tid = /* ... */;
212 uint32_t iid = *(CC + tid);
lowRISC Contributors802543a2019-08-31 12:12:56 +0100213 if (iid == 0) {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600214 // Interrupt is claimed by one of other targets.
215 return;
216 }
lowRISC Contributors802543a2019-08-31 12:12:56 +0100217
218 do {
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600219 // Process interrupts...
lowRISC Contributors802543a2019-08-31 12:12:56 +0100220 // ...
221
Miguel Young de la Sota0240b782019-12-20 09:33:23 -0600222 // Finish.
lowRISC Contributors802543a2019-08-31 12:12:56 +0100223 *(CC + tid) = iid;
224 iid = *(CC + tid);
225 } while (iid != 0);
226}
227~~~~
228
Sam Elliottb6745d32020-04-08 21:46:28 +0100229## Device Interface Functions (DIFs)
230
231{{< dif_listing "sw/device/lib/dif/dif_plic.h" >}}
232
Garret Kelly9eebde02019-10-22 15:36:49 -0400233## Registers
lowRISC Contributors802543a2019-08-31 12:12:56 +0100234
Sam Elliottd834c702020-02-12 11:18:47 +0000235The register description below matches the instance in the [Earl Grey top level
236design]({{< relref "hw/top_earlgrey/doc" >}}).
lowRISC Contributors802543a2019-08-31 12:12:56 +0100237
Sam Elliottd834c702020-02-12 11:18:47 +0000238A similar register description can be generated with `reg_rv_plic.py` script.
239The reason another script for register generation is that RV_PLIC is
240configurable to the number of input sources and output targets. To implement it,
241some of the registers (see below **IE**) should be double nested in register
242description file. As of Jan. 2019, `regtool.py` supports only one nested
243multiple register format `multireg`.
244
245The RV_PLIC in the top level is generated by topgen tool so that the number of
Timothy Chene4648992019-11-02 17:58:54 -0700246interrupt sources may be different.
lowRISC Contributors802543a2019-08-31 12:12:56 +0100247
248- LE: CEILING(N_SOURCE / DW)
249 Value 1 indicates the interrupt source's behavior is edge-triggered It is
250 used in the gateways module.
251- IE: CEILING(N_SOURCE / DW) X N_TARGET
252 Each bit enables corresponding interrupt source. Each target has IE set.
253- PRIO: N_SOURCE
254 Universal set across all targets. Lower n bits are valid. n is determined by
255 MAX_PRIO parameter
256- THRESHOLD: N_TARGET
257 Priority threshold per target. Only priority of the interrupt greater than
258 threshold can raise interrupt notification to the target.
259- IP: CEILING(N_SOURCE / DW)
260 Pending bits right after the gateways. Read-only
261- CC: N_TARGET
262 Claim by read, complete by write
263
Sam Elliottd834c702020-02-12 11:18:47 +0000264{{< registers "hw/top_earlgrey/ip/rv_plic/data/autogen/rv_plic.hjson" >}}