Initial load of files
This commit is contained in:
41
src_Core/PLIC/Makefile
Normal file
41
src_Core/PLIC/Makefile
Normal file
@@ -0,0 +1,41 @@
|
||||
# Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
# Makefile to create Test_PLIC and PLIC into a standalone unit-test executable.
|
||||
|
||||
# Edit the StmtFSM in Test_PLIC to create different tests.
|
||||
|
||||
# ----------------
|
||||
|
||||
REPO = $(HOME)/GitHub/Flute
|
||||
|
||||
# ----------------
|
||||
# Top-level file and module
|
||||
|
||||
TOPFILE ?= $(REPO)/src_Core/PLIC/Test_PLIC.bsv
|
||||
TOPMODULE ?= mkTest_PLIC
|
||||
|
||||
# ================================================================
|
||||
# RISC-V config macros passed into Bluespec 'bsc' compiler
|
||||
|
||||
BSC_COMPILATION_FLAGS += \
|
||||
-D RV64 \
|
||||
-D ISA_PRIV_M -D ISA_PRIV_U -D ISA_PRIV_S \
|
||||
-D SV39 \
|
||||
-D ISA_I -D ISA_M -D ISA_A \
|
||||
-D SHIFT_BARREL \
|
||||
-D MULT_SYNTH \
|
||||
-D Near_Mem_Caches \
|
||||
-D FABRIC64 \
|
||||
|
||||
|
||||
# ================================================================
|
||||
# Common boilerplate rules
|
||||
|
||||
include $(REPO)/builds/Resources/Include_Common.mk
|
||||
|
||||
# ================================================================
|
||||
# Makefile rules for building for specific simulator: bluesim
|
||||
|
||||
include $(REPO)/builds/Resources/Include_bluesim.mk
|
||||
|
||||
# ================================================================
|
||||
623
src_Core/PLIC/PLIC.bsv
Normal file
623
src_Core/PLIC/PLIC.bsv
Normal file
@@ -0,0 +1,623 @@
|
||||
// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package PLIC;
|
||||
|
||||
// ================================================================
|
||||
// This package implements a PLIC (Platform-Level Interrupt Controller)
|
||||
// conforming to the RISC-V PLIC standard.
|
||||
// It is parameterized for:
|
||||
// - # of sources
|
||||
// - # of targets
|
||||
// - # of priorities
|
||||
//
|
||||
// ================================================================
|
||||
// Bluespec lib imports
|
||||
|
||||
import ConfigReg :: *;
|
||||
import Vector :: *;
|
||||
import FIFOF :: *;
|
||||
import ClientServer :: *;
|
||||
import Assert :: *;
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
import GetPut_Aux :: *;
|
||||
import Semi_FIFOF :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import AXI4_Types :: *;
|
||||
import AXI4_Fabric :: *;
|
||||
import Fabric_Defs :: *; // for Wd_Id, Wd_Addr, Wd_Data, Wd_User
|
||||
|
||||
// ================================================================
|
||||
// Change bitwidth without requiring < or > constraints.
|
||||
|
||||
function Bit #(m) changeWidth (Bit #(n) x);
|
||||
Bit #(TAdd #(m, n)) y = zeroExtend (x);
|
||||
Bit #(m) z = y [valueOf (m)-1 : 0];
|
||||
return z;
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// Maximum supported sources, targets, ...
|
||||
|
||||
typedef 10 T_wd_source_id; // Max 1024 sources (source 0 is reserved for 'no interrupt')
|
||||
typedef 5 T_wd_target_id; // Max 32 targets
|
||||
|
||||
// ================================================================
|
||||
// Interfaces
|
||||
|
||||
// ----------------
|
||||
// Individual source interface
|
||||
|
||||
interface PLIC_Source_IFC;
|
||||
(* always_ready, always_enabled *)
|
||||
method Action m_interrupt_req (Bool set_not_clear);
|
||||
endinterface
|
||||
|
||||
// ----------------
|
||||
// Individual target interface
|
||||
|
||||
interface PLIC_Target_IFC;
|
||||
(* always_ready *)
|
||||
method Bool m_eip; // external interrupt pending
|
||||
endinterface
|
||||
|
||||
// ----------------
|
||||
// PLIC interface
|
||||
|
||||
interface PLIC_IFC #(numeric type t_n_external_sources,
|
||||
numeric type t_n_targets,
|
||||
numeric type t_max_priority);
|
||||
// Debugging
|
||||
method Action set_verbosity (Bit #(4) verbosity);
|
||||
method Action show_PLIC_state;
|
||||
|
||||
// Reset
|
||||
interface Server #(Bit #(0), Bit #(0)) server_reset;
|
||||
|
||||
// set_addr_map should be called after this module's reset
|
||||
method Action set_addr_map (Bit #(64) addr_base, Bit #(64) addr_lim);
|
||||
|
||||
// Memory-mapped access
|
||||
interface AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) axi4_slave;
|
||||
|
||||
// sources
|
||||
interface Vector #(t_n_external_sources, PLIC_Source_IFC) v_sources;
|
||||
|
||||
// targets EIPs (External Interrupt Pending)
|
||||
interface Vector #(t_n_targets, PLIC_Target_IFC) v_targets;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
// PLIC module implementation
|
||||
|
||||
module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
provisos (Add #(1, t_n_external_sources, t_n_sources), // source 0 is reserved for 'no source'
|
||||
Add #(_any_0, TLog #(t_n_sources), T_wd_source_id),
|
||||
Add #(_any_1, TLog #(t_n_targets), T_wd_target_id),
|
||||
Log #(TAdd #(t_max_priority, 1), t_wd_priority));
|
||||
|
||||
Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
|
||||
|
||||
// Source_Ids and Priorities are read and written over the memory interface
|
||||
// and should fit within the data bus width, currently 64 bits.
|
||||
staticAssert ((valueOf (TLog #(t_n_sources)) <= 64), "PLIC: t_n_sources parameter too large");
|
||||
staticAssert ((valueOf (TLog #(TAdd #(t_max_priority, 1))) <= 64), "PLIC: t_max_priority parameter too large");
|
||||
|
||||
Integer n_sources = valueOf (t_n_sources);
|
||||
Integer n_targets = valueOf (t_n_targets);
|
||||
|
||||
// ----------------
|
||||
// Soft reset requests and responses
|
||||
FIFOF #(Bit #(0)) f_reset_reqs <- mkFIFOF;
|
||||
FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF;
|
||||
|
||||
// ----------------
|
||||
// Memory-mapped access
|
||||
|
||||
// Base and limit addrs for this memory-mapped block.
|
||||
Reg #(Bit #(64)) rg_addr_base <- mkRegU;
|
||||
Reg #(Bit #(64)) rg_addr_lim <- mkRegU;
|
||||
|
||||
// Connector to AXI4 fabric
|
||||
AXI4_Slave_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) slave_xactor <- mkAXI4_Slave_Xactor;
|
||||
|
||||
// ----------------
|
||||
// Per-interrupt source state
|
||||
|
||||
// Interrupt pending from source
|
||||
Vector #(t_n_sources, Reg #(Bool)) vrg_source_ip <- replicateM (mkConfigReg (False));
|
||||
// Interrupt claimed and being serviced by a hart
|
||||
Vector #(t_n_sources, Reg #(Bool)) vrg_source_busy <- replicateM (mkReg (False));
|
||||
// Priority for this source
|
||||
Vector #(t_n_sources, Reg #(Bit #(t_wd_priority))) vrg_source_prio <- replicateM (mkReg (0));
|
||||
|
||||
// ----------------
|
||||
// Per-target hart context state
|
||||
|
||||
// Threshold: interrupts at or below threshold should be masked out for target
|
||||
Vector #(t_n_targets, Reg #(Bit #(t_wd_priority))) vrg_target_threshold <- replicateM (mkReg ('1));
|
||||
// Target has claimed interrupt for source and is servicing it
|
||||
Vector #(t_n_targets, Reg #(Bit #(TLog #(t_n_sources)))) vrg_servicing_source <- replicateM (mkReg (0));
|
||||
|
||||
// ----------------
|
||||
// Per-target, per-source state
|
||||
|
||||
// Interrupt enables from source to target
|
||||
Vector #(t_n_targets,
|
||||
Vector #(t_n_sources, Reg #(Bool))) vvrg_ie <- replicateM (replicateM (mkReg (False)));
|
||||
|
||||
// ================================================================
|
||||
// Compute outputs for each target (combinational)
|
||||
|
||||
function Tuple2 #(Bit #(t_wd_priority), Bit #(TLog #(t_n_sources)))
|
||||
fn_target_max_prio_and_max_id (Bit #(T_wd_target_id) target_id);
|
||||
|
||||
Bit #(t_wd_priority) max_prio = 0;
|
||||
Bit #(TLog #(t_n_sources)) max_id = 0;
|
||||
|
||||
// Note: source_ids begin at 1, not 0.
|
||||
for (Integer source_id = 1; source_id < n_sources; source_id = source_id + 1)
|
||||
if ( vrg_source_ip [source_id]
|
||||
&& (vrg_source_prio [source_id] > max_prio)
|
||||
&& (vvrg_ie [target_id][source_id])) begin
|
||||
max_id = fromInteger (source_id);
|
||||
max_prio = vrg_source_prio [source_id];
|
||||
end
|
||||
// Assert: if any interrupt is pending (max_id > 0), then prio > 0
|
||||
return tuple2 (max_prio, max_id);
|
||||
endfunction
|
||||
|
||||
function Action fa_show_PLIC_state;
|
||||
action
|
||||
$display ("----------------");
|
||||
$write ("Src IPs :");
|
||||
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
|
||||
$write (" %0d", pack (vrg_source_ip [source_id]));
|
||||
$display ("");
|
||||
|
||||
$write ("Src Prios:");
|
||||
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
|
||||
$write (" %0d", vrg_source_prio [source_id]);
|
||||
$display ("");
|
||||
|
||||
$write ("Src busy :");
|
||||
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
|
||||
$write (" %0d", pack (vrg_source_busy [source_id]));
|
||||
$display ("");
|
||||
|
||||
for (Integer target_id = 0; target_id < n_targets; target_id = target_id + 1) begin
|
||||
$write ("T %0d IEs :", target_id);
|
||||
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
|
||||
$write (" %0d", vvrg_ie [target_id][source_id]);
|
||||
match { .max_prio, .max_id } = fn_target_max_prio_and_max_id (fromInteger (target_id));
|
||||
$display (" MaxPri %0d, Thresh %0d, MaxId %0d, Svcing %0d",
|
||||
max_prio, vrg_target_threshold [target_id], max_id, vrg_servicing_source [target_id]);
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// Soft reset
|
||||
|
||||
rule rl_reset;
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_reset", cur_cycle);
|
||||
|
||||
let x <- pop (f_reset_reqs);
|
||||
|
||||
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1) begin
|
||||
vrg_source_ip [source_id] <= False;
|
||||
vrg_source_busy [source_id] <= False;
|
||||
vrg_source_prio [source_id] <= 0;
|
||||
end
|
||||
|
||||
for (Integer target_id = 0; target_id < n_targets; target_id = target_id + 1) begin
|
||||
// Mask all interrupts with highest threshold
|
||||
vrg_target_threshold [target_id] <= '1;
|
||||
vrg_servicing_source [target_id] <= 0;
|
||||
end
|
||||
|
||||
for (Integer target_id = 0; target_id < n_targets; target_id = target_id + 1)
|
||||
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
|
||||
vvrg_ie [target_id][source_id] <= False;
|
||||
|
||||
slave_xactor.reset;
|
||||
|
||||
f_reset_rsps.enq (?);
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// Bus interface for reading/writing control/status regs
|
||||
// Relative-address map is same as 'SiFive U54-MC Core Complex Manual v1p0'.
|
||||
// Accesses are 4-bytes wide, even though bus may be 64b wide.
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Handle memory-mapped read requests
|
||||
|
||||
rule rl_process_rd_req (! f_reset_reqs.notEmpty);
|
||||
|
||||
let rda <- pop_o (slave_xactor.o_rd_addr);
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: PLIC.rl_process_rd_req:", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
end
|
||||
|
||||
let addr_offset = rda.araddr - rg_addr_base;
|
||||
Bit #(64) rdata = 0;
|
||||
AXI4_Resp rresp = axi4_resp_okay;
|
||||
|
||||
if (rda.araddr < rg_addr_base) begin
|
||||
// Technically this should not happen: the fabric should
|
||||
// never have delivered such an addr to this IP.
|
||||
$display ("%0d: ERROR: PLIC.rl_process_rd_req: unrecognized addr", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
rresp = axi4_resp_decerr;
|
||||
end
|
||||
|
||||
// Source Priority
|
||||
else if (addr_offset < 'h1000) begin
|
||||
Bit #(T_wd_source_id) source_id = truncate (addr_offset [11:2]);
|
||||
if ((0 < source_id) && (source_id <= fromInteger (n_sources - 1))) begin
|
||||
rdata = changeWidth (vrg_source_prio [source_id]);
|
||||
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_rd_req: reading Source Priority: source %0d = 0x%0h",
|
||||
cur_cycle, source_id, rdata);
|
||||
end
|
||||
else
|
||||
rresp = axi4_resp_slverr;
|
||||
end
|
||||
|
||||
// Source IPs (interrupt pending).
|
||||
// Return 32 consecutive IP bits starting with addr.
|
||||
else if (('h1000 <= addr_offset) && (addr_offset < 'h2000)) begin
|
||||
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [11:0], 5'h0 });
|
||||
|
||||
function Bool fn_ip_source_id (Integer source_id_offset);
|
||||
let source_id = source_id_base + fromInteger (source_id_offset);
|
||||
Bool ip_source_id = ( (source_id <= fromInteger (n_sources - 1))
|
||||
? vrg_source_ip [source_id]
|
||||
: False);
|
||||
return ip_source_id;
|
||||
endfunction
|
||||
|
||||
if (source_id_base <= fromInteger (n_sources - 1)) begin
|
||||
Bit #(32) v_ip = pack (genWith (fn_ip_source_id));
|
||||
rdata = changeWidth (v_ip);
|
||||
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_rd_req: reading Intr Pending 32 bits from source %0d = 0x%0h",
|
||||
cur_cycle, source_id_base, rdata);
|
||||
end
|
||||
else
|
||||
rresp = axi4_resp_slverr;
|
||||
end
|
||||
|
||||
// Source IEs (interrupt enables) for a target
|
||||
// Return 32 consecutive IE bits starting with addr.
|
||||
// Target 0 addrs: 2000-207F, Target 1 addrs: 2080-20FF, ...
|
||||
else if (('h2000 <= addr_offset) && (addr_offset < 'h3000)) begin
|
||||
Bit #(T_wd_target_id) target_id = truncate (addr_offset [11:7]);
|
||||
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [6:0], 5'h0 });
|
||||
|
||||
function Bool fn_ie_source_id (Integer source_id_offset);
|
||||
let source_id = fromInteger (source_id_offset) + source_id_base;
|
||||
return ( (source_id <= fromInteger (n_sources - 1))
|
||||
? vvrg_ie [target_id][source_id]
|
||||
: False);
|
||||
endfunction
|
||||
|
||||
if ( (source_id_base <= fromInteger (n_sources - 1))
|
||||
&& (target_id <= fromInteger (n_targets - 1))) begin
|
||||
Bit #(32) v_ie = pack (genWith (fn_ie_source_id));
|
||||
rdata = changeWidth (v_ie);
|
||||
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_rd_req: reading Intr Enable 32 bits from source %0d = 0x%0h",
|
||||
cur_cycle, source_id_base, rdata);
|
||||
end
|
||||
else
|
||||
rresp = axi4_resp_slverr;
|
||||
end
|
||||
|
||||
// Target threshold
|
||||
else if ((addr_offset [31:0] & 32'hFFFF_0FFF) == 32'h0020_0000) begin
|
||||
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
|
||||
if (target_id <= fromInteger (n_targets - 1)) begin
|
||||
rdata = changeWidth (vrg_target_threshold [target_id]);
|
||||
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_rd_req: reading Threshold for target %0d = 0x%0h",
|
||||
cur_cycle, target_id, rdata);
|
||||
end
|
||||
else
|
||||
rresp = axi4_resp_slverr;
|
||||
end
|
||||
|
||||
// Interrupt service claim by target
|
||||
else if ((addr_offset [31:0] & 32'hFFFF_0FFF) == 32'h0020_0004) begin
|
||||
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
|
||||
match { .max_prio, .max_id } = fn_target_max_prio_and_max_id (target_id);
|
||||
Bool eip = (max_prio > vrg_target_threshold [target_id]);
|
||||
if (target_id <= fromInteger (n_targets - 1)) begin
|
||||
if (vrg_servicing_source [target_id] != 0) begin
|
||||
$display ("%0d: ERROR: PLIC: target %0d claiming without prior completion",
|
||||
cur_cycle, target_id);
|
||||
$display (" Still servicing interrupt from source %0d", vrg_servicing_source [target_id]);
|
||||
$display (" Trying to claim service for source %0d", max_id);
|
||||
$display (" Ignoring.");
|
||||
rresp = axi4_resp_slverr;
|
||||
end
|
||||
else begin
|
||||
if (max_id != 0) begin
|
||||
vrg_source_ip [max_id] <= False;
|
||||
vrg_source_busy [max_id] <= True;
|
||||
vrg_servicing_source [target_id] <= truncate (max_id);
|
||||
rdata = changeWidth (max_id);
|
||||
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_rd_req: reading Claim for target %0d = 0x%0h",
|
||||
cur_cycle, target_id, rdata);
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
rresp = axi4_resp_slverr;
|
||||
end
|
||||
|
||||
else
|
||||
rresp = axi4_resp_slverr;
|
||||
|
||||
if (rresp != axi4_resp_okay) begin
|
||||
$display ("%0d: ERROR: PLIC.rl_process_rd_req: unrecognized addr", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
end
|
||||
|
||||
if ((valueOf (Wd_Data) == 64) && ((addr_offset & 'h7) == 'h4))
|
||||
rdata = { rdata [31:0], 32'h0 };
|
||||
|
||||
// Send read-response to bus
|
||||
Fabric_Data x = truncate (rdata);
|
||||
let rdr = AXI4_Rd_Data {rid: rda.arid,
|
||||
rdata: x,
|
||||
rresp: rresp,
|
||||
rlast: True,
|
||||
ruser: rda.aruser};
|
||||
slave_xactor.i_rd_data.enq (rdr);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: PLIC.rl_process_rd_req", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
$display (" ", fshow (rdr));
|
||||
end
|
||||
endrule: rl_process_rd_req
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Handle memory-mapped write requests
|
||||
|
||||
(* descending_urgency = "rl_process_rd_req, rl_process_wr_req" *) // Ad hoc order
|
||||
|
||||
rule rl_process_wr_req (! f_reset_reqs.notEmpty);
|
||||
|
||||
let wra <- pop_o (slave_xactor.o_wr_addr);
|
||||
let wrd <- pop_o (slave_xactor.o_wr_data);
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: PLIC.rl_process_wr_req", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
end
|
||||
|
||||
let addr_offset = wra.awaddr - rg_addr_base;
|
||||
let wdata32 = (((valueOf (Wd_Data) == 64) && ((addr_offset & 'h7) == 'h4))
|
||||
? wrd.wdata [63:32]
|
||||
: wrd.wdata [31:0]);
|
||||
let bresp = axi4_resp_okay;
|
||||
|
||||
if (wra.awaddr < rg_addr_base) begin
|
||||
// Technically this should not happen: the fabric should
|
||||
// never have delivered such an addr to this IP.
|
||||
$display ("%0d: ERROR: PLIC.rl_process_wr_req: unrecognized addr", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
bresp = axi4_resp_decerr;
|
||||
end
|
||||
|
||||
// Source priority
|
||||
else if (addr_offset < 'h1000) begin
|
||||
Bit #(T_wd_source_id) source_id = truncate (addr_offset [11:2]);
|
||||
if ((0 < source_id) && (source_id <= fromInteger (n_sources - 1))) begin
|
||||
vrg_source_prio [source_id] <= changeWidth (wdata32);
|
||||
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_wr_req: writing Source Priority: source %0d = 0x%0h",
|
||||
cur_cycle, source_id, wdata32);
|
||||
end
|
||||
else begin
|
||||
// Note: write to source_id 0 is error; should it just be ignored?
|
||||
bresp = axi4_resp_slverr;
|
||||
end
|
||||
end
|
||||
|
||||
// Source IPs (interrupt pending).
|
||||
// Read-only, so ignore write; just check that addr ok.
|
||||
else if (('h1000 <= addr_offset) && (addr_offset < 'h2000)) begin
|
||||
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [11:0], 5'h0 });
|
||||
|
||||
if (source_id_base <= fromInteger (n_sources - 1)) begin
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_wr_req: Ignoring write to Read-only Intr Pending 32 bits from source %0d",
|
||||
cur_cycle, source_id_base);
|
||||
end
|
||||
else
|
||||
bresp = axi4_resp_slverr;
|
||||
end
|
||||
|
||||
// Source IEs (interrupt enables) for a target
|
||||
// Write 32 consecutive IE bits starting with addr.
|
||||
// Target 0 addrs: 2000-207F, Target 1 addrs: 2080-20FF, ...
|
||||
else if (('h2000 <= addr_offset) && (addr_offset < 'h3000)) begin
|
||||
Bit #(T_wd_target_id) target_id = truncate (addr_offset [11:7]);
|
||||
Bit #(T_wd_source_id) source_id_base = truncate ({ addr_offset [6:0], 5'h0 });
|
||||
|
||||
if ( (source_id_base <= fromInteger (n_sources - 1))
|
||||
&& (target_id <= fromInteger (n_targets - 1))) begin
|
||||
for (Bit #(T_wd_source_id) k = 0; k < 32; k = k + 1) begin
|
||||
Bit #(T_wd_source_id) source_id = source_id_base + k;
|
||||
if (source_id <= fromInteger (n_sources - 1))
|
||||
vvrg_ie [target_id][source_id] <= unpack (wdata32 [k]);
|
||||
end
|
||||
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_wr_req: writing Intr Enable 32 bits for target %0d from source %0d = 0x%0h",
|
||||
cur_cycle, target_id, source_id_base, wdata32);
|
||||
end
|
||||
else
|
||||
bresp = axi4_resp_slverr;
|
||||
end
|
||||
|
||||
// Target threshold
|
||||
else if ((addr_offset [31:0] & 32'hFFFF_0FFF) == 32'h0020_0000) begin
|
||||
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
|
||||
if (target_id <= fromInteger (n_targets - 1)) begin
|
||||
vrg_target_threshold [target_id] <= changeWidth (wdata32);
|
||||
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_wr_req: writing threshold for target %0d = 0x%0h",
|
||||
cur_cycle, target_id, wdata32);
|
||||
end
|
||||
else
|
||||
bresp = axi4_resp_slverr;
|
||||
end
|
||||
|
||||
// Interrupt service completion by target
|
||||
// Actual memory-write-data is irrelevant.
|
||||
else if ((addr_offset [31:0] & 32'hFFFF_0FFF) == 32'h0020_0004) begin
|
||||
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
|
||||
Bit #(T_wd_source_id) source_id = zeroExtend (vrg_servicing_source [target_id]);
|
||||
|
||||
if (target_id <= fromInteger (n_targets - 1)) begin
|
||||
if (vrg_source_busy [source_id]) begin
|
||||
vrg_source_busy [source_id] <= False;
|
||||
vrg_servicing_source [target_id] <= 0;
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_wr_req: writing completion for target %0d for source 0x%0h",
|
||||
cur_cycle, target_id, source_id);
|
||||
end
|
||||
else begin
|
||||
$display ("%0d: ERROR: PLIC: interrupt completion to source that is not being serviced",
|
||||
cur_cycle);
|
||||
$display (" Completion message from target %0d to source %0d", target_id, source_id);
|
||||
$display (" Ignoring");
|
||||
bresp = axi4_resp_slverr;
|
||||
end
|
||||
end
|
||||
else
|
||||
bresp = axi4_resp_slverr;
|
||||
end
|
||||
|
||||
else
|
||||
bresp = axi4_resp_slverr;
|
||||
|
||||
if (bresp != axi4_resp_okay) begin
|
||||
$display ("%0d: ERROR: PLIC.rl_process_wr_req: unrecognized addr", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
end
|
||||
|
||||
// Send write-response to bus
|
||||
let wrr = AXI4_Wr_Resp {bid: wra.awid,
|
||||
bresp: bresp,
|
||||
buser: wra.awuser};
|
||||
slave_xactor.i_wr_resp.enq (wrr);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: PLIC.AXI4.rl_process_wr_req", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
$display (" ", fshow (wrr));
|
||||
end
|
||||
endrule: rl_process_wr_req
|
||||
|
||||
// ================================================================
|
||||
// Creator of each source interface
|
||||
|
||||
function PLIC_Source_IFC fn_mk_PLIC_Source_IFC (Integer source_id);
|
||||
return interface PLIC_Source_IFC;
|
||||
method Action m_interrupt_req (Bool set_not_clear);
|
||||
action
|
||||
if (! vrg_source_busy [source_id]) begin
|
||||
vrg_source_ip [source_id] <= set_not_clear;
|
||||
|
||||
if ((cfg_verbosity > 0) && (vrg_source_ip [source_id] != set_not_clear))
|
||||
$display ("%0d: Changing vrg_source_ip [%0d] to %0d",
|
||||
cur_cycle, source_id, pack (set_not_clear));
|
||||
end
|
||||
endaction
|
||||
endmethod
|
||||
endinterface;
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// Creator of each target interface
|
||||
|
||||
function PLIC_Target_IFC fn_mk_PLIC_Target_IFC (Integer target_id);
|
||||
return interface PLIC_Target_IFC;
|
||||
method Bool m_eip; // external interrupt pending
|
||||
match { .max_prio, .max_id } = fn_target_max_prio_and_max_id (fromInteger (target_id));
|
||||
Bool eip = (max_prio > vrg_target_threshold [target_id]);
|
||||
return eip;
|
||||
endmethod
|
||||
endinterface;
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
// Debugging
|
||||
method Action set_verbosity (Bit #(4) verbosity);
|
||||
cfg_verbosity <= verbosity;
|
||||
endmethod
|
||||
|
||||
method Action show_PLIC_state;
|
||||
fa_show_PLIC_state;
|
||||
endmethod
|
||||
|
||||
// Reset
|
||||
interface server_reset = toGPServer (f_reset_reqs, f_reset_rsps);
|
||||
|
||||
// set_addr_map should be called after this module's reset
|
||||
method Action set_addr_map (Bit #(64) addr_base, Bit #(64) addr_lim);
|
||||
if (addr_base [1:0] != 0)
|
||||
$display ("%0d: WARNING: PLIC.set_addr_map: addr_base 0x%0h is not 4-Byte-aligned",
|
||||
cur_cycle, addr_base);
|
||||
|
||||
if (addr_lim [1:0] != 0)
|
||||
$display ("%0d: WARNING: PLIC.set_addr_map: addr_lim 0x%0h is not 4-Byte-aligned",
|
||||
cur_cycle, addr_lim);
|
||||
|
||||
rg_addr_base <= addr_base;
|
||||
rg_addr_lim <= addr_lim;
|
||||
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.set_addr_map: base 0x%0h limit 0x%0h", cur_cycle, addr_base, addr_lim);
|
||||
endmethod
|
||||
|
||||
// Memory-mapped access
|
||||
interface axi4_slave = slave_xactor.axi_side;
|
||||
|
||||
// sources
|
||||
interface v_sources = genWith (fn_mk_PLIC_Source_IFC);
|
||||
|
||||
// targets
|
||||
interface v_targets = genWith (fn_mk_PLIC_Target_IFC);
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage
|
||||
42
src_Core/PLIC/PLIC_16_2_7.bsv
Normal file
42
src_Core/PLIC/PLIC_16_2_7.bsv
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package PLIC_16_2_7;
|
||||
|
||||
// ================================================================
|
||||
// Instantiation of parameterized PLIC to specific parameter values.
|
||||
//
|
||||
// ================================================================
|
||||
// Bluespec lib imports
|
||||
|
||||
// None
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
|
||||
// None
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import SoC_Map :: *; // For N_External_Interrupt_Sources
|
||||
import PLIC :: *; // For PLIC_IFC, mkPLIC
|
||||
|
||||
// ================================================================
|
||||
// PLIC for this core
|
||||
|
||||
typedef 2 PLIC_N_Targets;
|
||||
typedef 7 PLIC_Max_Priority;
|
||||
|
||||
typedef PLIC_IFC #(N_External_Interrupt_Sources,
|
||||
PLIC_N_Targets,
|
||||
PLIC_Max_Priority) PLIC_IFC_16_2_7;
|
||||
|
||||
(* synthesize *)
|
||||
module mkPLIC_16_2_7 (PLIC_IFC_16_2_7);
|
||||
let m <- mkPLIC;
|
||||
return m;
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage
|
||||
134
src_Core/PLIC/README_PLIC.txt
Normal file
134
src_Core/PLIC/README_PLIC.txt
Normal file
@@ -0,0 +1,134 @@
|
||||
The (relative) Memory map for this PLIC follows the one given in:
|
||||
|
||||
SiFive U54-MC Core Complex Manual, v1p0, Oct 4 2017
|
||||
Chapter 8 Platform Level Interrupt Controller, pp.32-38.
|
||||
|
||||
>----------------
|
||||
Priority registers
|
||||
|
||||
0x0000 Reserved
|
||||
0x0004 Source 1 priority
|
||||
0x0008 Source 2 priority
|
||||
...
|
||||
0x0800 Source 511 priority
|
||||
|
||||
>----------------
|
||||
Reserved
|
||||
|
||||
0x0804 ... 0x0FFF
|
||||
|
||||
>----------------
|
||||
IP (Interrupt Pending) array: 32 sources per 32b word
|
||||
|
||||
0x1000
|
||||
...
|
||||
0x103C
|
||||
|
||||
>----------------
|
||||
Reserved
|
||||
|
||||
0x1018 ... 0x1FFF
|
||||
|
||||
>----------------
|
||||
IE (interrupt enables) array for Hart0 M mode (1 bit per source)
|
||||
|
||||
0x2000
|
||||
...
|
||||
0x2014
|
||||
|
||||
>----------------
|
||||
Reserved
|
||||
|
||||
0x2018 ... 0x207F
|
||||
|
||||
>----------------
|
||||
IE (interrupt enables) array for Hart1 M mode (1 bit per source)
|
||||
|
||||
0x2080
|
||||
...
|
||||
0x2094
|
||||
|
||||
>----------------
|
||||
IE (interrupt enables) array for Hart1 S mode (1 bit per source)
|
||||
|
||||
0x2100
|
||||
...
|
||||
0x2114
|
||||
|
||||
>----------------
|
||||
IE (interrupt enables) array for Hart2 M mode (1 bit per source)
|
||||
|
||||
0x2180
|
||||
...
|
||||
0x2194
|
||||
|
||||
>----------------
|
||||
IE (interrupt enables) array for Hart2 S mode (1 bit per source)
|
||||
|
||||
0x2200
|
||||
...
|
||||
0x2214
|
||||
|
||||
>----------------
|
||||
IE (interrupt enables) array for Hart3 M mode (1 bit per source)
|
||||
|
||||
0x2280
|
||||
...
|
||||
0x2294
|
||||
|
||||
>----------------
|
||||
IE (interrupt enables) array for Hart3 S mode (1 bit per source)
|
||||
|
||||
0x2300
|
||||
...
|
||||
0x2314
|
||||
|
||||
>----------------
|
||||
IE (interrupt enables) array for Hart4 M mode (1 bit per source)
|
||||
|
||||
0x2380
|
||||
...
|
||||
0x2394
|
||||
|
||||
>----------------
|
||||
IE (interrupt enables) array for Hart4 S mode (1 bit per source)
|
||||
|
||||
0x2400
|
||||
...
|
||||
0x2414
|
||||
|
||||
>----------------
|
||||
Reserved
|
||||
|
||||
0x0C00 2480 ... 0x0C1F FFFF
|
||||
|
||||
>----------------
|
||||
Threshold (of priority) and Claim/Complete registers
|
||||
|
||||
0x0C20 0000 Hart 0 M-mode
|
||||
0x0C20 0004 Hart 0 M-mode claim/complete
|
||||
>----------------
|
||||
0x0C20 1000 Hart 1 M-mode
|
||||
0x0C20 1004 Hart 1 M-mode claim/complete
|
||||
>----------------
|
||||
0x0C20 2000 Hart 1 S-mode
|
||||
0x0C20 2004 Hart 1 S-mode claim/complete
|
||||
>----------------
|
||||
0x0C20 3000 Hart 2 M-mode
|
||||
0x0C20 3004 Hart 2 M-mode claim/complete
|
||||
>----------------
|
||||
0x0C20 4000 Hart 2 S-mode
|
||||
0x0C20 4004 Hart 2 S-mode claim/complete
|
||||
>----------------
|
||||
0x0C20 5000 Hart 3 M-mode
|
||||
0x0C20 5004 Hart 3 M-mode claim/complete
|
||||
>----------------
|
||||
0x0C20 6000 Hart 3 S-mode
|
||||
0x0C20 6004 Hart 3 S-mode claim/complete
|
||||
>----------------
|
||||
0x0C20 7000 Hart 4 M-mode
|
||||
0x0C20 7004 Hart 4 M-mode claim/complete
|
||||
>----------------
|
||||
0x0C20 8000 Hart 4 S-mode
|
||||
0x0C20 8004 Hart 4 S-mode claim/complete
|
||||
>----------------
|
||||
296
src_Core/PLIC/Test_PLIC.bsv
Normal file
296
src_Core/PLIC/Test_PLIC.bsv
Normal file
@@ -0,0 +1,296 @@
|
||||
// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package Test_PLIC;
|
||||
|
||||
// ================================================================
|
||||
// Standalone unit-test testbench for PLIC.
|
||||
//
|
||||
// ================================================================
|
||||
// Bluespec lib imports
|
||||
|
||||
import ConfigReg :: *;
|
||||
import Vector :: *;
|
||||
import FIFOF :: *;
|
||||
import GetPut :: *;
|
||||
import ClientServer :: *;
|
||||
import Connectable :: *;
|
||||
import Assert :: *;
|
||||
import StmtFSM :: *;
|
||||
|
||||
// ----------------
|
||||
// BSV additional libs
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
import GetPut_Aux :: *;
|
||||
import Semi_FIFOF :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports
|
||||
|
||||
import AXI4_Types :: *;
|
||||
import AXI4_Fabric :: *;
|
||||
import Fabric_Defs :: *; // for Wd_Id, Wd_Addr, Wd_Data, Wd_User
|
||||
import SoC_Map :: *;
|
||||
import PLIC :: *;
|
||||
import PLIC_16_2_7 :: *;
|
||||
|
||||
// ================================================================
|
||||
|
||||
Integer n_external_interrupt_sources = valueOf (N_External_Interrupt_Sources);
|
||||
typedef TAdd #(1, N_External_Interrupt_Sources) N_Interrupt_Sources;
|
||||
typedef Bit #(TLog #(N_Interrupt_Sources)) Source_Id;
|
||||
|
||||
Integer plic_n_targets = valueOf (PLIC_N_Targets);
|
||||
Integer target_0 = 0;
|
||||
Integer target_1 = 1;
|
||||
|
||||
Integer plic_max_priority = valueOf (PLIC_Max_Priority);
|
||||
typedef Bit #(TLog #(TAdd #(1, PLIC_Max_Priority))) Priority;
|
||||
|
||||
// ================================================================
|
||||
// The Core module
|
||||
|
||||
(* synthesize *)
|
||||
module mkTest_PLIC (Empty);
|
||||
|
||||
// System address map
|
||||
SoC_Map_IFC soc_map <- mkSoC_Map;
|
||||
|
||||
// PLIC (Platform-Level Interrupt Controller)
|
||||
PLIC_IFC_16_2_7 plic <- mkPLIC_16_2_7;
|
||||
|
||||
// Master transactor through which to read/write PLIC regs
|
||||
AXI4_Master_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) master_xactor <- mkAXI4_Master_Xactor;
|
||||
|
||||
Vector #(N_Interrupt_Sources, Reg #(Bool)) vrg_irqs <- replicateM (mkReg (False));
|
||||
|
||||
// ================================================================
|
||||
// AXI4 interactions
|
||||
|
||||
FIFOF #(Fabric_Addr) f_read_addr <- mkFIFOF;
|
||||
FIFOF #(Fabric_Data) f_read_data <- mkFIFOF;
|
||||
|
||||
function Action fa_read_req (Integer addr);
|
||||
action
|
||||
let fabric_addr = soc_map.m_plic_addr_base + fromInteger (addr);
|
||||
|
||||
let mem_req_rd_addr = AXI4_Rd_Addr {arid: fabric_default_id,
|
||||
araddr: fabric_addr,
|
||||
arlen: 0, // burst len = arlen+1
|
||||
arsize: zeroExtend (axsize_4),
|
||||
arburst: fabric_default_burst,
|
||||
arlock: fabric_default_lock,
|
||||
arcache: fabric_default_arcache,
|
||||
arprot: fabric_default_prot,
|
||||
arqos: fabric_default_qos,
|
||||
arregion: fabric_default_region,
|
||||
aruser: fabric_default_user};
|
||||
master_xactor.i_rd_addr.enq (mem_req_rd_addr);
|
||||
f_read_addr.enq (fabric_addr);
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
function Action fa_read_rsp;
|
||||
action
|
||||
let fabric_addr <- pop (f_read_addr);
|
||||
let rd_data <- pop_o (master_xactor.o_rd_data);
|
||||
if (rd_data.rresp != axi4_resp_okay) begin
|
||||
$display ("ERROR: fa_read_rsp: fabric response error");
|
||||
$display (" ", fshow (rd_data));
|
||||
end
|
||||
let x = (((valueOf (Wd_Data) == 64) && ((fabric_addr & 'h7) == 'h4))
|
||||
? (rd_data.rdata >> 32)
|
||||
: rd_data.rdata);
|
||||
f_read_data.enq (x);
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
function Action fa_write_req (Integer addr, Fabric_Data data);
|
||||
action
|
||||
let fabric_addr = soc_map.m_plic_addr_base + fromInteger (addr);
|
||||
|
||||
let mem_req_wr_addr = AXI4_Wr_Addr {awid: fabric_default_id,
|
||||
awaddr: fabric_addr,
|
||||
awlen: 0, // burst len = awlen+1
|
||||
awsize: zeroExtend (axsize_4),
|
||||
awburst: fabric_default_burst,
|
||||
awlock: fabric_default_lock,
|
||||
awcache: fabric_default_awcache,
|
||||
awprot: fabric_default_prot,
|
||||
awqos: fabric_default_qos,
|
||||
awregion: fabric_default_region,
|
||||
awuser: fabric_default_user};
|
||||
|
||||
let x = (((valueOf (Wd_Data) == 64) && ((fabric_addr & 'h7) == 'h4))
|
||||
? (data << 32)
|
||||
: data);
|
||||
let mem_req_wr_data = AXI4_Wr_Data {wid: fabric_default_id,
|
||||
wdata: x,
|
||||
wstrb: '1,
|
||||
wlast: True,
|
||||
wuser: fabric_default_user};
|
||||
master_xactor.i_wr_addr.enq (mem_req_wr_addr);
|
||||
master_xactor.i_wr_data.enq (mem_req_wr_data);
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
function Action fa_write_rsp;
|
||||
action
|
||||
let wr_resp <- pop_o (master_xactor.o_wr_resp);
|
||||
|
||||
if (wr_resp.bresp != axi4_resp_okay) begin
|
||||
$display ("ERROR: rl_discard_write_rsp: fabric response error");
|
||||
$display (" ", fshow (wr_resp));
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// Help functions to interact with PLIC at an "API" level
|
||||
|
||||
function Action fa_print_plic_eips ();
|
||||
action
|
||||
$write ("PLIC.v_target eip =");
|
||||
$write (" ", fshow (plic.v_targets [0].m_eip));
|
||||
$write (" ", fshow (plic.v_targets [1].m_eip));
|
||||
$display ("");
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
function Stmt fstmt_set_source_priority (Integer src, Priority prio);
|
||||
return seq
|
||||
fa_write_req (src * 4, zeroExtend (prio));
|
||||
fa_write_rsp;
|
||||
endseq;
|
||||
endfunction
|
||||
|
||||
function Stmt fstmt_set_target_ies (Integer target, Bit #(32) ies);
|
||||
return seq
|
||||
fa_write_req ('h2000 + (target * 'h80), zeroExtend (ies));
|
||||
fa_write_rsp;
|
||||
endseq;
|
||||
endfunction
|
||||
|
||||
function Stmt fstmt_set_target_threshold (Integer target, Priority threshold);
|
||||
return seq
|
||||
fa_write_req ('h20_0000 + (target * 'h1000), zeroExtend (threshold));
|
||||
fa_write_rsp;
|
||||
endseq;
|
||||
endfunction
|
||||
|
||||
function Stmt fstmt_claim (Integer target);
|
||||
return seq
|
||||
fa_read_req ('h20_0004 + (target * 'h1000));
|
||||
fa_read_rsp;
|
||||
action
|
||||
let x <- pop (f_read_data);
|
||||
$display ("fstmt_claim: PLIC returned %0d", x);
|
||||
endaction
|
||||
endseq;
|
||||
endfunction
|
||||
|
||||
function Stmt fstmt_complete (Integer target, Source_Id source_id);
|
||||
return seq
|
||||
fa_write_req ('h20_0004 + (target * 'h1000), zeroExtend (source_id));
|
||||
fa_write_rsp;
|
||||
endseq;
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// BEHAVIOR
|
||||
|
||||
mkConnection (master_xactor.axi_side, plic.axi4_slave);
|
||||
|
||||
// Drive all interrupt requests from local regs
|
||||
for (Integer j = 0; j < n_external_interrupt_sources; j = j + 1)
|
||||
rule rl_drive_irq;
|
||||
plic.v_sources [j].m_interrupt_req (vrg_irqs [j]);
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
|
||||
Stmt init = seq
|
||||
action
|
||||
$display ("Initializing PLIC");
|
||||
plic.server_reset.request.put (?);
|
||||
endaction
|
||||
action
|
||||
let rsp <- plic.server_reset.response.get;
|
||||
plic.set_addr_map (zeroExtend (soc_map.m_plic_addr_base),
|
||||
zeroExtend (soc_map.m_plic_addr_lim));
|
||||
endaction
|
||||
fstmt_set_source_priority (1, 0);
|
||||
fstmt_set_source_priority (2, 0);
|
||||
fstmt_set_source_priority (3, 0);
|
||||
fstmt_set_source_priority (4, 0);
|
||||
|
||||
fstmt_set_source_priority (5, 0);
|
||||
fstmt_set_source_priority (6, 0);
|
||||
fstmt_set_source_priority (7, 0);
|
||||
fstmt_set_source_priority (8, 0);
|
||||
|
||||
fstmt_set_source_priority (9, 0);
|
||||
fstmt_set_source_priority (10, 0);
|
||||
fstmt_set_source_priority (11, 0);
|
||||
fstmt_set_source_priority (12, 0);
|
||||
|
||||
fstmt_set_source_priority (13, 0);
|
||||
fstmt_set_source_priority (14, 0);
|
||||
fstmt_set_source_priority (15, 0);
|
||||
fstmt_set_source_priority (16, 0);
|
||||
|
||||
fstmt_set_target_ies (target_0, 0);
|
||||
fstmt_set_target_ies (target_1, 0);
|
||||
|
||||
fstmt_set_target_threshold (target_0, 7);
|
||||
fstmt_set_target_threshold (target_1, 7);
|
||||
delay (5);
|
||||
$display ("Finished Initializing PLIC");
|
||||
endseq;
|
||||
|
||||
Stmt test1 = seq
|
||||
$display (">---------------- TEST 1");
|
||||
plic.set_verbosity (1);
|
||||
fstmt_set_source_priority (5, 4);
|
||||
|
||||
fstmt_set_target_ies (target_0, 'b10_0000); // bit 5
|
||||
fstmt_set_target_threshold (target_0, 4);
|
||||
|
||||
fstmt_set_target_ies (target_1, 'b10_0000); // bit 5
|
||||
fstmt_set_target_threshold (target_1, 2);
|
||||
|
||||
plic.show_PLIC_state;
|
||||
fa_print_plic_eips;
|
||||
|
||||
vrg_irqs [5] <= True;
|
||||
delay (2);
|
||||
plic.show_PLIC_state;
|
||||
fa_print_plic_eips;
|
||||
|
||||
fstmt_set_target_threshold (target_0, 3);
|
||||
plic.show_PLIC_state;
|
||||
fa_print_plic_eips;
|
||||
|
||||
fstmt_claim (target_1);
|
||||
plic.show_PLIC_state;
|
||||
fa_print_plic_eips;
|
||||
|
||||
fstmt_complete (target_1, 5);
|
||||
plic.show_PLIC_state;
|
||||
fa_print_plic_eips;
|
||||
endseq;
|
||||
|
||||
// ================================================================
|
||||
|
||||
mkAutoFSM (seq
|
||||
init;
|
||||
test1;
|
||||
$finish (0);
|
||||
endseq);
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
endpackage
|
||||
Reference in New Issue
Block a user