../src/lowrisc_ip_rv_plic_component_0.1/rtl/rv_plic_target.sv Cov: 89.1%
1: // Copyright lowRISC contributors.
2: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3: // SPDX-License-Identifier: Apache-2.0
4: //
5: // RISC-V Platform-Level Interrupt Generator for Target
6: //
7: // This module basically doing IE & IP based on priority and threshold.
8: // Keep in mind that increasing MAX_PRIO affects logic size a lot.
9: //
10: // The module implements a binary tree to find the maximal entry. the solution
11: // has O(N) area and O(log(N)) delay complexity, and thus scales well with
12: // many input sources.
13: //
14:
15: `include "prim_assert.sv"
16:
17: module rv_plic_target #(
18: parameter int N_SOURCE = 32,
19: parameter int MAX_PRIO = 7,
20:
21: // Local param (Do not change this through parameter
22: localparam int SrcWidth = $clog2(N_SOURCE+1), // derived parameter
23: localparam int PrioWidth = $clog2(MAX_PRIO+1) // derived parameter
24: ) (
25: input clk_i,
26: input rst_ni,
27:
28: input [N_SOURCE-1:0] ip,
29: input [N_SOURCE-1:0] ie,
30:
31: input [PrioWidth-1:0] prio [N_SOURCE],
32: input [PrioWidth-1:0] threshold,
33:
34: output logic irq,
35: output logic [SrcWidth-1:0] irq_id
36: );
37:
38: // this only works with 2 or more sources
39: `ASSERT_INIT(NumSources_A, N_SOURCE >= 2)
40:
41: // align to powers of 2 for simplicity
42: // a full binary tree with N levels has 2**N + 2**N-1 nodes
43: localparam int NumLevels = $clog2(N_SOURCE);
44: logic [2**(NumLevels+1)-2:0] is_tree;
45: logic [2**(NumLevels+1)-2:0][SrcWidth-1:0] id_tree;
46: logic [2**(NumLevels+1)-2:0][PrioWidth-1:0] max_tree;
47:
48: for (genvar level = 0; level < NumLevels+1; level++) begin : gen_tree
49: //
50: // level+1 C0 C1 <- "Base1" points to the first node on "level+1",
51: // \ / these nodes are the children of the nodes one level below
52: // level Pa <- "Base0", points to the first node on "level",
53: // these nodes are the parents of the nodes one level above
54: //
55: // hence we have the following indices for the paPa, C0, C1 nodes:
56: // Pa = 2**level - 1 + offset = Base0 + offset
57: // C0 = 2**(level+1) - 1 + 2*offset = Base1 + 2*offset
58: // C1 = 2**(level+1) - 1 + 2*offset + 1 = Base1 + 2*offset + 1
59: //
60: localparam int Base0 = (2**level)-1;
61: localparam int Base1 = (2**(level+1))-1;
62:
63: for (genvar offset = 0; offset < 2**level; offset++) begin : gen_level
64: localparam int Pa = Base0 + offset;
65: localparam int C0 = Base1 + 2*offset;
66: localparam int C1 = Base1 + 2*offset + 1;
67:
68: // this assigns the gated interrupt source signals, their
69: // corresponding IDs and priorities to the tree leafs
70: if (level == NumLevels) begin : gen_leafs
71: if (offset < N_SOURCE) begin : gen_assign
72: assign is_tree[Pa] = ip[offset] & ie[offset];
73: assign id_tree[Pa] = offset;
74: assign max_tree[Pa] = prio[offset];
75: end else begin : gen_tie_off
76: assign is_tree[Pa] = '0;
77: assign id_tree[Pa] = '0;
78: assign max_tree[Pa] = '0;
79: end
80: // this creates the node assignments
81: end else begin : gen_nodes
82: // NOTE: the code below has been written in this way in order to work
83: // around a synthesis issue in Vivado 2018.3 and 2019.2 where the whole
84: // module would be optimized away if these assign statements contained
85: // ternary statements to implement the muxes.
86: //
87: // TODO: rewrite these lines with ternary statmements onec the problem
88: // has been fixed in the tool.
89: //
90: // See also originating issue:
91: // https://github.com/lowRISC/opentitan/issues/1355
92: // Xilinx issue:
93: // https://forums.xilinx.com/t5/Synthesis/Simulation-Synthesis-Mismatch-with-Vivado-2018-3/m-p/1065923#M33849
94:
95: logic sel; // local helper variable
96: // in case only one of the parent has a pending irq, forward that one
97: // in case both irqs are pending, forward the one with higher priority
98: assign sel = (~is_tree[C0] & is_tree[C1]) |
99: (is_tree[C0] & is_tree[C1] & logic'(max_tree[C1] > max_tree[C0]));
100: // forwarding muxes
101: assign is_tree[Pa] = (sel & is_tree[C1]) | ((~sel) & is_tree[C0]);
102: assign id_tree[Pa] = ({SrcWidth{sel}} & id_tree[C1]) | ({SrcWidth{~sel}} & id_tree[C0]);
103: assign max_tree[Pa] = ({PrioWidth{sel}} & max_tree[C1]) | ({PrioWidth{~sel}} & max_tree[C0]);
104: end
105: end : gen_level
106: end : gen_tree
107:
108: logic irq_d, irq_q;
109: logic [SrcWidth-1:0] irq_id_d, irq_id_q;
110:
111: // the results can be found at the tree root
112: assign irq_d = (max_tree[0] > threshold) ? is_tree[0] : 1'b0;
113: assign irq_id_d = (is_tree[0]) ? id_tree[0] : '0;
114:
115: always_ff @(posedge clk_i or negedge rst_ni) begin : gen_regs
116: if (!rst_ni) begin
117: irq_q <= 1'b0;
118: irq_id_q <= '0;
119: end else begin
120: irq_q <= irq_d;
121: irq_id_q <= irq_id_d;
122: end
123: end
124:
125: assign irq = irq_q;
126: assign irq_id = irq_id_q;
127:
128: endmodule
129:
130: