This commit is contained in:
Florian Zaruba 2018-09-17 17:09:04 +02:00
parent d29a334fe0
commit ab5b5dd670
No known key found for this signature in database
GPG key ID: E742FFE8EC38A792
6 changed files with 792 additions and 0 deletions

View file

@ -0,0 +1,63 @@
// 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

155
src/plic/plic_core.sv Normal file
View file

@ -0,0 +1,155 @@
// 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_core #(
parameter int ADDR_WIDTH = -1, //width of external address bus
parameter int DATA_WIDTH = -1, //width of external data bus
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 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

78
src/plic/plic_find_max.sv Normal file
View file

@ -0,0 +1,78 @@
// 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

80
src/plic/plic_gateway.sv Normal file
View file

@ -0,0 +1,80 @@
// 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

322
src/plic/plic_interface.sv Normal file
View file

@ -0,0 +1,322 @@
// 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 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];
//debug signals (only used in the wave...)
logic [31:0] gw_bundle;
logic [31:0] tar;
logic [31:0] gw;
//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;
gw_bundle = 'z;
tar = 'z;
gw = 'z;
//only alligned 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;
//debug:
gw = page_word_offset;
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;
//debug:
gw_bundle = page_word_offset;
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;
// debug:
gw_bundle = page_offset[6:$clog2(bpw)];
tar = ({page_address[8:0], page_offset[11:7]} - 64);
end
end
//priority / claim / complete
end else begin
//page address - 0h20 gives the target number
if (page_address[13:0] - 'h200 < NUM_TARGETS) begin
//debug:
tar = page_address[13:0] - 'h200;
//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_off
endmodule

View file

@ -0,0 +1,94 @@
// 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];
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
// 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
endmodule