rv_plic: Add lowrisc PLIC

Use a PLIC which has been developed as part of the lowrisc project. It
has been integrated into the Ariane SoC as a submodule pointing to a
fork which has some (temporary) custom patches on top.
This commit is contained in:
Florian Zaruba 2019-04-02 15:28:38 +02:00
parent 095cda6194
commit 5bf0d9256b
15 changed files with 66 additions and 924 deletions

3
.gitmodules vendored
View file

@ -43,3 +43,6 @@
[submodule "src/riscv-dbg"]
path = src/riscv-dbg
url = https://github.com/pulp-platform/riscv-dbg.git
[submodule "src/rv_plic"]
path = src/rv_plic
url = https://github.com/pulp-platform/rv_plic.git

View file

@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fix bug in wt_axi_adapter (only appeared when dcache lines were wider than icache lines)
- Fix potentially long timing path in `axi_lite_interface`
- Fix VCS elab warning in `load_store_unit`
- Bump `common_cells` to v1.12.0
- Provision exponential backoff for AMO SC in L1 D$ miss handler
- Add lowrisc PLIC
### 4.1.2

View file

@ -58,6 +58,7 @@ ariane_pkg := include/riscv_pkg.sv \
include/wt_cache_pkg.sv \
src/axi/src/axi_pkg.sv \
src/register_interface/src/reg_intf.sv \
src/register_interface/src/reg_intf_pkg.sv \
include/axi_intf.sv \
tb/ariane_soc_pkg.sv \
include/ariane_axi_pkg.sv \
@ -112,10 +113,13 @@ src := $(filter-out src/ariane_regfile.sv, $(wildcard src/*.sv)) \
$(wildcard src/clint/*.sv) \
$(wildcard fpga/src/axi2apb/src/*.sv) \
$(wildcard fpga/src/axi_slice/src/*.sv) \
$(wildcard src/plic/*.sv) \
$(wildcard src/axi_node/src/*.sv) \
$(wildcard src/axi_riscv_atomics/src/*.sv) \
$(wildcard src/axi_mem_if/src/*.sv) \
src/rv_plic/rtl/rv_plic_target.sv \
src/rv_plic/rtl/rv_plic_gateway.sv \
src/rv_plic/rtl/plic_regmap.sv \
src/rv_plic/rtl/plic_top.sv \
src/riscv-dbg/src/dmi_cdc.sv \
src/riscv-dbg/src/dmi_jtag.sv \
src/riscv-dbg/src/dmi_jtag_tap.sv \

View file

@ -156,17 +156,31 @@ module ariane_peripherals #(
.reg_o ( reg_bus )
);
plic #(
.ID_BITWIDTH ( ariane_soc::PLICIdWidth ),
.PARAMETER_BITWIDTH ( ariane_soc::ParameterBitwidth ),
.NUM_TARGETS ( ariane_soc::NumTargets ),
.NUM_SOURCES ( ariane_soc::NumSources )
reg_intf::reg_intf_resp_d32 plic_resp;
reg_intf::reg_intf_req_a32_d32 plic_req;
assign plic_req.addr = reg_bus.addr;
assign plic_req.write = reg_bus.write;
assign plic_req.wdata = reg_bus.wdata;
assign plic_req.wstrb = reg_bus.wstrb;
assign plic_req.valid = reg_bus.valid;
assign reg_bus.rdata = plic_resp.rdata;
assign reg_bus.error = plic_resp.error;
assign reg_bus.ready = plic_resp.ready;
plic_top #(
.N_SOURCE ( ariane_soc::NumSources ),
.N_TARGET ( ariane_soc::NumTargets ),
.MAX_PRIO ( ariane_soc::MaxPriority )
) i_plic (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.irq_sources_i ( irq_sources ),
.eip_targets_o ( irq_o ),
.external_bus_io ( reg_bus )
.clk_i,
.rst_ni,
.req_i ( plic_req ),
.resp_o ( plic_resp ),
.le_i ( '0 ), // 0:level 1:edge
.irq_sources_i ( irq_sources ),
.eip_targets_o ( irq_o )
);
// ---------------

View file

@ -1,155 +0,0 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
//-------------------------------------------------------------------------------
//-- Title : PLIC Core
//-- File : plic_core.sv
//-- Author : Gian Marti <gimarti.student.ethz.ch>
//-- Author : Thomas Kramer <tkramer.student.ethz.ch>
//-- Author : Thomas E. Benz <tbenz.student.ethz.ch>
//-- Company : Integrated Systems Laboratory, ETH Zurich
//-- Created : 2018-03-31
//-- Last update: 2018-03-31
//-- Platform : ModelSim (simulation), Synopsys (synthesis)
//-- Standard : SystemVerilog IEEE 1800-2012
//-------------------------------------------------------------------------------
//-- Description: PLIC Top-level
//-------------------------------------------------------------------------------
//-- Revisions :
//-- Date Version Author Description
//-- 2018-03-31 2.0 tbenz Created header
//-------------------------------------------------------------------------------
module plic #(
parameter int ADDR_WIDTH = 32, // can be either 32 or 64 bits (don't use 64bit at the moment as this causes memory map issues)
parameter int DATA_WIDTH = 32, // can be either 32 or 64 bits (don't use 64bit at the moment as this causes memory map issues)
parameter int ID_BITWIDTH = -1, // width of the gateway identifiers
parameter int PARAMETER_BITWIDTH = -1, // width of the internal parameter e.g. priorities
parameter int NUM_TARGETS = -1, // number of target slices
parameter int NUM_SOURCES = -1 // number of sources = number of gateways
) (
input logic clk_i,
input logic rst_ni,
input logic [NUM_SOURCES-1:0] irq_sources_i,
output logic [NUM_TARGETS-1:0] eip_targets_o,
REG_BUS.in external_bus_io
);
// declare all local variables
// gateway arrays always go from NUM_SOURCES to 1 because gateway ids start at 1
logic gateway_irq_pendings [NUM_SOURCES]; //for pending irqs of the gateways
logic gateway_claimed [NUM_SOURCES]; //if a gateway is claimed, it masks its irq
logic gateway_completed [NUM_SOURCES]; //if a gateway is completed, it is reenabled
logic [ID_BITWIDTH-1:0 ] gateway_ids [NUM_SOURCES]; //ids of gateways
logic [PARAMETER_BITWIDTH-1:0] gateway_priorities [NUM_SOURCES]; //priorities of gateways
logic irq_enableds [NUM_SOURCES][NUM_TARGETS];
logic [PARAMETER_BITWIDTH-1:0] target_thresholds [NUM_TARGETS];
logic [ID_BITWIDTH-1:0 ] identifier_of_largest_priority_per_target [NUM_TARGETS];
logic target_irq_claims [NUM_TARGETS];
logic target_irq_completes [NUM_TARGETS];
logic [ID_BITWIDTH-1:0 ] target_irq_completes_id [NUM_TARGETS];
//instantiate and connect gateways
for (genvar counter = 0; counter < NUM_SOURCES; counter++) begin : gen_plic_gateway
plic_gateway plic_gateway_instance (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.irq_source_i ( irq_sources_i [counter] ),
.claim_i ( gateway_claimed [counter] ),
.completed_i ( gateway_completed [counter] ),
.irq_pending_o ( gateway_irq_pendings[counter] )
);
end
// assign ids to gateways
for (genvar counter = 1; counter <= NUM_SOURCES; counter++) begin
assign gateway_ids[counter-1] = counter;
end
// instantiate and connect target slices
for (genvar counter = 0; counter < NUM_TARGETS; counter++) begin : gen_plic_target_slice
logic irq_enableds_slice[NUM_SOURCES];
for (genvar inner_counter = 0; inner_counter < NUM_SOURCES; inner_counter++) begin
assign irq_enableds_slice[inner_counter] = irq_enableds[inner_counter][counter];
end
plic_target_slice #(
.PRIORITY_BITWIDTH ( PARAMETER_BITWIDTH ),
.ID_BITWIDTH ( ID_BITWIDTH ),
.NUM_GATEWAYS ( NUM_SOURCES )
) plic_target_slice_instance (
.interrupt_pending_i ( gateway_irq_pendings ),
.interrupt_priority_i ( gateway_priorities ),
.interrupt_id_i ( gateway_ids ),
.interrupt_enable_i ( irq_enableds_slice ),
.threshold_i ( target_thresholds[counter] ),
.ext_interrupt_present_o ( eip_targets_o[counter] ),
.identifier_of_largest_o ( identifier_of_largest_priority_per_target[counter] )
);
end
//instantiate and connect plic_interface
plic_interface #(
.ADDR_WIDTH ( ADDR_WIDTH ),
.DATA_WIDTH ( DATA_WIDTH ),
.ID_BITWIDTH ( ID_BITWIDTH ),
.PARAMETER_BITWIDTH ( PARAMETER_BITWIDTH ),
.NUM_TARGETS ( NUM_TARGETS ),
.NUM_GATEWAYS ( NUM_SOURCES )
) plic_interface_instance (
.clk_i,
.rst_ni,
.id_of_largest_priority_i ( identifier_of_largest_priority_per_target ),
.pending_array_i ( gateway_irq_pendings ),
.thresholds_o ( target_thresholds ),
.gateway_priorities_o ( gateway_priorities ),
.irq_enables_o ( irq_enableds ),
.target_irq_claims_o ( target_irq_claims ),
.target_irq_completes_o ( target_irq_completes ),
.target_irq_completes_id_o ( target_irq_completes_id ),
.external_bus_io ( external_bus_io )
);
//instantiate and connect claim_complete_tracker
plic_claim_complete_tracker #(
.NUM_TARGETS ( NUM_TARGETS ),
.NUM_GATEWAYS ( NUM_SOURCES ),
.ID_BITWIDTH ( ID_BITWIDTH )
) plic_claim_complete_tracker_instance (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.identifier_of_largest_priority_per_target ( identifier_of_largest_priority_per_target ),
.target_irq_claims_i ( target_irq_claims ),
.target_irq_completes_i ( target_irq_completes ),
.target_irq_completes_identifier_i ( target_irq_completes_id ),
.gateway_irq_claims_o ( gateway_claimed ),
.gateway_irq_completes_o ( gateway_completed )
);
//pragma translate_off
`ifndef VERILATOR
initial begin
assert((ADDR_WIDTH == 32) | (ADDR_WIDTH == 64)) else $error("Address width has to bei either 32 or 64 bit");
assert((DATA_WIDTH == 32) | (DATA_WIDTH == 64)) else $error("Data width has to bei either 32 or 64 bit");
assert(ID_BITWIDTH > 0 ) else $error("ID_BITWIDTH has to be larger than 1");
assert(ID_BITWIDTH < 10 ) else $error("ID_BITWIDTH has to be smaller than 10");
assert(PARAMETER_BITWIDTH > 0) else $error("PARAMETER_BITWIDTH has to be larger than 1");
assert(PARAMETER_BITWIDTH < 8) else $error("PARAMETER_BITWIDTH has to be smaller than 8");
assert(NUM_SOURCES > 0 ) else $error("Num od Gateways has to be larger than 1");
assert(NUM_SOURCES < 512 ) else $error("Num of Gateways has to be smaller than 512");
assert(NUM_TARGETS > 0 ) else $error("Num Target slices has to be larger than 1");
assert(NUM_TARGETS < 15872 ) else $error("Num target slices has to be smaller than 15872");
end
`endif
//pragma translate_on
endmodule

View file

@ -1,125 +0,0 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
//-------------------------------------------------------------------------------
//-- Title : Claim - Complete - Tracker
//-------------------------------------------------------------------------------
//-- File : plic_claim_complete_tracker.sv
//-- Author : Gian Marti <gimarti.student.ethz.ch>
//-- Author : Thomas Kramer <tkramer.student.ethz.ch>
//-- Author : Thomas E. Benz <tbenz.student.ethz.ch>
//-- Company : Integrated Systems Laboratory, ETH Zurich
//-- Created : 2018-03-31
//-- Last update: 2018-03-31
//-- Platform : ModelSim (simulation), Synopsys (synthesis)
//-- Standard : SystemVerilog IEEE 1800-2012
//-------------------------------------------------------------------------------
//-- Description: Implements the control logic of the plic
//-------------------------------------------------------------------------------
//-- Revisions :
//-- Date Version Author Description
//-- 2018-03-31 2.0 tbenz Created header
//-------------------------------------------------------------------------------
//FSM that receives interrupt claims and interrupt completes from targets
//and generates the fitting inerrupt claims and interrupt completes for sources
module plic_claim_complete_tracker #(
parameter int NUM_TARGETS = 1,
parameter int NUM_GATEWAYS = 1,
parameter int ID_BITWIDTH = 4
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic [ID_BITWIDTH-1:0] identifier_of_largest_priority_per_target[NUM_TARGETS],
input logic target_irq_claims_i [NUM_TARGETS],
input logic target_irq_completes_i[NUM_TARGETS],
input logic [ID_BITWIDTH-1:0] target_irq_completes_identifier_i[NUM_TARGETS],
output logic gateway_irq_claims_o [NUM_GATEWAYS],
output logic gateway_irq_completes_o[NUM_GATEWAYS]
);
// claimed_gateways_q[target] is 0 if the target has not claimed the irq of any gateway
// and the is the identifier of the claimed gateway otherwise
logic [ID_BITWIDTH-1:0] claimed_gateways_q[NUM_TARGETS];
// the +1 is because counting starts from 1 and goes to NUM_GATEWAYS+1
logic claim_array [NUM_GATEWAYS+1][NUM_TARGETS];
logic save_claims_array_q [NUM_GATEWAYS+1][NUM_TARGETS];
logic complete_array [NUM_GATEWAYS+1][NUM_TARGETS];
// for handling claims
for (genvar counter = 0; counter < NUM_TARGETS; counter++) begin
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_target
if (~rst_ni) begin
claimed_gateways_q[counter] <= '0;
for (integer i = 0; i <= NUM_GATEWAYS; i++) begin
claim_array[i][counter] <= '0;
save_claims_array_q[i][counter] <= '0;
end
end else begin
// per default, all claims and completes are zero
for (integer i = 0; i <= NUM_GATEWAYS; i++) begin
claim_array[i][counter] <= 0;
complete_array[i][counter] <= 0;
end
// if a claim is issued, forward it to gateway with highest priority for the claiming target
if (target_irq_claims_i[counter]) begin
claim_array[identifier_of_largest_priority_per_target[counter]][counter] <= 1;
// save claim for later when the complete-notification arrives
save_claims_array_q[identifier_of_largest_priority_per_target[counter]][counter] <= 1;
end else begin
// if a complete is issued, check if that gateway has previously been claimed by
// this target and forward the
// complete message to that gateway. if no claim has previously been issued, the
// complete message is ignored
if (target_irq_completes_i[counter] && (save_claims_array_q[target_irq_completes_identifier_i[counter]][counter] > 0)) begin
complete_array[target_irq_completes_identifier_i[counter]][counter] <= 1;
save_claims_array_q[target_irq_completes_identifier_i[counter]][counter] <= 0;
end
end
end
end
end
// the outputs for an id are the ORs of all targets for that id
always_comb begin : proc_result_computation
for (integer gateway = 1; gateway <= NUM_GATEWAYS; gateway++) begin
automatic logic is_claimed = '0;
automatic logic is_completed = '0;
for (integer target = 0; target < NUM_TARGETS; target++) begin
is_claimed = is_claimed | claim_array [gateway][target];
is_completed = is_completed | complete_array[gateway][target];
end
if (is_claimed) begin
gateway_irq_claims_o [gateway-1] = 1;
end else begin
gateway_irq_claims_o [gateway-1] = 0;
end
if (is_completed) begin
gateway_irq_completes_o[gateway-1] = 1;
end else begin
gateway_irq_completes_o[gateway-1] = 0;
end
end
end
endmodule //plic_claim_complete_tracker

View file

@ -1,63 +0,0 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
//-------------------------------------------------------------------------------
//-- Title : Comperator
//-- File : plic_comperator.sv
//-- Author : Gian Marti <gimarti.student.ethz.ch>
//-- Author : Thomas Kramer <tkramer.student.ethz.ch>
//-- Author : Thomas E. Benz <tbenz.student.ethz.ch>
//-- Company : Integrated Systems Laboratory, ETH Zurich
//-- Created : 2018-03-31
//-- Last update: 2018-03-31
//-- Platform : ModelSim (simulation), Synopsys (synthesis)
//-- Standard : SystemVerilog IEEE 1800-2012
//-------------------------------------------------------------------------------
//-- Description: Comparator
//-------------------------------------------------------------------------------
//-- Revisions :
//-- Date Version Author Description
//-- 2018-03-31 2.0 tbenz Created header
//-------------------------------------------------------------------------------
// find larger operand (value and identifier)
// chooses the left operand on equality
module plic_comparator #(
parameter int ID_BITWIDTH = -1,
parameter int PRIORITY_BITWIDTH = -1
)(
input logic [PRIORITY_BITWIDTH-1:0] left_priority_i,
input logic [PRIORITY_BITWIDTH-1:0] right_priority_i,
input logic [ID_BITWIDTH-1:0 ] left_identifier_i,
input logic [ID_BITWIDTH-1:0 ] right_identifier_i,
output logic [PRIORITY_BITWIDTH-1:0] larger_priority_o,
output logic[ ID_BITWIDTH-1:0 ] identifier_of_larger_o
);
always_comb begin : proc_compare
if (left_priority_i >= right_priority_i) begin
larger_priority_o = left_priority_i;
identifier_of_larger_o = left_identifier_i;
end else begin
larger_priority_o = right_priority_i;
identifier_of_larger_o = right_identifier_i;
end
end
//pragma translate_off
`ifndef VERILATOR
initial begin
assert(ID_BITWIDTH > 0) else $error("ID_BITWIDTH has to be larger than 0");
assert(PRIORITY_BITWIDTH > 0) else $error("PRIORITY_BITWIDTH has to be larger than 0");
end
`endif
//pragma translate_on
endmodule

View file

@ -1,78 +0,0 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
//-------------------------------------------------------------------------------
//-- Title : Find Maximun
//-- File : plic_find_max.sv
//-- Author : Gian Marti <gimarti.student.ethz.ch>
//-- Author : Thomas Kramer <tkramer.student.ethz.ch>
//-- Author : Thomas E. Benz <tbenz.student.ethz.ch>
//-- Company : Integrated Systems Laboratory, ETH Zurich
//-- Created : 2018-03-31
//-- Last update: 2018-03-31
//-- Platform : ModelSim (simulation), Synopsys (synthesis)
//-- Standard : SystemVerilog IEEE 1800-2012
//-------------------------------------------------------------------------------
//-- Description: Find the element with the largest priority
//-------------------------------------------------------------------------------
//-- Revisions :
//-- Date Version Author Description
//-- 2018-03-31 2.0 tbenz Created header
//-------------------------------------------------------------------------------
module plic_find_max #(
parameter int NUM_OPERANDS = 2,
parameter int ID_BITWIDTH = 4,
parameter int PRIORITY_BITWIDTH = 3
)(
input logic [PRIORITY_BITWIDTH-1:0] priorities_i [NUM_OPERANDS],
input logic [ID_BITWIDTH-1:0 ] identifiers_i [NUM_OPERANDS],
output logic [PRIORITY_BITWIDTH-1:0] largest_priority_o,
output logic [ID_BITWIDTH-1:0 ] identifier_of_largest_o
);
localparam int max_stage = ($clog2(NUM_OPERANDS)-1);
localparam int num_operands_aligned = 2**(max_stage+1);
logic [PRIORITY_BITWIDTH-1:0] priority_stages [max_stage + 2][num_operands_aligned];
logic [ID_BITWIDTH-1:0 ] identifier_stages [max_stage + 2][num_operands_aligned];
always_comb begin : proc_zero_padding
for (integer operand = 0; operand < num_operands_aligned; operand++) begin
if(operand < NUM_OPERANDS) begin
priority_stages [0][operand] = priorities_i [operand];
identifier_stages[0][operand] = identifiers_i [operand];
end else begin
priority_stages [0][operand] = '0;
identifier_stages[0][operand] = '0;
end
end
end
for (genvar comparator_stage = max_stage; comparator_stage >= 0 ; comparator_stage--) begin
for (genvar stage_index = 0; stage_index < 2**comparator_stage; stage_index++) begin
plic_comparator #(
.ID_BITWIDTH (ID_BITWIDTH ),
.PRIORITY_BITWIDTH (PRIORITY_BITWIDTH )
) comp_instance(
.left_priority_i ( priority_stages [max_stage - comparator_stage][2*stage_index] ),
.right_priority_i ( priority_stages [max_stage - comparator_stage][2*stage_index + 1] ),
.left_identifier_i ( identifier_stages[max_stage - comparator_stage][2*stage_index] ),
.right_identifier_i ( identifier_stages[max_stage - comparator_stage][2*stage_index + 1] ),
.larger_priority_o ( priority_stages [max_stage - (comparator_stage-1)][stage_index] ),
.identifier_of_larger_o ( identifier_stages[max_stage - (comparator_stage-1)][stage_index] )
);
end
end
assign largest_priority_o = priority_stages [max_stage+1][0];
assign identifier_of_largest_o = identifier_stages[max_stage+1][0];
endmodule

View file

@ -1,80 +0,0 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
//-------------------------------------------------------------------------------
//-- Title : Interrupt Gateway
//-- File : plic_gateway.sv
//-- Author : Gian Marti <gimarti.student.ethz.ch>
//-- Author : Thomas Kramer <tkramer.student.ethz.ch>
//-- Author : Thomas E. Benz <tbenz.student.ethz.ch>
//-- Company : Integrated Systems Laboratory, ETH Zurich
//-- Created : 2018-03-31
//-- Last update: 2018-03-31
//-- Platform : ModelSim (simulation), Synopsys (synthesis)
//-- Standard : SystemVerilog IEEE 1800-2012
//-------------------------------------------------------------------------------
//-- Description: Implementation of the Irq Gateway
//-------------------------------------------------------------------------------
//-- Revisions :
//-- Date Version Author Description
//-- 2018-03-31 2.0 tbenz Created header
//-------------------------------------------------------------------------------
// the gateway does enable or disable itself depending on the signals claim_i, completed_i
// the gateway knows neither its gateway_id nor its priority
module plic_gateway (
input logic clk_i,
input logic rst_ni,
input logic irq_source_i,
input logic claim_i,
input logic completed_i,
output logic irq_pending_o
);
logic irq_pending_q; // is 1 when an interrupt appears until the interrupt is claimed
logic wait_completion_q; // is 1 when an interrupt appears until the interrupt is completed
// also determines if the gateway is disabled, i.e. if interrupts are masked
logic irq_trigger;
assign irq_trigger = (~wait_completion_q | completed_i) & irq_source_i;
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_update_ff
if (~rst_ni) begin
irq_pending_q <= 1'b0;
wait_completion_q <= 1'b0;
end else begin
//pragma translate_off
`ifndef VERILATOR
assert (~(claim_i & (~wait_completion_q & irq_source_i)));
assert (~(completed_i & (~wait_completion_q & irq_source_i)));
`endif
//pragma translate_on
//interrupts not masked and interrupt received -> output to 1
if (irq_trigger) begin
irq_pending_q <= 1;
//interrupt claimed -> output to 0
end else if (claim_i) begin
irq_pending_q <= 0;
end
//interrupts not masked and interrupt received -> interrupts masked from know on
if (irq_trigger) begin
wait_completion_q <= 1;
//interrupt completed -> demask interrupts
end else if (completed_i) begin
wait_completion_q <= 0;
end
end
end
// Make sure there is 0 cycles delay from claim_i to irq_pending_o.
assign irq_pending_o = (irq_pending_q | irq_trigger) & ~claim_i;
endmodule

View file

@ -1,304 +0,0 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
//-------------------------------------------------------------------------------
//-- Title : Register Interface
//-- File : plic_target_slice.sv
//-- Author : Gian Marti <gimarti.student.ethz.ch>
//-- Author : Thomas Kramer <tkramer.student.ethz.ch>
//-- Author : Thomas E. Benz <tbenz.student.ethz.ch>
//-- Company : Integrated Systems Laboratory, ETH Zurich
//-- Created : 2018-03-31
//-- Last update: 2018-03-31
//-- Platform : ModelSim (simulation), Synopsys (synthesis)
//-- Standard : SystemVerilog IEEE 1800-2012
//-------------------------------------------------------------------------------
//-- Description: Implementation of the plic's register interface
//-------------------------------------------------------------------------------
//-- Revisions :
//-- Date Version Author Description
//-- 2018-03-31 2.0 tbenz Created header
//-------------------------------------------------------------------------------
module plic_interface #(
parameter int ADDR_WIDTH = 32, // width of external address bus
parameter int DATA_WIDTH = 32, // width of external data bus
parameter int ID_BITWIDTH = 10, // width of the gateway indecies
parameter int PARAMETER_BITWIDTH = 3, // width of the internal parameter e.g. priorities
parameter int NUM_TARGETS = 1, // number of target slices
parameter int NUM_GATEWAYS = 1 // number of gateways
)(
input logic clk_i, // the clock signal
input logic rst_ni, // asynchronous reset active low
input logic[ID_BITWIDTH-1:0] id_of_largest_priority_i[NUM_TARGETS], // input array id of largest priority
input logic pending_array_i[NUM_GATEWAYS], // array with the interrupt pending , idx0 is gateway 1
output reg [PARAMETER_BITWIDTH-1:0] thresholds_o[NUM_TARGETS], // save internally the thresholds, communicate values over this port to the core
output reg [PARAMETER_BITWIDTH-1:0] gateway_priorities_o[NUM_GATEWAYS], // save internally the the priorities, communicate values
output logic irq_enables_o[NUM_GATEWAYS][NUM_TARGETS], // communicate enable bits over this port
output logic target_irq_claims_o[NUM_TARGETS], // claim signals
output logic target_irq_completes_o[NUM_TARGETS], // complete signals
output logic[ID_BITWIDTH-1:0] target_irq_completes_id_o[NUM_TARGETS], // the id of the gateway to be completed
REG_BUS.in external_bus_io // the bus
);
//define ennumerated types
enum logic [2:0] {INV, PRI, IPA, IEB, THR, CCP} funct; // the address mapping will primarily check what
// function should be performed
// INV: invalid, PRI: priorities, IPA: interrupt pending
// IEB: interrupt enable, THR: threshold and claim/complete
// CCP: claim/clear pulses
//calculate some parameter needed later
localparam int num_gateway_bundles = (NUM_GATEWAYS-1) / DATA_WIDTH + 1; // how many bundles we have to consider
localparam int bpw = DATA_WIDTH / 8; // how many bytes a data word consist of
//internal signals
logic [ADDR_WIDTH-12-1:0 ] page_address; // the upper part of the address
logic [11:0 ] page_offset; // the lowest 12 bit describes the page offset
logic [11-$clog2(bpw):0 ] page_word_offset; // the word address of each page offset
logic [$clog2(bpw)-1:0 ] word_offset; // the byte in the word
logic [DATA_WIDTH/8-1:0 ] write_active; // 0 if inactive, else what byte ahs to be written
logic read_active; // 0 if inactive, 1 when reading the word
//bundle definitions
logic [DATA_WIDTH-1:0 ] irq_pending_bundle[num_gateway_bundles];
//registers
logic [PARAMETER_BITWIDTH-1:0] thresholds_d[NUM_TARGETS];
logic [PARAMETER_BITWIDTH-1:0] thresholds_q[NUM_TARGETS];
logic [PARAMETER_BITWIDTH-1:0] priorities_d[NUM_GATEWAYS];
logic [PARAMETER_BITWIDTH-1:0] priorities_q[NUM_GATEWAYS];
logic [ID_BITWIDTH-1:0 ] id_of_largest_priority_d[NUM_TARGETS];
logic [ID_BITWIDTH-1:0 ] id_of_largest_priority_q[NUM_TARGETS];
logic [DATA_WIDTH/bpw-1:0 ] ena_bundles_d[num_gateway_bundles][NUM_TARGETS][DATA_WIDTH/8];
logic [DATA_WIDTH/bpw-1:0 ] ena_bundles_q[num_gateway_bundles][NUM_TARGETS][DATA_WIDTH/8];
// assignments
assign id_of_largest_priority_d = id_of_largest_priority_i;
// assign addresses
assign page_address = external_bus_io.addr[ADDR_WIDTH-1:12];
assign page_offset = external_bus_io.addr[11:0 ];
assign page_word_offset = external_bus_io.addr[11:$clog2(bpw) ];
assign word_offset = external_bus_io.addr[$clog2(bpw)-1:0];
assign write_active = (external_bus_io.valid & external_bus_io.write) ? external_bus_io.wstrb : '0;
assign read_active = external_bus_io.valid & !external_bus_io.write;
// bundle signals
for (genvar bundle = 0; bundle < num_gateway_bundles; bundle++) begin
for (genvar ip_bit = 0; ip_bit < DATA_WIDTH; ip_bit++) begin
if (bundle * DATA_WIDTH + ip_bit < NUM_GATEWAYS) begin
assign irq_pending_bundle[bundle][ip_bit] = pending_array_i[bundle * DATA_WIDTH + ip_bit];
end else begin
assign irq_pending_bundle[bundle][ip_bit] = '0;
end
end
end
for (genvar bundle = 0; bundle < num_gateway_bundles; bundle++) begin
for (genvar target = 0; target < NUM_TARGETS; target++) begin
for (genvar byte_in_word = 0; byte_in_word < DATA_WIDTH/8; byte_in_word++) begin
for (genvar enable_bit = 0; enable_bit < 8; enable_bit++) begin
assign irq_enables_o[bundle * DATA_WIDTH + enable_bit + byte_in_word * 8][target] =
ena_bundles_q[bundle][target][byte_in_word][enable_bit];
end
end
end
end
// determine the function to be performed
always_comb begin : proc_address_map
// default values
funct = INV;
// only aligned access is allowed:
if (word_offset == '0) begin
// we have now an word alligned access -> check out page offset to determine
// what type of access this is.
if (page_address[13:0] == 0) begin // we access the gateway priority bits
// the page_word_offset tells us now which gateway we consider
// in order to grant or deny access, we have to check if the gateway
// in question really exist.
// Gateway 0 does not exist, so return an error
if (page_word_offset <= NUM_GATEWAYS && page_word_offset > 0) begin //the gateway in question exists
// set the current operation to be an access to the priority registers
funct = PRI;
end
// we now access the IP Bits, read only
end else if (page_address[13:0] == 1) begin
// the page_word_offset tells us now, which word we have to consider,
// the word, which includes the IP bit in question should be returned
if (page_word_offset<num_gateway_bundles) begin
funct = IPA;
end
// access of the enable bits for each target
end else if (page_address[13:9] == 0) begin
// the bottom part page_word_offset now tells us which gateway bundle we have to consider
// part of the page_address and the upper part of the page_word_offset give us the target nr.
if (page_offset[6:$clog2(bpw)] < num_gateway_bundles) begin
if (({page_address[8:0], page_offset[11:7]} - 64) < NUM_TARGETS) begin
funct = IEB;
end
end
// priority / claim / complete
end else begin
// page address - 0h20 gives the target number
if (page_address[13:0] - 'h200 < NUM_TARGETS) begin
// check lowest bit of the page_word_offset to get the exact function
if (page_word_offset == 0) begin
funct = THR;
end else if (page_word_offset == 1) begin
funct = CCP;
end
end
end
end
end
always_comb begin : proc_read_write
// defalt values
external_bus_io.rdata = 0;
external_bus_io.error = 0;
external_bus_io.ready = 0;
for (integer target = 0; target<NUM_TARGETS; target++) begin
target_irq_claims_o [target] = '0;
target_irq_completes_o [target] = '0;
target_irq_completes_id_o[target] = '0;
end
//just keep the values untouched as default
priorities_d = priorities_q;
ena_bundles_d = ena_bundles_q;
thresholds_d = thresholds_q;
case (funct)
PRI: begin
// read case
if (read_active != 0) begin
external_bus_io.rdata = priorities_q[page_word_offset-1];
external_bus_io.ready = 1;
// write case
end else if (write_active[0] == 1) begin
priorities_d[page_word_offset-1] = external_bus_io.wdata[PARAMETER_BITWIDTH-1:0];
external_bus_io.ready = 1;
end
end
IPA: begin
// read case
if (read_active != 0) begin
external_bus_io.rdata = irq_pending_bundle[page_word_offset];
external_bus_io.ready = 1;
// write case
end else if (write_active != 0) begin
external_bus_io.error = 1; //not allowed
end
end
IEB: begin
// read case
if (read_active != 0) begin
for (integer byte_in_word = 0; byte_in_word < DATA_WIDTH/8; byte_in_word++) begin
external_bus_io.rdata[8*(byte_in_word) +: 8] = ena_bundles_q[page_offset[6:$clog2(bpw)]][({page_address[8:0], page_offset[11:7]} - 64)][byte_in_word];
end
external_bus_io.ready = 1;
// write case
end else if(write_active != 0) begin
for (integer byte_in_word=0; byte_in_word<DATA_WIDTH/8; byte_in_word++) begin
if(write_active[byte_in_word]) begin
ena_bundles_d[page_offset[6:$clog2(bpw)]][({page_address[8:0], page_offset[11:7]} - 64)][byte_in_word] = external_bus_io.wdata[8*(byte_in_word) +: 8];
end
end
external_bus_io.ready = 1;
end
end
THR: begin
// read case
if (read_active != 0) begin
external_bus_io.rdata[PARAMETER_BITWIDTH-1:0] = thresholds_q[(page_address[13:0] - 'h200)];
external_bus_io.ready = 1;
// write case
end else if (write_active != 0) begin
thresholds_d[(page_address[13:0] - 'h200)] = external_bus_io.wdata[PARAMETER_BITWIDTH-1:0];
external_bus_io.ready = 1;
end
end
CCP: begin
// read case
if (read_active != 0) begin
target_irq_claims_o[(page_address[13:0] - 'h200)] = 1;
external_bus_io.rdata[ID_BITWIDTH-1:0] = id_of_largest_priority_q[(page_address[13:0] - 'h200)];
external_bus_io.ready = 1;
// write case
end else if (write_active != 0) begin
target_irq_completes_o[(page_address[13:0] - 'h200)] = 1;
target_irq_completes_id_o[(page_address[13:0] - 'h200)] = external_bus_io.wdata[ID_BITWIDTH-1:0];
external_bus_io.ready = 1;
end
end
default : begin
//per default: error
external_bus_io.error = 1;
external_bus_io.ready = 1;
end
endcase // funct
end
// store data in flip flops
always_ff @(posedge clk_i or negedge rst_ni) begin : proc_update_ff
if (~rst_ni) begin // set all registers to 0
for (integer gateway = 0; gateway < NUM_GATEWAYS; gateway++)
priorities_q[gateway] <= 0;
for (integer bundle = 0; bundle < num_gateway_bundles; bundle++)
for (integer target = 0; target < NUM_TARGETS; target++)
for (integer byte_in_word = 0; byte_in_word < DATA_WIDTH/8; byte_in_word++)
ena_bundles_q[bundle][target][byte_in_word] <= 0;
for (integer target = 0; target < NUM_TARGETS; target++) begin
thresholds_q[target] <= 0;
id_of_largest_priority_q[target] <= 0;
end
end else begin
priorities_q <= priorities_d;
ena_bundles_q <= ena_bundles_d;
thresholds_q <= thresholds_d;
id_of_largest_priority_q <= id_of_largest_priority_d;
end
end
//assign outputs
assign thresholds_o = thresholds_q;
assign gateway_priorities_o = priorities_q;
// pragma translate_off
`ifndef VERILATOR
initial begin
assert ((ADDR_WIDTH==32) | (ADDR_WIDTH==64)) else $error("Address width has to bei either 32 or 64 bit");
assert ((DATA_WIDTH==32) | (DATA_WIDTH==64)) else $error("Data width has to bei either 32 or 64 bit");
assert (ID_BITWIDTH>0) else $error("ID_BITWIDTH has to be larger than 1");
assert (ID_BITWIDTH<10) else $error("ID_BITWIDTH has to be smaller than 10");
assert (PARAMETER_BITWIDTH>0) else $error("PARAMETER_BITWIDTH has to be larger than 1");
assert (PARAMETER_BITWIDTH<8) else $error("PARAMETER_BITWIDTH has to be smaller than 8");
assert (NUM_GATEWAYS>0) else $error("Num od Gateways has to be larger than 1");
assert (NUM_GATEWAYS<512) else $error("Num of Gateways has to be smaller than 512");
assert (NUM_TARGETS>0) else $error("Num Target slices has to be larger than 1");
assert (NUM_TARGETS<15872) else $error("Num target slices has to be smaller than 15872");
end
`endif
// pragma translate_on
endmodule

View file

@ -1,92 +0,0 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
//-------------------------------------------------------------------------------
//-- Title : Target Slice
//-- File : plic_target_slice.sv
//-- Author : Gian Marti <gimarti.student.ethz.ch>
//-- Author : Thomas Kramer <tkramer.student.ethz.ch>
//-- Author : Thomas E. Benz <tbenz.student.ethz.ch>
//-- Company : Integrated Systems Laboratory, ETH Zurich
//-- Created : 2018-03-31
//-- Last update: 2018-03-31
//-- Platform : ModelSim (simulation), Synopsys (synthesis)
//-- Standard : SystemVerilog IEEE 1800-2012
//-------------------------------------------------------------------------------
//-- Description: Target Slice
//-------------------------------------------------------------------------------
//-- Revisions :
//-- Date Version Author Description
//-- 2018-03-31 2.0 tbenz Created header
//-------------------------------------------------------------------------------
// Note: The gateways are expected to be ordered by their IDs (ascending).
// This resolves priority ties by choosing the gateway with the lower ID.
module plic_target_slice #(
parameter int PRIORITY_BITWIDTH = 8,
parameter int ID_BITWIDTH = 8,
parameter int NUM_GATEWAYS = 1
)(
// Input signals from gateways.
input logic interrupt_pending_i [NUM_GATEWAYS],
input logic [PRIORITY_BITWIDTH-1:0] interrupt_priority_i[NUM_GATEWAYS],
input logic [ID_BITWIDTH-1:0 ] interrupt_id_i [NUM_GATEWAYS],
input logic interrupt_enable_i [NUM_GATEWAYS],
input logic [PRIORITY_BITWIDTH-1:0] threshold_i,
output logic ext_interrupt_present_o,
output logic [ID_BITWIDTH-1:0 ] identifier_of_largest_o
);
logic[PRIORITY_BITWIDTH:0] interrupt_priority_masked[NUM_GATEWAYS];
// Signals that represent the selected interrupt source.
logic[PRIORITY_BITWIDTH:0] best_priority;
logic[ID_BITWIDTH-1:0 ] best_id;
// Create a tree to find the best interrupt source.
plic_find_max #(
.NUM_OPERANDS ( NUM_GATEWAYS ),
.ID_BITWIDTH ( ID_BITWIDTH ),
.PRIORITY_BITWIDTH ( PRIORITY_BITWIDTH + 1 )
) find_max_instance (
.priorities_i ( interrupt_priority_masked ),
.identifiers_i ( interrupt_id_i ),
// Outputs
.largest_priority_o ( best_priority ),
.identifier_of_largest_o ( best_id )
);
// Compare the priority of the best interrupt source to the threshold.
always_comb begin : proc_compare_threshold
if ((best_priority - 1 > threshold_i) && (best_priority != '0)) begin
ext_interrupt_present_o = 1;
identifier_of_largest_o = best_id;
end else begin
if ((best_priority - 1 <= threshold_i) && (best_priority != '0)) begin
ext_interrupt_present_o = 0;
identifier_of_largest_o = best_id;
end else begin
ext_interrupt_present_o = 0;
identifier_of_largest_o = 0;
end
end
end
always_comb begin : proc_mask_gateway_outputs
for (int i = 0; i < NUM_GATEWAYS; i++) begin
if (interrupt_enable_i[i] && interrupt_pending_i[i]) begin
interrupt_priority_masked[i] = interrupt_priority_i[i] + 1; //priority shift +1
end else begin
interrupt_priority_masked[i] = '0;
end
end
end
endmodule

@ -1 +1 @@
Subproject commit d10dce04b7211da044d31baaa06c7044c84083d9
Subproject commit d8aeccc65fdbbb30ef9dd28e065c2947a2396eab

1
src/rv_plic Submodule

@ -0,0 +1 @@
Subproject commit 6046cfa518237c06031e65030f250bb29555e913

View file

@ -148,17 +148,31 @@ module ariane_peripherals #(
.reg_o ( reg_bus )
);
plic #(
.ID_BITWIDTH ( ariane_soc::PLICIdWidth ),
.PARAMETER_BITWIDTH ( ariane_soc::ParameterBitwidth ),
.NUM_TARGETS ( ariane_soc::NumTargets ),
.NUM_SOURCES ( ariane_soc::NumSources )
reg_intf::reg_intf_resp_d32 plic_resp;
reg_intf::reg_intf_req_a32_d32 plic_req;
assign plic_req.addr = reg_bus.addr;
assign plic_req.write = reg_bus.write;
assign plic_req.wdata = reg_bus.wdata;
assign plic_req.wstrb = reg_bus.wstrb;
assign plic_req.valid = reg_bus.valid;
assign reg_bus.rdata = plic_resp.rdata;
assign reg_bus.error = plic_resp.error;
assign reg_bus.ready = plic_resp.ready;
plic_top #(
.N_SOURCE ( ariane_soc::NumSources ),
.N_TARGET ( ariane_soc::NumTargets ),
.MAX_PRIO ( ariane_soc::MaxPriority )
) i_plic (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.irq_sources_i ( irq_sources ),
.eip_targets_o ( irq_o ),
.external_bus_io ( reg_bus )
.clk_i,
.rst_ni,
.req_i ( plic_req ),
.resp_o ( plic_resp ),
.le_i ( '0 ), // 0:level 1:edge
.irq_sources_i ( irq_sources ),
.eip_targets_o ( irq_o )
);
// ---------------

View file

@ -12,11 +12,11 @@
// Description: Contains SoC information as constants
package ariane_soc;
// M-Mode Hart, S-Mode Hart
localparam NumTargets = 2;
// Uart, SPI, Ethernet
localparam NumSources = 3;
localparam PLICIdWidth = 3;
localparam ParameterBitwidth = PLICIdWidth;
localparam int unsigned NumTargets = 2;
// Uart, SPI, Ethernet, reserved
localparam int unsigned NumSources = 30;
localparam int unsigned MaxPriority = 7;
localparam NrSlaves = 2; // actually masters, but slaves on the crossbar
// 4 is recommended by AXI standard, so lets stick to it, do not change