Skip to content
This repository was archived by the owner on Jun 30, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ Privileges specification Section

## `reg_rv_plic.py`

The tool is to create register hjson file given values of number of sources,
number of targets, and max value of priority. By default `target` is **1** and
`priority` is **7** (8 level of priorities supported)
The tool is to create register hjson and top module `rv_plic.sv` files given
values of number of sources, number of targets, and max value of priority. By
default `target` is **1** and `priority` is **7** (8 level of priorities
supported)

To change the value and to re-create hjson,

$ reg_rv_plic.py -s 64 -t 2 -p 15 rv_plic_reg.tpl.hjson > rv_plic_reg.hjson
$ reg_rv_plic.py -s 64 -t 2 -p 15 rv_plic.tpl.sv > ../rtl/rv_plic.sv

219 changes: 219 additions & 0 deletions doc/rv_plic.tpl.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// RISC-V Platform-Level Interrupt Controller compliant INTC
//
// Current version doesn't support MSI interrupt but it is easy to add
// the feature. Create one external register and connect qe signal to the
// gateway module (as edge-triggered)
//
// Consider to set MAX_PRIO as small number as possible. It is main factor
// of area increase if edge-triggered counter isn't implemented.
//
// verilog parameter
// N_SOURCE: Number of interrupt sources
// N_TARGET: Number of interrupt targets (#receptor)
// MAX_PRIO: Maximum value of interrupt priority

module rv_plic #(
parameter int N_SOURCE = ${src},
parameter int N_TARGET = ${target},
parameter FIND_MAX = "SEQUENTIAL", // SEQUENTIAL | MATRIX

parameter int SRCW = $clog2(N_SOURCE+1) // derived parameter
) (
input clk_i,
input rst_ni,

// Bus Interface (device)
input tlul_pkg::tl_h2d_t tl_i,
output tlul_pkg::tl_d2h_t tl_o,

// Interrupt Sources
input [N_SOURCE-1:0] intr_src_i,

// Interrupt notification to targets
output [N_TARGET-1:0] irq_o,
output [SRCW-1:0] irq_id_o [N_TARGET]
);

import rv_plic_reg_pkg::*;

rv_plic_reg2hw_t reg2hw;
rv_plic_hw2reg_t hw2reg;

localparam int MAX_PRIO = ${prio};
localparam int PRIOW = $clog2(MAX_PRIO+1);

logic [N_SOURCE-1:0] le; // 0:level 1:edge
logic [N_SOURCE-1:0] ip;

logic [N_SOURCE-1:0] ie [N_TARGET];

logic [N_TARGET-1:0] claim_re; // Target read indicator
logic [SRCW-1:0] claim_id [N_TARGET];
logic [N_SOURCE-1:0] claim; // Converted from claim_re/claim_id

logic [N_TARGET-1:0] complete_we; // Target write indicator
logic [SRCW-1:0] complete_id [N_TARGET];
logic [N_SOURCE-1:0] complete; // Converted from complete_re/complete_id

logic [SRCW-1:0] cc_id [N_TARGET]; // Write ID

logic [PRIOW-1:0] prio [N_SOURCE];

logic [PRIOW-1:0] threshold [N_TARGET];

// Glue logic between rv_plic_reg_top and others
assign cc_id = irq_id_o;

always_comb begin
claim = '0;
for (int i = 0 ; i < N_TARGET ; i++) begin
if (claim_re[i]) claim[claim_id[i] -1] = 1'b1;
end
end
always_comb begin
complete = '0;
for (int i = 0 ; i < N_TARGET ; i++) begin
if (complete_we[i]) complete[complete_id[i] -1] = 1'b1;
end
end

//`ASSERT_PULSE(claimPulse, claim_re[i], clk_i, !rst_ni)
//`ASSERT_PULSE(completePulse, complete_we[i], clk_i, !rst_ni)

`ASSERT(onehot0Claim, $onehot0(claim_re), clk_i, !rst_ni)

`ASSERT(onehot0Complete, $onehot0(complete_we), clk_i, !rst_ni)

//////////////////////////////////////////////////////////////////////////////
// Priority
% for s in range(src):
assign prio[${s}] = reg2hw.prio${s}.q;
% endfor
//----------------------------------------------------------------------------

//////////////////////////////////////////////////////////////////////////////
// Interrupt Enable
% for t in range(target):
% for s in range(src):
% if s > 32:
## TODO: make regwidth configurable
assign ie[${t}][${s}] = reg2hw.ie${t}${s//32}.e${s%32}.q;
% else:
## no multireg expands to multiple registers
assign ie[${t}][${s}] = reg2hw.ie${t}.e${s}.q;
% endif
% endfor
% endfor
//----------------------------------------------------------------------------

//////////////////////////////////////////////////////////////////////////////
// THRESHOLD register
% for t in range(target):
assign threshold[${t}] = reg2hw.threshold${t}.q;
% endfor
//----------------------------------------------------------------------------

//////////////////////////////////////////////////////////////////////////////
// CC register
% for t in range(target):
assign claim_re[${t}] = reg2hw.cc${t}.re;
assign claim_id[${t}] = irq_id_o[${t}];
assign complete_we[${t}] = reg2hw.cc${t}.qe;
assign complete_id[${t}] = reg2hw.cc${t}.q;
assign hw2reg.cc${t}.d = cc_id[${t}];
% endfor
//----------------------------------------------------------------------------

//////////////////////////////////////////////////////////////////////////////
// IP
% for s in range(src):
% if s > 32:
## TODO: make regwidth configurable
assign hw2reg.ip${s//32}.p${s%32}.de = 1'b1; // Always write
% else:
## no multireg expands to multiple registers
assign hw2reg.ip.p${s}.de = 1'b1; // Always write
% endif
% endfor
% for s in range(src):
% if s > 32:
## TODO: make regwidth configurable
assign hw2reg.ip${s//32}.p${s%32}.d = ip[${s}];
% else:
## no multireg expands to multiple registers
assign hw2reg.ip.p${s}.d = ip[${s}];
% endif
% endfor
//----------------------------------------------------------------------------

//////////////////////////////////////////////////////////////////////////////
// Detection:: 0: Level, 1: Edge
% for s in range(src):
% if s > 32:
## TODO: make regwidth configurable
assign le[${s}] = reg2hw.le${s//32}.le${s%32}.q;
% else:
## no multireg expands to multiple registers
assign le[${s}] = reg2hw.le.le${s}.q;
% endif
% endfor
//----------------------------------------------------------------------------

// Gateways
rv_plic_gateway #(
.N_SOURCE (N_SOURCE)
) u_gateway (
.clk_i,
.rst_ni,

.src (intr_src_i),
.le,

.claim,
.complete,

.ip
);


// Target interrupt notification
for (genvar i = 0 ; i < N_TARGET ; i++) begin : gen_target
rv_plic_target #(
.N_SOURCE (N_SOURCE),
.MAX_PRIO (MAX_PRIO),
.ALGORITHM(FIND_MAX)
) u_target (
.clk_i,
.rst_ni,

.ip,
.ie (ie[i]),

.prio,
.threshold (threshold[i]),

.irq (irq_o[i]),
.irq_id (irq_id_o[i])

);
end

// Register interface
// Limitation of register tool prevents the module from having flexibility to parameters
// So, signals are manually tied at the top.
rv_plic_reg_top u_reg (
.clk_i,
.rst_ni,

.tl_i,
.tl_o,

.reg2hw,
.hw2reg
);

endmodule
Loading