Merge branch 'CHERI' into ifetch-cleanup
This commit is contained in:
@@ -93,10 +93,10 @@ library RTL can be found in the directory `src_bsc_lib_RTL`.
|
||||
|
||||
- `src_Core/`, for the CPU core, with sub-directories:
|
||||
- `Core/`: the top-level of the CPU Core (specifically, the files CoreW_IFC.bsv and CoreW.bsv)
|
||||
- 'CPU/': more CPU core sources
|
||||
- 'RISCY_OOO': the bulk of the code, taken from MIT's riscy-ooo design, with local modifications.
|
||||
- `CPU/`: more CPU core sources
|
||||
- `RISCY_OOO/`: the bulk of the code, taken from MIT's riscy-ooo design, with local modifications.
|
||||
- `ISA/`: generic types/constants/functions for the RISC-V ISA (not CPU-implementation-specific)
|
||||
- 'PLIC/': Platform-Level Interrupt Controller (standard RISC-V spec)
|
||||
- `PLIC/`: Platform-Level Interrupt Controller (standard RISC-V spec)
|
||||
- `BSV_Additional_Libs/`: generic utilities (not CPU-specific)
|
||||
- `Debug_Module/`: RISC-V Debug Module to debug the CPU from GDB or other debuggers
|
||||
|
||||
|
||||
@@ -249,9 +249,9 @@ void c_mem_load_elf (char *elf_filename,
|
||||
#define MIN_MEM_ADDR_16MB BASE_ADDR_B
|
||||
#define MAX_MEM_ADDR_16MB (BASE_ADDR_B + 0x1000000lu)
|
||||
|
||||
// For 256 MB memory at 0x_8000_0000
|
||||
#define MIN_MEM_ADDR_256MB BASE_ADDR_B
|
||||
#define MAX_MEM_ADDR_256MB (BASE_ADDR_B + 0x10000000lu)
|
||||
// For 1 GB memory at 0x_8000_0000
|
||||
#define MIN_MEM_ADDR_1GB BASE_ADDR_B
|
||||
#define MAX_MEM_ADDR_1GB (BASE_ADDR_B + 0x40000000lu)
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -282,8 +282,8 @@ void write_mem_hex_file (FILE *fp, uint64_t addr1, uint64_t addr2)
|
||||
}
|
||||
|
||||
// Write last word, if necessary, to avoid warnings about missing locations
|
||||
if (addr < (MAX_MEM_ADDR_256MB - bytes_per_raw_mem_word)) {
|
||||
addr = MAX_MEM_ADDR_256MB - bytes_per_raw_mem_word;
|
||||
if (addr < (MAX_MEM_ADDR_1GB - bytes_per_raw_mem_word)) {
|
||||
addr = MAX_MEM_ADDR_1GB - bytes_per_raw_mem_word;
|
||||
fprintf (fp, "@%07" PRIx64 " // last raw_mem addr; byte addr: %08" PRIx64 "\n",
|
||||
((addr - BASE_ADDR_B) / bytes_per_raw_mem_word),
|
||||
addr - BASE_ADDR_B);
|
||||
@@ -304,8 +304,8 @@ void print_usage (FILE *fp, int argc, char *argv [])
|
||||
fprintf (fp, " %s <ELF filename> <mem hex filename>\n", argv [0]);
|
||||
fprintf (fp, "Reads ELF file and writes a Verilog Hex Memory image file\n");
|
||||
fprintf (fp, "ELF file should have addresses within this range:\n");
|
||||
fprintf (fp, "< Max: 0x%8" PRIx64 "\n", MAX_MEM_ADDR_256MB);
|
||||
fprintf (fp, ">= Min: 0x%8" PRIx64 "\n", MIN_MEM_ADDR_256MB);
|
||||
fprintf (fp, "< Max: 0x%8" PRIx64 "\n", MAX_MEM_ADDR_1GB);
|
||||
fprintf (fp, ">= Min: 0x%8" PRIx64 "\n", MIN_MEM_ADDR_1GB);
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
@@ -327,7 +327,7 @@ int main (int argc, char *argv [])
|
||||
|
||||
c_mem_load_elf (argv [1], "_start", "exit", "tohost");
|
||||
|
||||
if ((min_addr < BASE_ADDR_B) || (MAX_MEM_ADDR_256MB <= max_addr)) {
|
||||
if ((min_addr < BASE_ADDR_B) || (MAX_MEM_ADDR_1GB <= max_addr)) {
|
||||
print_usage (stderr, argc, argv);
|
||||
exit (1);
|
||||
}
|
||||
@@ -340,7 +340,7 @@ int main (int argc, char *argv [])
|
||||
|
||||
fprintf (stdout, "Writing mem hex to file '%s'\n", argv [2]);
|
||||
write_mem_hex_file (fp_out, BASE_ADDR_B, max_addr);
|
||||
// write_mem_hex_file (fp_out, BASE_ADDR_B, MAX_MEM_ADDR_256MB);
|
||||
// write_mem_hex_file (fp_out, BASE_ADDR_B, MAX_MEM_ADDR_1GB);
|
||||
|
||||
fclose (fp_out);
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ BSC_COMPILATION_FLAGS += \
|
||||
-D CheriMasterIDWidth=1 \
|
||||
-D CheriTransactionIDWidth=5 \
|
||||
-D CAP128 -D BLUESIM \
|
||||
-D PERFORMANCE_MONITORING \
|
||||
-D MEM64 \
|
||||
-D RISCV \
|
||||
-D RVFI_DII \
|
||||
|
||||
Submodule libs/BlueStuff updated: baf31fb288...c483104aa7
Submodule libs/TagController updated: aaa23bc246...f4c5348188
@@ -59,6 +59,10 @@ import TlbTypes::*;
|
||||
import SynthParam::*;
|
||||
import VerificationPacket::*;
|
||||
import Performance::*;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor::*;
|
||||
import BlueUtils::*;
|
||||
`endif
|
||||
import HasSpecBits::*;
|
||||
import Exec::*;
|
||||
import FetchStage::*;
|
||||
@@ -212,6 +216,10 @@ interface Core;
|
||||
method Bit#(32) debugRename;
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method Action events_llc(EventsCache events);
|
||||
method Action events_tgc(EventsCache events);
|
||||
`endif
|
||||
endinterface
|
||||
|
||||
// fixpoint to instantiate modules
|
||||
@@ -232,6 +240,21 @@ typedef enum {
|
||||
} Core_Run_State
|
||||
deriving (Bits, Eq, FShow);
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
instance BitVectorable #(EventsCore, SizeOf#(SupCnt), EventsCoreElements) provisos (Bits #(EventsCore, m));
|
||||
function Vector#(EventsCoreElements, SupCnt) to_vector(EventsCore e) =
|
||||
reverse(unpack(pack(e)));
|
||||
endinstance
|
||||
instance BitVectorable #(EventsCoreMem, SizeOf#(HpmRpt), EventsCoreMemElements) provisos (Bits #(EventsCoreMem, m));
|
||||
function Vector#(EventsCoreMemElements, HpmRpt) to_vector(EventsCoreMem e) =
|
||||
reverse(unpack(pack(e)));
|
||||
endinstance
|
||||
instance BitVectorable #(EventsCache, SizeOf#(HpmRpt), EventsCacheElements) provisos (Bits #(EventsCache, m));
|
||||
function Vector#(EventsCacheElements, HpmRpt) to_vector(EventsCache e) =
|
||||
reverse(unpack(pack(e)));
|
||||
endinstance
|
||||
`endif
|
||||
|
||||
(* synthesize *)
|
||||
module mkCore#(CoreId coreId)(Core);
|
||||
let verbose = False;
|
||||
@@ -258,6 +281,10 @@ module mkCore#(CoreId coreId)(Core);
|
||||
Vector #(SupSize, FIFOF #(Trace_Data2)) v_f_to_TV <- replicateM (mkFIFOF);
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
Array #(Reg #(EventsCore)) hpm_core_events <- mkDRegOR (5, unpack (0));
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
|
||||
// front end
|
||||
@@ -400,6 +427,11 @@ module mkCore#(CoreId coreId)(Core);
|
||||
`endif
|
||||
);
|
||||
globalSpecUpdate.incorrectSpec(False, spec_tag, inst_tag);
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCore events = unpack (0);
|
||||
events.evt_REDIRECT = 1;
|
||||
hpm_core_events[1] <= events;
|
||||
`endif
|
||||
endmethod
|
||||
method correctSpec = globalSpecUpdate.correctSpec[finishAluCorrectSpecPort(i)].put;
|
||||
method doStats = doStatsReg._read;
|
||||
@@ -1075,6 +1107,41 @@ module mkCore#(CoreId coreId)(Core);
|
||||
endrule
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
// ================================================================
|
||||
// Performance counters
|
||||
|
||||
Reg#(EventsCache) events_llc_reg <- mkRegU;
|
||||
Reg#(EventsCache) events_tgc_reg <- mkRegU;
|
||||
rule report_events;
|
||||
hpm_core_events[2] <= unpack(pack(commitStage.events));
|
||||
endrule
|
||||
|
||||
Vector #(1, Bit #(Report_Width)) null_evt = replicate (0);
|
||||
Vector #(31, Bit #(Report_Width)) mem_core_evts_vec = to_large_vector (coreFix.memExeIfc.events);
|
||||
Vector #(31, Bit #(Report_Width)) other_core_evts_vec = to_large_vector (hpm_core_events[0]);
|
||||
Vector #(31, Bit #(Report_Width)) core_evts_vec = unpack(pack(mem_core_evts_vec) | pack(other_core_evts_vec));
|
||||
EventsCache instMem = unpack(pack(iMem.events) | pack(iTlb.events));
|
||||
Vector #(16, Bit #(Report_Width)) imem_evts_vec = to_large_vector (instMem);
|
||||
EventsCache dataMem = unpack(pack(dMem.events) | pack(dTlb.events));
|
||||
Vector #(16, Bit #(Report_Width)) dmem_evts_vec = to_large_vector (dataMem);
|
||||
Vector #(32, Bit #(Report_Width)) external_evts_vec = replicate (0);//to_large_vector (w_external_evts);
|
||||
Vector #(16, Bit #(Report_Width)) llc_evts_vec = to_large_vector (events_llc_reg);
|
||||
Vector #(16, Bit #(Report_Width)) tgc_evts_vec = to_large_vector (events_tgc_reg);
|
||||
|
||||
let events = append (null_evt, core_evts_vec);
|
||||
events = append (events, imem_evts_vec);
|
||||
events = append (events, dmem_evts_vec);
|
||||
events = append (events, external_evts_vec);
|
||||
events = append (events, llc_evts_vec);
|
||||
events = append (events, tgc_evts_vec);
|
||||
|
||||
(* fire_when_enabled, no_implicit_conditions *)
|
||||
rule rl_send_perf_evts;
|
||||
csrf.send_performance_events (events);
|
||||
endrule
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ================================================================
|
||||
// DEBUG MODULE INTERFACE
|
||||
@@ -1467,4 +1534,9 @@ module mkCore#(CoreId coreId)(Core);
|
||||
endmethod
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method events_llc = events_llc_reg._write;
|
||||
method events_tgc = events_tgc_reg._write;
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -58,6 +58,10 @@ import ISA_Decls_CHERI::*;
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor :: *;
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
// Project imports from Toooba
|
||||
|
||||
@@ -179,6 +183,10 @@ interface CsrFile;
|
||||
method Action dcsr_cause_write (Bit #(3) dcsr_cause);
|
||||
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
(* always_ready, always_enabled *)
|
||||
method Action send_performance_events (Vector #(No_Of_Evts, Bit #(Report_Width)) evts);
|
||||
`endif
|
||||
endinterface
|
||||
|
||||
// Fancy Reg functions
|
||||
@@ -233,6 +241,38 @@ function Reg#(t) addWriteSideEffect(Reg#(t) r, Action a);
|
||||
endinterface);
|
||||
endfunction
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
interface PerfCountersVec;
|
||||
interface Vector#(No_Of_Ctrs, Reg#(Data)) counter_vec;
|
||||
interface Vector#(No_Of_Ctrs, Reg#(Data)) event_vec;
|
||||
interface Reg#(Data) inhibit;
|
||||
method Action send_performance_events (Vector #(No_Of_Evts, Bit#(Report_Width)) evts);
|
||||
endinterface
|
||||
(* synthesize *)
|
||||
module mkPerfCountersToooba (PerfCountersVec);
|
||||
PerfCounters_IFC #(No_Of_Ctrs, Counter_Width, Report_Width, No_Of_Evts) perf_counters <- mkPerfCounters;
|
||||
Vector#(No_Of_Ctrs, Reg#(Data)) counters = ?;
|
||||
for (Bit#(TLog#(No_Of_Ctrs)) i = 0; i < 29; i = i + 1) counters[i] =
|
||||
interface Reg;
|
||||
method Action _write(Data x) = perf_counters.write_counter(i,x);
|
||||
method Data _read = perf_counters.read_counters[i];
|
||||
endinterface;
|
||||
Vector#(No_Of_Ctrs, Reg#(Data)) events = ?;
|
||||
for (Bit#(TLog#(No_Of_Ctrs)) i = 0; i < 29; i = i + 1) events[i] =
|
||||
interface Reg;
|
||||
method Action _write(Data x) = perf_counters.write_ctr_sel(i,truncate(x));
|
||||
method Data _read = zeroExtend(perf_counters.read_ctr_sels[i]);
|
||||
endinterface;
|
||||
interface counter_vec = counters;
|
||||
interface event_vec = events;
|
||||
interface inhibit = interface Reg;
|
||||
method Action _write(Data x) = perf_counters.write_ctr_inhibit(truncate(x));
|
||||
method Data _read = zeroExtend(perf_counters.read_ctr_inhibit);
|
||||
endinterface;
|
||||
method send_performance_events = perf_counters.send_performance_events;
|
||||
endmodule
|
||||
`endif
|
||||
|
||||
function Bool has_csr_permission(CSR csr, Bit#(2) prv, Bool write);
|
||||
Bit#(12) csr_index = pack(csr);
|
||||
return ((prv >= csr_index[9:8]) && (!write || (csr_index[11:10] != 2'b11)));
|
||||
@@ -682,6 +722,16 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
Reg #(Data) rg_dscratch1 <- mkConfigRegU;
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
PerfCountersVec perf_counters <- mkPerfCountersToooba;
|
||||
|
||||
//Reg #(Bit #(2)) rg_ctr_inhib_lsb <- mkReg (0);
|
||||
//Wire #(Bit #(2)) w_ctr_inhib_lsb <- mkWire;
|
||||
//Bit #(3) ctr_inhibit_lsb = { rg_ctr_inhib_lsb [1], 0, rg_ctr_inhib_lsb [0] };
|
||||
//Word ctr_inhibit = zeroExtend ({ perf_counters.read_ctr_inhibit, ctr_inhibit_lsb });
|
||||
//CSR_Addr no_of_ctrs = fromInteger (valueOf (No_Of_Ctrs));
|
||||
`endif
|
||||
|
||||
`ifdef SECURITY
|
||||
// sanctum machine CSRs
|
||||
|
||||
@@ -756,6 +806,14 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
|
||||
// Function for getting a csr given an index
|
||||
function Reg#(Data) get_csr(CSR csr);
|
||||
Reg#(Data) ret = readOnlyReg(64'b0);
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
let c = csr.addr;
|
||||
if ((csrAddrMHPMCOUNTER3.addr <= c) && (c <= csrAddrMHPMCOUNTER31.addr))
|
||||
ret = perf_counters.counter_vec[c-csrAddrMHPMCOUNTER3.addr];
|
||||
if ((csrAddrMHPMEVENT3.addr <= c) && (c <= csrAddrMHPMEVENT31.addr))
|
||||
ret = perf_counters.event_vec[c - csrAddrMHPMEVENT3.addr];
|
||||
`endif
|
||||
return (case (csr)
|
||||
// User CSRs
|
||||
csrAddrFFLAGS: fflags_csr;
|
||||
@@ -797,6 +855,9 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
csrAddrMIMPID: mimpid_csr;
|
||||
csrAddrMHARTID: mhartid_csr;
|
||||
csrAddrMCCSR: csr_capcause(mccsr_reg);
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
csrAddrMCOUNTERINHIBIT: perf_counters.inhibit;
|
||||
`endif
|
||||
`ifdef SECURITY
|
||||
csrAddrMEVBASE: mevbase_csr;
|
||||
csrAddrMEVMASK: mevmask_csr;
|
||||
@@ -810,20 +871,19 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
csrAddrMSPEC: mspec_csr;
|
||||
csrAddrTRNG: trng_csr;
|
||||
`endif
|
||||
|
||||
csrAddrTSELECT: rg_tselect;
|
||||
csrAddrTDATA1: rg_tdata1;
|
||||
csrAddrTDATA2: rg_tdata2;
|
||||
csrAddrTDATA3: rg_tdata3;
|
||||
csrAddrTSELECT: rg_tselect;
|
||||
csrAddrTDATA1: rg_tdata1;
|
||||
csrAddrTDATA2: rg_tdata2;
|
||||
csrAddrTDATA3: rg_tdata3;
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
csrAddrDCSR: rg_dcsr; // TODO: take NMI into account (cf. Piccolo/Flute)
|
||||
csrAddrDPC: scrToCsr(rg_dpc);
|
||||
csrAddrDSCRATCH0: rg_dscratch0;
|
||||
csrAddrDSCRATCH1: rg_dscratch1;
|
||||
csrAddrDCSR: rg_dcsr; // TODO: take NMI into account (cf. Piccolo/Flute)
|
||||
csrAddrDPC: scrToCsr(rg_dpc);
|
||||
csrAddrDSCRATCH0: rg_dscratch0;
|
||||
csrAddrDSCRATCH1: rg_dscratch1;
|
||||
`endif
|
||||
|
||||
default: readOnlyReg(64'b0);
|
||||
default: ret;
|
||||
endcase);
|
||||
endfunction
|
||||
|
||||
@@ -1341,4 +1401,7 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method send_performance_events = perf_counters.send_performance_events;
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -54,9 +54,9 @@ interface LLC_AXI4_Adapter_IFC;
|
||||
method Action reset;
|
||||
|
||||
// Fabric master interface for memory
|
||||
interface AXI4_Master_Synth #(Wd_MId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) mem_master;
|
||||
interface AXI4_Master #(Wd_MId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) mem_master;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
@@ -76,7 +76,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
// ================================================================
|
||||
// Fabric request/response
|
||||
|
||||
let master_xactor <- mkAXI4_Master_Xactor;
|
||||
let masterPortShim <- mkAXI4ShimFF;
|
||||
|
||||
// For discarding write-responses
|
||||
CreditCounter_IFC #(4) ctr_wr_rsps_pending <- mkCreditCounter; // Max 15 writes outstanding
|
||||
@@ -100,7 +100,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
arregion: fabric_default_region,
|
||||
aruser: fabric_default_aruser};
|
||||
|
||||
master_xactor.slave.ar.put(mem_req_rd_addr);
|
||||
masterPortShim.slave.ar.put(mem_req_rd_addr);
|
||||
|
||||
// Debugging
|
||||
if (cfg_verbosity > 1) begin
|
||||
@@ -134,7 +134,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
endrule
|
||||
|
||||
rule rl_handle_read_rsps;
|
||||
let mem_rsp <- get(master_xactor.slave.r);
|
||||
let mem_rsp <- get(masterPortShim.slave.r);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: LLC_AXI4_Adapter.rl_handle_read_rsps: beat %0d ", cur_cycle, rg_rd_rsp_beat);
|
||||
@@ -189,7 +189,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
// ================
|
||||
if (rg_wr_req_beat == 0) begin
|
||||
// send AXI4 AW flit
|
||||
master_xactor.slave.aw.put (AXI4_AWFlit {
|
||||
masterPortShim.slave.aw.put (AXI4_AWFlit {
|
||||
awid: fabric_default_mid,
|
||||
awaddr: { wb.addr [63:6], 6'h0 },
|
||||
awlen: 7, // burst len = awlen+1
|
||||
@@ -218,7 +218,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
Vector #(8, Bit #(8)) line_strb = unpack(pack(wb.byteEn));
|
||||
Vector #(4, MemTaggedData) line_data = clineToMemTaggedDataVector(wb.data);
|
||||
// send AXI4 W flit
|
||||
master_xactor.slave.w.put(AXI4_WFlit {
|
||||
masterPortShim.slave.w.put(AXI4_WFlit {
|
||||
wdata: line_data[rg_wr_req_beat[2:1]].data[rg_wr_req_beat[0]],
|
||||
wstrb: line_strb[rg_wr_req_beat],
|
||||
wlast: rg_wr_req_beat == 7,
|
||||
@@ -229,7 +229,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
// Discard write-responses from the fabric
|
||||
|
||||
rule rl_discard_write_rsp;
|
||||
let wr_resp <- get(master_xactor.slave.b);
|
||||
let wr_resp <- get(masterPortShim.slave.b);
|
||||
|
||||
if (ctr_wr_rsps_pending.value == 0) begin
|
||||
$display ("%0d: ERROR: LLC_AXI4_Adapter.rl_discard_write_rsp: unexpected Wr response (ctr_wr_rsps_pending.value == 0)",
|
||||
@@ -256,7 +256,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
endmethod
|
||||
|
||||
// Fabric interface for memory
|
||||
interface mem_master = master_xactor.masterSynth;
|
||||
interface mem_master = masterPortShim.master;
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -50,6 +50,7 @@ import GetPut :: *;
|
||||
import ClientServer :: *;
|
||||
import Connectable :: *;
|
||||
import FIFOF :: *;
|
||||
import FIFO :: *;
|
||||
import ConfigReg :: *;
|
||||
|
||||
// ----------------
|
||||
@@ -170,16 +171,33 @@ module mkProc (Proc_IFC);
|
||||
// ================================================================
|
||||
// Connect stats
|
||||
|
||||
FIFO#(Bool) statReqs <- mkFIFO;
|
||||
|
||||
for(Integer i = 0; i < valueof(CoreNum); i = i+1) begin
|
||||
rule broadcastStats;
|
||||
Bool doStats <- core[i].sendDoStats;
|
||||
for(Integer j = 0; j < valueof(CoreNum); j = j+1) begin
|
||||
core[j].recvDoStats(doStats);
|
||||
end
|
||||
llc.perf.setStatus(doStats);
|
||||
endrule
|
||||
rule recvStatReq;
|
||||
Bool doStats <- core[i].sendDoStats;
|
||||
statReqs.enq(doStats);
|
||||
endrule
|
||||
end
|
||||
|
||||
rule broadcastStats;
|
||||
for(Integer j = 0; j < valueof(CoreNum); j = j+1) begin
|
||||
core[j].recvDoStats(statReqs.first);
|
||||
end
|
||||
llc.perf.setStatus(statReqs.first);
|
||||
statReqs.deq;
|
||||
endrule
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
Reg#(EventsCache) events_tgc_reg <- mkRegU;
|
||||
rule broadcastPerfEvents;
|
||||
for(Integer j = 0; j < valueof(CoreNum); j = j+1) begin
|
||||
core[j].events_llc(llc.events);
|
||||
core[j].events_tgc(events_tgc_reg);
|
||||
end
|
||||
endrule
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
// Stub out deadlock and renameDebug interfaces
|
||||
|
||||
@@ -340,6 +358,10 @@ module mkProc (Proc_IFC);
|
||||
method Bit #(32) hart0_debug_rename = core [0].debugRename;
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method events_tgc = events_tgc_reg._write;
|
||||
`endif
|
||||
|
||||
endmodule: mkProc
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -32,6 +32,7 @@ import ISA_Decls :: *;
|
||||
import AXI4 :: *;
|
||||
import Fabric_Defs :: *;
|
||||
import SoC_Map :: *;
|
||||
import CCTypes :: *;
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
import DM_CPU_Req_Rsp :: *;
|
||||
@@ -69,9 +70,9 @@ interface Proc_IFC;
|
||||
// SoC fabric connections
|
||||
|
||||
// Fabric master interface for memory (from LLC)
|
||||
interface AXI4_Master_Synth #(Wd_MId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) master0;
|
||||
interface AXI4_Master #(Wd_MId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) master0;
|
||||
|
||||
// Fabric master interface for IO (from MMIOPlatform)
|
||||
interface AXI4_Master #(Wd_MId_2x3, Wd_Addr, Wd_Data,
|
||||
@@ -101,9 +102,9 @@ interface Proc_IFC;
|
||||
// ----------------
|
||||
// Coherent port into LLC (used by Debug Module, DMA engines, ... to read/write memory)
|
||||
|
||||
interface AXI4_Slave_Synth #(Wd_SId_2x3, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) debug_module_mem_server;
|
||||
interface AXI4_Slave #(Wd_SId_2x3, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) debug_module_mem_server;
|
||||
|
||||
`ifdef RVFI_DII
|
||||
interface Toooba_RVFI_DII_Server rvfi_dii_server;
|
||||
@@ -144,6 +145,10 @@ interface Proc_IFC;
|
||||
method Bit #(32) hart0_debug_rename;
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method Action events_tgc(EventsCache events);
|
||||
`endif
|
||||
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -74,6 +74,7 @@ import ProcTypes :: *;
|
||||
// Main fabric
|
||||
import Fabric_Defs :: *; // for Wd_Id, Wd_Addr, Wd_Data...
|
||||
import SoC_Map :: *;
|
||||
import CCTypes :: *; // for EventsCache.
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
import Debug_Module :: *;
|
||||
@@ -164,17 +165,27 @@ module mkCoreW #(Reset dm_power_on_reset)
|
||||
Proc_IFC proc <- mkProc (reset_by hart0_reset);
|
||||
|
||||
// handle uncached interface
|
||||
let proc_uncached <- toAXI4_Master_Synth(extendIDFields(zeroMasterUserFields(proc.master1), 0));
|
||||
let proc_uncached = extendIDFields (zeroMasterUserFields (proc.master1), 0);
|
||||
// Bridge for uncached expernal bus transactions.
|
||||
let uncached_mem_shim <- mkAXI4ShimFF(reset_by hart0_reset);
|
||||
let uncached_mem_master <- toAXI4_Master_Synth(extendIDFields(zeroMasterUserFields(uncached_mem_shim.master), 0), reset_by hart0_reset);
|
||||
|
||||
// handle cached interface
|
||||
// AXI4 tagController
|
||||
TagControllerAXI#(Wd_MId, Wd_Addr, Wd_Data) tagController <- mkTagControllerAXI(reset_by hart0_reset); // TODO double check if reseting like this is good enough
|
||||
AXI4_Master#(Wd_MId, Wd_Addr, Wd_Data, Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User)
|
||||
tmp2 <- fromAXI4_Master_Synth(proc.master0, reset_by hart0_reset);
|
||||
mkConnection(tmp2, tagController.slave, reset_by hart0_reset);
|
||||
mkConnection(proc.master0, tagController.slave, reset_by hart0_reset);
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
rule report_tagController_events;
|
||||
Vector#(7, Bit#(1)) evts = tagController.events;
|
||||
EventsCache ce = unpack(0);
|
||||
ce.evt_ST = zeroExtend(evts[0]); // Unsure of mapping from EventsCacheCore to 7-bit vector.
|
||||
ce.evt_ST_MISS = zeroExtend(evts[1]);
|
||||
ce.evt_LD = zeroExtend(evts[2]);
|
||||
ce.evt_LD_MISS = zeroExtend(evts[3]);
|
||||
ce.evt_EVICT = zeroExtend(evts[4]);
|
||||
// SET_TAG_WRITE/READ aren't used in TagCache; tag table data is not tagged.
|
||||
proc.events_tgc(ce);
|
||||
endrule
|
||||
`endif
|
||||
|
||||
// PLIC (Platform-Level Interrupt Controller)
|
||||
PLIC_IFC_16_2_7 plic <- mkPLIC_16_2_7;
|
||||
@@ -355,26 +366,24 @@ module mkCoreW #(Reset dm_power_on_reset)
|
||||
// Connect the local 2x3 fabric
|
||||
|
||||
// Masters on the local 2x3 fabric
|
||||
Vector#(Num_Masters_2x3,
|
||||
AXI4_Master_Synth #(Wd_MId_2x3, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User))
|
||||
master_vector = newVector;
|
||||
Vector#(Num_Masters_2x3, AXI4_Master #(Wd_MId_2x3, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User))
|
||||
master_vector = newVector;
|
||||
//let master_vector = newVector;
|
||||
master_vector[cpu_uncached_master_num] = proc_uncached;
|
||||
master_vector[debug_module_sba_master_num] = dm_master_local;
|
||||
|
||||
// Slaves on the local 2x3 fabric
|
||||
// default slave is forwarded out directly to the Core interface
|
||||
Vector#(Num_Slaves_2x3,
|
||||
AXI4_Slave_Synth #(Wd_SId_2x3, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User))
|
||||
slave_vector = newVector;
|
||||
Vector#(Num_Slaves_2x3, AXI4_Slave #(Wd_SId_2x3, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User))
|
||||
slave_vector = newVector;
|
||||
//let slave_vector = newVector;
|
||||
slave_vector[default_slave_num] <- toAXI4_Slave_Synth(uncached_mem_shim.slave);
|
||||
slave_vector[default_slave_num] = uncached_mem_shim.slave;
|
||||
slave_vector[llc_slave_num] = proc.debug_module_mem_server;
|
||||
slave_vector[plic_slave_num] = plic.axi4_slave;
|
||||
slave_vector[plic_slave_num] = zeroSlaveUserFields (plic.axi4_slave);
|
||||
|
||||
function Vector#(Num_Slaves_2x3, Bool) route_2x3 (Bit#(Wd_Addr) addr);
|
||||
Vector#(Num_Slaves_2x3, Bool) res = replicate(False);
|
||||
@@ -389,9 +398,7 @@ module mkCoreW #(Reset dm_power_on_reset)
|
||||
return res;
|
||||
endfunction
|
||||
|
||||
mkAXI4Bus_Synth (route_2x3, master_vector, slave_vector);
|
||||
|
||||
let cached_mem_master <- toAXI4_Master_Synth(tagController.master);
|
||||
mkAXI4Bus (route_2x3, master_vector, slave_vector);
|
||||
|
||||
// ================================================================
|
||||
// Connect external interrupt lines from PLIC to CPU
|
||||
@@ -441,10 +448,10 @@ module mkCoreW #(Reset dm_power_on_reset)
|
||||
// AXI4 Fabric interfaces
|
||||
|
||||
// Cached master to Fabric master interface
|
||||
interface cpu_imem_master = cached_mem_master;
|
||||
interface cpu_imem_master = tagController.master;
|
||||
|
||||
// Uncached master to Fabric master interface
|
||||
interface cpu_dmem_master = uncached_mem_master;
|
||||
interface cpu_dmem_master = extendIDFields(zeroMasterUserFields(uncached_mem_shim.master), 0);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// External interrupt sources
|
||||
@@ -493,6 +500,31 @@ module mkCoreW #(Reset dm_power_on_reset)
|
||||
|
||||
endmodule: mkCoreW
|
||||
|
||||
(* synthesize *)
|
||||
module mkCoreW_Synth #(Reset dm_power_on_reset)
|
||||
(CoreW_IFC_Synth #(N_External_Interrupt_Sources));
|
||||
let core <- mkCoreW (dm_power_on_reset);
|
||||
let cpu_imem_master_synth <- toAXI4_Master_Synth (core.cpu_imem_master);
|
||||
let cpu_dmem_master_synth <- toAXI4_Master_Synth (core.cpu_dmem_master);
|
||||
|
||||
method set_verbosity = core.set_verbosity;
|
||||
method start = core.start;
|
||||
interface cpu_imem_master = cpu_imem_master_synth;
|
||||
interface cpu_dmem_master = cpu_dmem_master_synth;
|
||||
interface core_external_interrupt_sources = core.core_external_interrupt_sources;
|
||||
method nmi_req = core.nmi_req;
|
||||
`ifdef RVFI_DII
|
||||
interface rvfi_dii_server = core.rvfi_dii_server;
|
||||
`endif
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
interface dmi = core.dmi;
|
||||
interface ndm_reset_client = core.ndm_reset_client;
|
||||
`endif
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
interface tv_verifier_info_get = core.tv_verifier_info_get;
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
// 2x3 Fabric for this Core
|
||||
// Masters: CPU DMem, Debug Module System Bus Access, External access
|
||||
|
||||
@@ -81,6 +81,74 @@ interface CoreW_IFC #(numeric type t_n_interrupt_sources);
|
||||
// ----------------------------------------------------------------
|
||||
// AXI4 Fabric interfaces
|
||||
|
||||
// CPU IMem to Fabric master interface
|
||||
interface AXI4_Master #(TAdd#(Wd_MId,1), Wd_Addr, Wd_Data,
|
||||
0, 0, 0, 0, 0) cpu_imem_master;
|
||||
|
||||
// CPU DMem to Fabric master interface
|
||||
interface AXI4_Master #(TAdd#(Wd_MId,1), Wd_Addr, Wd_Data,
|
||||
0, 0, 0, 0, 0) cpu_dmem_master;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// External interrupt sources
|
||||
|
||||
interface Vector #(t_n_interrupt_sources, PLIC_Source_IFC) core_external_interrupt_sources;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Non-maskable interrupt request
|
||||
|
||||
(* always_ready, always_enabled *)
|
||||
method Action nmi_req (Bool set_not_clear);
|
||||
|
||||
`ifdef RVFI_DII
|
||||
interface Toooba_RVFI_DII_Server rvfi_dii_server;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ----------------------------------------------------------------
|
||||
// Optional Debug Module interfaces
|
||||
|
||||
// ----------------
|
||||
// DMI (Debug Module Interface) facing remote debugger
|
||||
|
||||
interface DMI dmi;
|
||||
|
||||
// ----------------
|
||||
// Facing Platform
|
||||
// Non-Debug-Module Reset (reset all except DM)
|
||||
|
||||
interface Client #(Bool, Bool) ndm_reset_client;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
// ----------------------------------------------------------------
|
||||
// Optional Tandem Verifier interface output tuples (n,vb),
|
||||
// where 'vb' is a vector of bytes
|
||||
// with relevant bytes in locations [0]..[n-1]
|
||||
|
||||
interface Get #(Info_CPU_to_Verifier) tv_verifier_info_get;
|
||||
`endif
|
||||
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
// The Synthesizable CoreW interface (same with Synth AXI)
|
||||
|
||||
interface CoreW_IFC_Synth #(numeric type t_n_interrupt_sources);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Debugging: set core's verbosity
|
||||
|
||||
method Action set_verbosity (Bit #(4) verbosity, Bit #(64) logdelay);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Start
|
||||
|
||||
method Action start (Bool is_running, Bit #(64) tohost_addr, Bit #(64) fromhost_addr);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// AXI4 Fabric interfaces
|
||||
|
||||
// CPU IMem to Fabric master interface
|
||||
interface AXI4_Master_Synth #(TAdd#(Wd_MId,1), Wd_Addr, Wd_Data,
|
||||
0, 0, 0, 0, 0) cpu_imem_master;
|
||||
|
||||
@@ -54,9 +54,9 @@ interface DM_System_Bus_IFC;
|
||||
|
||||
// ----------------
|
||||
// Facing System
|
||||
interface AXI4_Master_Synth #(Wd_MId_2x3, Wd_Addr, Wd_Data_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) master;
|
||||
interface AXI4_Master #(Wd_MId_2x3, Wd_Addr, Wd_Data_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) master;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
@@ -197,10 +197,8 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// Interface to memory fabric
|
||||
AXI4_Master_Xactor#(Wd_MId_2x3, Wd_Addr, Wd_Data_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User)
|
||||
master_xactor <- mkAXI4_Master_Xactor;
|
||||
let master_xactor <- mkAXI4ShimFF;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// System Bus state
|
||||
@@ -680,7 +678,7 @@ module mkDM_System_Bus (DM_System_Bus_IFC);
|
||||
|
||||
// ----------------
|
||||
// Facing System
|
||||
interface AXI4_Master_IFC master = master_xactor.masterSynth;
|
||||
interface master = master_xactor.master;
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -155,9 +155,9 @@ interface Debug_Module_IFC;
|
||||
interface Client #(Bool, Bool) ndm_reset_client;
|
||||
|
||||
// Read/Write RISC-V memory
|
||||
interface AXI4_Master_Synth #(Wd_MId_2x3, Wd_Addr, Wd_Data_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) master;
|
||||
interface AXI4_Master #(Wd_MId_2x3, Wd_Addr, Wd_Data_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) master;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
@@ -481,7 +481,7 @@ module mkDebug_Module (Debug_Module_IFC);
|
||||
interface Client ndm_reset_client = dm_run_control.ndm_reset_client;
|
||||
|
||||
// Read/Write RISC-V memory
|
||||
interface AXI4_Master_IFC master = dm_system_bus.master;
|
||||
interface master = dm_system_bus.master;
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -85,8 +85,8 @@ endinterface
|
||||
// PLIC interface
|
||||
|
||||
interface PLIC_IFC #(numeric type t_n_external_sources,
|
||||
numeric type t_n_targets,
|
||||
numeric type t_max_priority);
|
||||
numeric type t_n_targets,
|
||||
numeric type t_max_priority);
|
||||
// Debugging
|
||||
method Action set_verbosity (Bit #(4) verbosity);
|
||||
method Action show_PLIC_state;
|
||||
@@ -98,9 +98,8 @@ interface PLIC_IFC #(numeric type t_n_external_sources,
|
||||
method Action set_addr_map (Bit #(64) addr_base, Bit #(64) addr_lim);
|
||||
|
||||
// Memory-mapped access
|
||||
interface AXI4_Slave_Synth #(Wd_SId_2x3, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) axi4_slave;
|
||||
interface AXI4_Slave #( Wd_SId_2x3, Wd_Addr, Wd_Data, 0, 0, 0, 0, 0)
|
||||
axi4_slave;
|
||||
|
||||
// sources
|
||||
interface Vector #(t_n_external_sources, PLIC_Source_IFC) v_sources;
|
||||
@@ -114,9 +113,9 @@ endinterface
|
||||
|
||||
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));
|
||||
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));
|
||||
|
||||
// 0 = quiet; 1 = show PLIC transactions; 2 = also show AXI4 transactions
|
||||
Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
|
||||
@@ -142,9 +141,7 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
Reg #(Bit #(64)) rg_addr_lim <- mkRegU;
|
||||
|
||||
// Connector to AXI4 fabric
|
||||
AXI4_Slave_Width_Xactor#(Wd_SId_2x3, Wd_Addr, Wd_Data_Periph, Wd_Data,
|
||||
Wd_AW_User_Periph, Wd_W_User_Periph, Wd_B_User_Periph, Wd_AR_User_Periph, Wd_R_User_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User) slave_xactor <- mkAXI4_Slave_Zeroing_Xactor;
|
||||
let slavePortShim <- mkAXI4ShimFF;
|
||||
|
||||
// ----------------
|
||||
// Per-interrupt source state
|
||||
@@ -161,15 +158,13 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
|
||||
// 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)));
|
||||
Vector #(t_n_sources, Reg #(Bool))) vvrg_ie <- replicateM (replicateM (mkReg (False)));
|
||||
|
||||
// ================================================================
|
||||
// Compute outputs for each target (combinational)
|
||||
@@ -182,42 +177,42 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
|
||||
// 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
|
||||
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 ("");
|
||||
$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 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 ("");
|
||||
$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
|
||||
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",
|
||||
max_prio, vrg_target_threshold [target_id], max_id);
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
@@ -226,27 +221,26 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
|
||||
rule rl_reset;
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_reset", cur_cycle);
|
||||
$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;
|
||||
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;
|
||||
// Mask all interrupts with highest threshold
|
||||
vrg_target_threshold [target_id] <= '1;
|
||||
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;
|
||||
for (Integer source_id = 0; source_id < n_sources; source_id = source_id + 1)
|
||||
vvrg_ie [target_id][source_id] <= False;
|
||||
|
||||
slave_xactor.clear;
|
||||
slavePortShim.clear;
|
||||
|
||||
f_reset_rsps.enq (?);
|
||||
endrule
|
||||
@@ -261,10 +255,10 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
|
||||
rule rl_process_rd_req (! f_reset_reqs.notEmpty);
|
||||
|
||||
let rda <- get(slave_xactor.master.ar);
|
||||
let rda <- get(slavePortShim.master.ar);
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: PLIC.rl_process_rd_req:", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
$display ("%0d: PLIC.rl_process_rd_req:", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
end
|
||||
|
||||
let addr_offset = rda.araddr - rg_addr_base;
|
||||
@@ -272,148 +266,137 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
AXI4_Resp rresp = 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 = DECERR;
|
||||
// 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 = 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]);
|
||||
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 = SLVERR;
|
||||
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 = 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 });
|
||||
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
|
||||
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 (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 = SLVERR;
|
||||
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 = 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 });
|
||||
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
|
||||
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 ( (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 = SLVERR;
|
||||
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 = 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]);
|
||||
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 = SLVERR;
|
||||
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 = 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 = 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);
|
||||
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 (max_id != 0) begin
|
||||
vrg_source_ip [max_id] <= False;
|
||||
vrg_source_busy [max_id] <= True;
|
||||
rdata = changeWidth (max_id);
|
||||
end
|
||||
|
||||
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 = SLVERR;
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_rd_req: reading Claim for target %0d = 0x%0h",
|
||||
cur_cycle, target_id, rdata);
|
||||
end
|
||||
else
|
||||
rresp = SLVERR;
|
||||
end
|
||||
|
||||
else
|
||||
rresp = SLVERR;
|
||||
rresp = SLVERR;
|
||||
|
||||
if (rresp != OKAY) begin
|
||||
$display ("%0d: ERROR: PLIC.rl_process_rd_req: unrecognized addr", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
$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 };
|
||||
rdata = { rdata [31:0], 32'h0 };
|
||||
|
||||
// Send read-response to bus
|
||||
Fabric_Data x = truncate (rdata);
|
||||
let rdr = AXI4_RFlit {rid: rda.arid,
|
||||
rdata: x,
|
||||
rresp: rresp,
|
||||
rlast: True,
|
||||
ruser: rda.aruser}; // XXX This requires that Wd_AR_User == Wd_R_User
|
||||
slave_xactor.master.r.put(rdr);
|
||||
rdata: x,
|
||||
rresp: rresp,
|
||||
rlast: True,
|
||||
ruser: rda.aruser}; // XXX This requires that Wd_AR_User == Wd_R_User
|
||||
slavePortShim.master.r.put(rdr);
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: PLIC.rl_process_rd_req", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
$display (" ", fshow (rdr));
|
||||
$display ("%0d: PLIC.rl_process_rd_req", cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
$display (" ", fshow (rdr));
|
||||
end
|
||||
endrule: rl_process_rd_req
|
||||
|
||||
@@ -424,142 +407,140 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
|
||||
rule rl_process_wr_req (! f_reset_reqs.notEmpty);
|
||||
|
||||
let wra <- get(slave_xactor.master.aw);
|
||||
let wrd <- get(slave_xactor.master.w);
|
||||
let wra <- get(slavePortShim.master.aw);
|
||||
let wrd <- get(slavePortShim.master.w);
|
||||
if (cfg_verbosity > 1) begin
|
||||
$display ("%0d: PLIC.rl_process_wr_req", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
$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]);
|
||||
? wrd.wdata [63:32]
|
||||
: wrd.wdata [31:0]);
|
||||
let bresp = 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 = DECERR;
|
||||
// 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 = 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);
|
||||
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 = SLVERR;
|
||||
end
|
||||
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 = 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 });
|
||||
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 = SLVERR;
|
||||
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 = 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 });
|
||||
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 ( (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 = SLVERR;
|
||||
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 = 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);
|
||||
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 = SLVERR;
|
||||
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 = SLVERR;
|
||||
end
|
||||
|
||||
// Interrupt service completion by target
|
||||
// Actual memory-write-data is irrelevant.
|
||||
// Write data is the source ID to complete. Disabled sources are ignored.
|
||||
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]);
|
||||
Bit #(T_wd_target_id) target_id = truncate (addr_offset [20:12]);
|
||||
Bit #(T_wd_source_id) source_id = truncate (wdata32);
|
||||
|
||||
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 = SLVERR;
|
||||
end
|
||||
end
|
||||
else
|
||||
bresp = SLVERR;
|
||||
if (target_id <= fromInteger (n_targets - 1)) begin
|
||||
if ( (source_id <= fromInteger (n_sources))
|
||||
&& vvrg_ie [target_id][source_id]) begin
|
||||
vrg_source_busy [source_id] <= False;
|
||||
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
|
||||
if (cfg_verbosity > 0)
|
||||
$display ("%0d: PLIC.rl_process_wr_req: ignoring completion for target %0d for source 0x%0h",
|
||||
cur_cycle, target_id, source_id);
|
||||
end
|
||||
end
|
||||
else
|
||||
bresp = SLVERR;
|
||||
end
|
||||
|
||||
else
|
||||
bresp = SLVERR;
|
||||
bresp = SLVERR;
|
||||
|
||||
if (bresp != OKAY) begin
|
||||
$display ("%0d: ERROR: PLIC.rl_process_wr_req: unrecognized addr", cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
$display (" ", fshow (wrd));
|
||||
$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_BFlit {bid: wra.awid,
|
||||
bresp: bresp,
|
||||
buser: wra.awuser}; // XXX This requires that Wd_AW_User == Wd_B_User
|
||||
slave_xactor.master.b.put(wrr);
|
||||
bresp: bresp,
|
||||
buser: wra.awuser}; // XXX This requires that Wd_AW_User == Wd_B_User
|
||||
slavePortShim.master.b.put(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));
|
||||
$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
|
||||
|
||||
@@ -568,18 +549,18 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
|
||||
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 + 1]) begin
|
||||
vrg_source_ip [source_id + 1] <= set_not_clear;
|
||||
method Action m_interrupt_req (Bool set_not_clear);
|
||||
action
|
||||
if (! vrg_source_busy [source_id + 1]) begin
|
||||
vrg_source_ip [source_id + 1] <= set_not_clear;
|
||||
|
||||
if ((cfg_verbosity > 0) && (vrg_source_ip [source_id + 1] != set_not_clear))
|
||||
$display ("%0d: %m.m_interrupt_req: changing vrg_source_ip [%0d] to %0d",
|
||||
cur_cycle, source_id + 1, pack (set_not_clear));
|
||||
end
|
||||
endaction
|
||||
endmethod
|
||||
endinterface;
|
||||
if ((cfg_verbosity > 0) && (vrg_source_ip [source_id + 1] != set_not_clear))
|
||||
$display ("%0d: %m.m_interrupt_req: changing vrg_source_ip [%0d] to %0d",
|
||||
cur_cycle, source_id + 1, pack (set_not_clear));
|
||||
end
|
||||
endaction
|
||||
endmethod
|
||||
endinterface;
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
@@ -587,12 +568,12 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
|
||||
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;
|
||||
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
|
||||
|
||||
// ================================================================
|
||||
@@ -613,22 +594,22 @@ module mkPLIC (PLIC_IFC #(t_n_external_sources, t_n_targets, t_max_priority))
|
||||
// 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);
|
||||
$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);
|
||||
$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);
|
||||
$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.slaveSynth;
|
||||
interface axi4_slave = slavePortShim.slave;
|
||||
|
||||
// sources
|
||||
interface v_sources = genWith (fn_mk_PLIC_Source_IFC);
|
||||
|
||||
@@ -45,6 +45,26 @@ import Connectable::*;
|
||||
import GetPut::*;
|
||||
import ClientServer::*;
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
typedef struct {
|
||||
Bit#(8) evt_LD;
|
||||
Bit#(8) evt_LD_MISS;
|
||||
Bit#(8) evt_LD_MISS_LAT;
|
||||
Bit#(8) evt_ST;
|
||||
Bit#(8) evt_ST_MISS; // Unimplemented
|
||||
Bit#(8) evt_ST_MISS_LAT; // Unimplemented
|
||||
Bit#(8) evt_AMO;
|
||||
Bit#(8) evt_AMO_MISS;
|
||||
Bit#(8) evt_AMO_MISS_LAT;
|
||||
Bit#(8) evt_TLB;
|
||||
Bit#(8) evt_TLB_MISS; // Only leaf is stored in TLB thus a full
|
||||
Bit#(8) evt_TLB_MISS_LAT; // walk must happen every miss
|
||||
Bit#(8) evt_TLB_FLUSH;
|
||||
Bit#(8) evt_EVICT;
|
||||
} EventsCache deriving (Bits, FShow);
|
||||
typedef TDiv#(SizeOf#(EventsCache),8) EventsCacheElements;
|
||||
`endif
|
||||
|
||||
typedef enum {
|
||||
I = 2'd0,
|
||||
S = 2'd1,
|
||||
|
||||
@@ -57,6 +57,10 @@ import CacheUtils::*;
|
||||
import Performance::*;
|
||||
import LatencyTimer::*;
|
||||
import RandomReplace::*;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor::*;
|
||||
import BlueUtils::*;
|
||||
`endif
|
||||
|
||||
export ICRqStuck(..);
|
||||
export IPRqStuck(..);
|
||||
@@ -97,6 +101,9 @@ interface IBank#(
|
||||
// performance
|
||||
method Action setPerfStatus(Bool stats);
|
||||
method Data getPerfData(L1IPerfType t);
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events;
|
||||
`endif
|
||||
endinterface
|
||||
|
||||
module mkIBank#(
|
||||
@@ -178,32 +185,50 @@ module mkIBank#(
|
||||
Bool flushDone = True;
|
||||
`endif
|
||||
|
||||
LatencyTimer#(cRqNum, 10) latTimer <- mkLatencyTimer;
|
||||
`ifdef PERF_COUNT
|
||||
Reg#(Bool) doStats <- mkConfigReg(False);
|
||||
Count#(Data) ldCnt <- mkCount(0);
|
||||
Count#(Data) ldMissCnt <- mkCount(0);
|
||||
Count#(Data) ldMissLat <- mkCount(0);
|
||||
|
||||
LatencyTimer#(cRqNum, 10) latTimer <- mkLatencyTimer;
|
||||
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
Array #(Reg #(EventsCache)) perf_events <- mkDRegOR (2, unpack (0));
|
||||
`endif
|
||||
function Action incrReqCnt;
|
||||
action
|
||||
`ifdef PERF_COUNT
|
||||
if(doStats) begin
|
||||
ldCnt.incr(1);
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache events = unpack (0);
|
||||
events.evt_LD = 1;
|
||||
perf_events[0] <= events;
|
||||
`endif
|
||||
noAction;
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
function Action incrMissCnt(cRqIdxT idx);
|
||||
action
|
||||
let lat <- latTimer.done(idx);
|
||||
`ifdef PERF_COUNT
|
||||
if(doStats) begin
|
||||
ldMissLat.incr(zeroExtend(lat));
|
||||
ldMissCnt.incr(1);
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache events = unpack (0);
|
||||
events.evt_LD_MISS_LAT = saturating_truncate(lat);
|
||||
events.evt_LD_MISS = 1;
|
||||
perf_events[1] <= events;
|
||||
`endif
|
||||
noAction;
|
||||
endaction
|
||||
endfunction
|
||||
`endif
|
||||
|
||||
function tagT getTag(Addr a) = truncateLSB(a);
|
||||
|
||||
@@ -227,10 +252,8 @@ module mkIBank#(
|
||||
}));
|
||||
// enq to indexQ for in order resp
|
||||
cRqIndexQ.enq(n);
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter: cRq type
|
||||
incrReqCnt;
|
||||
`endif
|
||||
if (verbose)
|
||||
$display("%t I %m cRqTransfer: ", $time,
|
||||
fshow(n), " ; ",
|
||||
@@ -377,10 +400,8 @@ module mkIBank#(
|
||||
fshow(slot), " ; ",
|
||||
fshow(cRqToP)
|
||||
);
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter: start miss timer
|
||||
latTimer.start(n);
|
||||
`endif
|
||||
endrule
|
||||
|
||||
// last stage of pipeline: process req
|
||||
@@ -617,10 +638,8 @@ module mkIBank#(
|
||||
"pRs must be a hit"
|
||||
);
|
||||
cRqHit(cOwner, procRq);
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter: miss cRq
|
||||
incrMissCnt(cOwner);
|
||||
`endif
|
||||
end
|
||||
else begin
|
||||
doAssert(False, ("pRs owner must match some cRq"));
|
||||
@@ -818,6 +837,9 @@ module mkIBank#(
|
||||
default: 0;
|
||||
endcase);
|
||||
endmethod
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events = perf_events[0];
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
|
||||
|
||||
@@ -60,6 +60,10 @@ import CrossBar::*;
|
||||
import Performance::*;
|
||||
import LatencyTimer::*;
|
||||
import RandomReplace::*;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor::*;
|
||||
import BlueUtils::*;
|
||||
`endif
|
||||
|
||||
export L1CRqStuck(..);
|
||||
export L1PRqStuck(..);
|
||||
@@ -103,6 +107,9 @@ interface L1Bank#(
|
||||
// performance
|
||||
method Action setPerfStatus(Bool stats);
|
||||
method Data getPerfData(L1DPerfType t);
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events;
|
||||
`endif
|
||||
endinterface
|
||||
|
||||
typedef struct {
|
||||
@@ -191,6 +198,7 @@ module mkL1Bank#(
|
||||
`endif
|
||||
|
||||
// performance
|
||||
LatencyTimer#(cRqNum, 10) latTimer <- mkLatencyTimer; // max 1K cycle latency
|
||||
`ifdef PERF_COUNT
|
||||
Reg#(Bool) doStats <- mkConfigReg(False);
|
||||
Count#(Data) ldCnt <- mkCount(0);
|
||||
@@ -202,43 +210,77 @@ module mkL1Bank#(
|
||||
Count#(Data) ldMissLat <- mkCount(0);
|
||||
Count#(Data) stMissLat <- mkCount(0);
|
||||
Count#(Data) amoMissLat <- mkCount(0);
|
||||
|
||||
LatencyTimer#(cRqNum, 10) latTimer <- mkLatencyTimer; // max 1K cycle latency
|
||||
|
||||
function Action incrReqCnt(MemOp op);
|
||||
action
|
||||
if(doStats) begin
|
||||
case(op)
|
||||
Ld: ldCnt.incr(1);
|
||||
St: stCnt.incr(1);
|
||||
Lr, Sc, Amo: amoCnt.incr(1);
|
||||
endcase
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
function Action incrMissCnt(MemOp op, cRqIdxT idx);
|
||||
action
|
||||
let lat <- latTimer.done(idx);
|
||||
if(doStats) begin
|
||||
case(op)
|
||||
Ld: begin
|
||||
ldMissLat.incr(zeroExtend(lat));
|
||||
ldMissCnt.incr(1);
|
||||
end
|
||||
St: begin
|
||||
stMissLat.incr(zeroExtend(lat));
|
||||
stMissCnt.incr(1);
|
||||
end
|
||||
Lr, Sc, Amo: begin
|
||||
amoMissLat.incr(zeroExtend(lat));
|
||||
amoMissCnt.incr(1);
|
||||
end
|
||||
endcase
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
Array #(Reg #(EventsCache)) perf_events <- mkDRegOR (2, unpack (0));
|
||||
`endif
|
||||
function Action incrReqCnt(MemOp op);
|
||||
action
|
||||
`ifdef PERF_COUNT
|
||||
if(doStats) begin
|
||||
case(op)
|
||||
Ld: ldCnt.incr(1);
|
||||
St: stCnt.incr(1);
|
||||
Lr, Sc, Amo: amoCnt.incr(1);
|
||||
endcase
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache events = unpack (0);
|
||||
case(op)
|
||||
Ld: events.evt_LD = 1;
|
||||
St: events.evt_ST = 1;
|
||||
Lr, Sc, Amo: events.evt_AMO = 1;
|
||||
endcase
|
||||
perf_events[0] <= events;
|
||||
`endif
|
||||
noAction;
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
function Action incrMissCnt(MemOp op, cRqIdxT idx);
|
||||
action
|
||||
let lat <- latTimer.done(idx);
|
||||
`ifdef PERF_COUNT
|
||||
if(doStats) begin
|
||||
case(op)
|
||||
Ld: begin
|
||||
ldMissLat.incr(zeroExtend(lat));
|
||||
ldMissCnt.incr(1);
|
||||
end
|
||||
St: begin
|
||||
stMissLat.incr(zeroExtend(lat));
|
||||
stMissCnt.incr(1);
|
||||
end
|
||||
Lr, Sc, Amo: begin
|
||||
amoMissLat.incr(zeroExtend(lat));
|
||||
amoMissCnt.incr(1);
|
||||
end
|
||||
endcase
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache events = unpack (0);
|
||||
case(op)
|
||||
Ld: begin
|
||||
events.evt_LD_MISS_LAT = saturating_truncate(lat);
|
||||
events.evt_LD_MISS = 1;
|
||||
end
|
||||
St: begin
|
||||
events.evt_ST_MISS_LAT = saturating_truncate(lat);
|
||||
events.evt_ST_MISS = 1;
|
||||
end
|
||||
Lr, Sc, Amo: begin
|
||||
events.evt_AMO_MISS_LAT = saturating_truncate(lat);
|
||||
events.evt_AMO_MISS = 1;
|
||||
end
|
||||
endcase
|
||||
perf_events[1] <= events;
|
||||
`endif
|
||||
noAction;
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
|
||||
function tagT getTag(Addr a) = truncateLSB(a);
|
||||
|
||||
@@ -274,10 +316,8 @@ module mkL1Bank#(
|
||||
addr: r.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter: cRq type
|
||||
incrReqCnt(r.op);
|
||||
`endif
|
||||
if (verbose)
|
||||
$display("%t L1 %m cRqTransfer_new: ", $time,
|
||||
fshow(n), " ; ",
|
||||
@@ -434,10 +474,8 @@ module mkL1Bank#(
|
||||
fshow(slot), " ; ",
|
||||
fshow(cRqToP)
|
||||
);
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter: start miss timer
|
||||
latTimer.start(n);
|
||||
`endif
|
||||
endrule
|
||||
|
||||
// last stage of pipeline: process req
|
||||
@@ -849,10 +887,8 @@ module mkL1Bank#(
|
||||
("pRs must be a hit")
|
||||
);
|
||||
cRqHit(cOwner, procRq);
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter: miss cRq
|
||||
incrMissCnt(procRq.op, cOwner);
|
||||
`endif
|
||||
end
|
||||
else begin
|
||||
doAssert(False, ("pRs owner must match some cRq"));
|
||||
@@ -1089,6 +1125,9 @@ module mkL1Bank#(
|
||||
default: 0;
|
||||
endcase);
|
||||
endmethod
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events = perf_events[0];
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
|
||||
@@ -1320,4 +1359,13 @@ module mkL1Cache#(
|
||||
end
|
||||
return fold(\+ , d);
|
||||
endmethod
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events;
|
||||
EventsCache ret = unpack(0);
|
||||
for(Integer i = 0; i < valueof(bankNum); i = i+1) begin
|
||||
ret = unpack(pack(ret) | pack(banks[i].events));
|
||||
end
|
||||
return ret;
|
||||
endmethod
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -51,6 +51,10 @@ import LatencyTimer::*;
|
||||
import Cntrs::*;
|
||||
import ConfigReg::*;
|
||||
import RandomReplace::*;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor::*;
|
||||
import BlueUtils::*;
|
||||
`endif
|
||||
|
||||
export LLCRqStuck(..);
|
||||
export LLBank(..);
|
||||
@@ -102,6 +106,9 @@ interface LLBank#(
|
||||
// performance
|
||||
method Action setPerfStatus(Bool stats);
|
||||
method Data getPerfData(LLCPerfType t);
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events;
|
||||
`endif
|
||||
endinterface
|
||||
|
||||
typedef struct {
|
||||
@@ -219,6 +226,7 @@ module mkLLBank#(
|
||||
`endif
|
||||
|
||||
// performance
|
||||
LatencyTimer#(cRqNum, 10) latTimer <- mkLatencyTimer; // max 1K cycle latency
|
||||
`ifdef PERF_COUNT
|
||||
Reg#(Bool) doStats <- mkConfigReg(False);
|
||||
Count#(Data) dmaMemLdCnt <- mkCount(0);
|
||||
@@ -233,25 +241,34 @@ module mkLLBank#(
|
||||
Count#(Data) upRespDataCnt <- mkCount(0);
|
||||
Count#(Data) dmaLdReqCnt <- mkCount(0);
|
||||
Count#(Data) dmaStReqCnt <- mkCount(0);
|
||||
|
||||
LatencyTimer#(cRqNum, 10) latTimer <- mkLatencyTimer; // max 1K cycle latency
|
||||
|
||||
function Action incrMissCnt(cRqIndexT idx, Bool isDma);
|
||||
action
|
||||
let lat <- latTimer.done(idx);
|
||||
if(doStats) begin
|
||||
if(isDma) begin
|
||||
dmaMemLdCnt.incr(1);
|
||||
dmaMemLdLat.incr(zeroExtend(lat));
|
||||
end
|
||||
else begin
|
||||
normalMemLdCnt.incr(1);
|
||||
normalMemLdLat.incr(zeroExtend(lat));
|
||||
end
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
Array #(Reg #(EventsCache)) perf_events <- mkDRegOR (2, unpack (0));
|
||||
`endif
|
||||
function Action incrMissCnt(cRqIndexT idx, Bool isDma);
|
||||
action
|
||||
let lat <- latTimer.done(idx);
|
||||
`ifdef PERF_COUNT
|
||||
if(doStats) begin
|
||||
if(isDma) begin
|
||||
dmaMemLdCnt.incr(1);
|
||||
dmaMemLdLat.incr(zeroExtend(lat));
|
||||
end
|
||||
else begin
|
||||
normalMemLdCnt.incr(1);
|
||||
normalMemLdLat.incr(zeroExtend(lat));
|
||||
end
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache events = unpack (0);
|
||||
events.evt_LD_MISS_LAT = saturating_truncate(lat); // Don't support seperate DMA counts.
|
||||
events.evt_LD_MISS = 1;
|
||||
perf_events[1] <= events;
|
||||
`endif
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
|
||||
function tagT getTag(Addr a) = truncateLSB(a);
|
||||
|
||||
@@ -515,10 +532,8 @@ module mkLLBank#(
|
||||
fshow(cRq), " ; ",
|
||||
fshow(cSlot), " ; "
|
||||
);
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter: normal miss lat and cnt
|
||||
incrMissCnt(n, False);
|
||||
`endif
|
||||
endrule
|
||||
|
||||
// this mem resp is just for a DMA req, won't go into pipeline to refill cache
|
||||
@@ -530,10 +545,8 @@ module mkLLBank#(
|
||||
// save data into cRq mshr & send to DMA resp IndexQ
|
||||
cRqMshr.mRsDeq.setData(mRs.id.mshrIdx, Valid (mRs.data));
|
||||
rsLdToDmaIndexQ_mRsDeq.enq(mRs.id.mshrIdx);
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter: dma miss lat and cnt
|
||||
incrMissCnt(mRs.id.mshrIdx, True);
|
||||
`endif
|
||||
endrule
|
||||
|
||||
// send rd/wr to mem
|
||||
@@ -572,10 +585,8 @@ module mkLLBank#(
|
||||
$display("%t LL %m sendToM: load only: ", $time, fshow(msg));
|
||||
doAssert(!isValid(data), "cannot have data");
|
||||
doAssert(!doLdAfterReplace, "doLdAfterReplace should be false");
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter: start miss timer
|
||||
latTimer.start(n);
|
||||
`endif
|
||||
`ifdef DEBUG_DMA
|
||||
if(cRq.id matches tagged Dma .dmaId) begin
|
||||
dmaRdMissQ.enq(dmaId); // DMA read takes effect
|
||||
@@ -619,10 +630,8 @@ module mkLLBank#(
|
||||
doLdAfterReplace <= False;
|
||||
if (verbose)
|
||||
$display("%t LL %m sendToM: rep then ld: ld: ", $time, fshow(msg));
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter: start miss timer
|
||||
latTimer.start(n);
|
||||
`endif
|
||||
end
|
||||
else begin // do write back part
|
||||
toMemT msg = Wb (WbMemRs {
|
||||
@@ -1531,6 +1540,9 @@ module mkLLBank#(
|
||||
default: 0;
|
||||
endcase);
|
||||
endmethod
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events = perf_events[0];
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
// Scheduling notes
|
||||
@@ -1593,4 +1605,3 @@ endmodule
|
||||
// -- this cRq is different from that in mRsDeq
|
||||
// -- this cRq is different from that in sendRsToC/sendRsToDma
|
||||
// -- XXX this cRq may be the same as that in sendRqToC!!!
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import Vector::*;
|
||||
import GetPut::*;
|
||||
import Cntrs::*;
|
||||
import ConfigReg::*;
|
||||
import DReg::*;
|
||||
import FIFO::*;
|
||||
import FIFOF::*;
|
||||
import Types::*;
|
||||
@@ -161,6 +162,9 @@ interface CommitStage;
|
||||
method Bool is_debug_halted;
|
||||
method Action debug_resume;
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCore events;
|
||||
`endif
|
||||
`ifdef DEBUG_WEDGE
|
||||
(* always_enabled *)
|
||||
method Tuple2#(CapMem, Bit#(32)) debugLastInst;
|
||||
@@ -410,6 +414,10 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
Count#(Data) flushCacheCnt <- mkCount(0);
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
Reg#(EventsCore) events_reg <- mkDReg(unpack(0));
|
||||
`endif
|
||||
|
||||
`ifdef RVFI
|
||||
// RVFI trace report. Not an input?
|
||||
FIFO#(Rvfi_Traces) rvfiQ <- mkFIFO;
|
||||
@@ -695,7 +703,11 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
end
|
||||
end
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCore events = unpack(0);
|
||||
events.evt_TRAP = 1;
|
||||
events_reg <= events;
|
||||
`endif
|
||||
// checks
|
||||
doAssert(x.rob_inst_state == Executed, "must be executed");
|
||||
doAssert(x.spec_bits == 0, "cannot have spec bits");
|
||||
@@ -988,6 +1000,13 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
end
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCore events = unpack(0);
|
||||
case(x.iType)
|
||||
Fence, FenceI, SFence: events.evt_FENCE = 1;
|
||||
endcase
|
||||
events_reg <= events;
|
||||
`endif
|
||||
`ifdef CHECK_DEADLOCK
|
||||
commitInst.send;
|
||||
if(csrf.decodeInfo.prv == 0) begin
|
||||
@@ -1060,7 +1079,6 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
// incr committed inst cnt at the end of rule
|
||||
SupCnt comInstCnt = 0;
|
||||
SupCnt comUserInstCnt = 0;
|
||||
`ifdef PERF_COUNT
|
||||
// incr some performance counter at the end of rule
|
||||
SupCnt brCnt = 0;
|
||||
SupCnt jmpCnt = 0;
|
||||
@@ -1070,7 +1088,14 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
SupCnt lrCnt = 0;
|
||||
SupCnt scCnt = 0;
|
||||
SupCnt amoCnt = 0;
|
||||
`endif
|
||||
SupCnt shiftCnt = 0;
|
||||
SupCnt muldivCnt = 0;
|
||||
SupCnt auipcCnt = 0;
|
||||
SupCnt fenceCnt = 0;
|
||||
SupCnt fpuCnt = 0;
|
||||
// CHERI-specific counters
|
||||
SupCnt ldCapCnt = 0;
|
||||
SupCnt stCapCnt = 0;
|
||||
|
||||
`ifdef RVFI
|
||||
Rvfi_Traces rvfis = replicate(tagged Invalid);
|
||||
@@ -1170,19 +1195,45 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
comUserInstCnt = comUserInstCnt + 1; // user space inst
|
||||
end
|
||||
|
||||
`ifdef PERF_COUNT
|
||||
// performance counter
|
||||
// performance counters
|
||||
// Some fields of the original instruction to help with classification.
|
||||
let inst = x.orig_inst;
|
||||
Opcode opcode = unpackOpcode(inst[ 6 : 0 ]);
|
||||
let funct3 = inst[ 14 : 12 ];
|
||||
let funct7 = inst[ 31 : 25 ];
|
||||
// For "F" and "D" ISA extensions
|
||||
let funct5 = inst[ 31 : 27 ];
|
||||
let fmt = inst[ 26 : 25 ];
|
||||
let rs3 = inst[ 31 : 27 ];
|
||||
let funct2 = inst[ 26 : 25 ];
|
||||
// For "A" ISA extension
|
||||
Bool aq = unpack(inst[ 26 ]);
|
||||
Bool rl = unpack(inst[ 25 ]);
|
||||
// For "xCHERI" ISA extension
|
||||
let funct5rs2 = inst[ 24 : 20 ];
|
||||
case(x.iType)
|
||||
Auipc, Auipcc: auipcCnt = auipcCnt + 1;
|
||||
Br: brCnt = brCnt + 1;
|
||||
J : jmpCnt = jmpCnt + 1;
|
||||
Jr: jrCnt = jrCnt + 1;
|
||||
Ld: ldCnt = ldCnt + 1;
|
||||
St: stCnt = stCnt + 1;
|
||||
Ld: begin
|
||||
ldCnt = ldCnt + 1;
|
||||
end
|
||||
St: begin
|
||||
stCnt = stCnt + 1;
|
||||
end
|
||||
Lr: lrCnt = lrCnt + 1;
|
||||
Sc: scCnt = scCnt + 1;
|
||||
Amo: amoCnt = amoCnt + 1;
|
||||
Fpu: fpuCnt = fpuCnt + 1;
|
||||
Alu: begin
|
||||
if (((opcode == opcOpImm) || (opcode == opcOpImm32) || (opcode == opcOp)) && ((funct3 == fnSLL) || (funct3 == fnSR)))
|
||||
shiftCnt = shiftCnt + 1;
|
||||
if ((opcode == opcOp || opcode == opcOp32) && funct7 == opMULDIV)
|
||||
muldivCnt = muldivCnt + 1;
|
||||
end
|
||||
endcase
|
||||
`endif
|
||||
if (opcode == opcMiscMem && funct3 == fnFENCE) fenceCnt = fenceCnt + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1235,6 +1286,23 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
end
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCore events = unpack(0);
|
||||
events.evt_BRANCH = brCnt;
|
||||
events.evt_JAL = jmpCnt;
|
||||
events.evt_JALR = jrCnt;
|
||||
events.evt_AUIPC = auipcCnt; // XXX
|
||||
events.evt_LOAD = ldCnt;
|
||||
events.evt_STORE = stCnt;
|
||||
events.evt_LR = lrCnt;
|
||||
events.evt_SC = scCnt;
|
||||
events.evt_AMO = amoCnt;
|
||||
events.evt_SERIAL_SHIFT = shiftCnt;
|
||||
events.evt_INT_MUL_DIV_REM = muldivCnt;
|
||||
events.evt_FP = fpuCnt;
|
||||
events.evt_FENCE = fenceCnt;
|
||||
events_reg <= events;
|
||||
`endif
|
||||
`ifdef RVFI
|
||||
rvfiQ.enq(rvfis);
|
||||
traceCnt <= traceCnt + zeroExtend(whichTrace);
|
||||
@@ -1309,6 +1377,10 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
endmethod
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method events = events_reg;
|
||||
`endif
|
||||
|
||||
`ifdef DEBUG_WEDGE
|
||||
method Tuple2#(CapMem, Bit#(32)) debugLastInst;
|
||||
return tuple2(rg_last_pcc, rg_last_inst);
|
||||
|
||||
@@ -68,6 +68,11 @@ import LatencyTimer::*;
|
||||
import CHERICap::*;
|
||||
import CHERICC_Fat::*;
|
||||
import ISA_Decls_CHERI::*;
|
||||
import CacheUtils::*;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor::*;
|
||||
import BlueUtils::*;
|
||||
`endif
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
|
||||
@@ -228,6 +233,9 @@ interface MemExePipeline;
|
||||
interface Server#(void, void) reconcile;
|
||||
`endif
|
||||
method Data getPerf(ExeStagePerfType t);
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCoreMem events;
|
||||
`endif
|
||||
endinterface
|
||||
|
||||
module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
@@ -237,6 +245,10 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
// is not good with single core
|
||||
Bool multicore = valueof(CoreNum) > 1;
|
||||
|
||||
// load/store memory total latency (max 1K cycle latency for 1 Ld/St)
|
||||
// These are always included as they are used by both stat counter systems.
|
||||
LatencyTimer#(LdQSize, 10) ldMemLatTimer <- mkLatencyTimer;
|
||||
LatencyTimer#(SBSize, 10) stMemLatTimer <- mkLatencyTimer;
|
||||
`ifdef PERF_COUNT
|
||||
// load issue stall
|
||||
Count#(Data) exeLdStallByLdCnt <- mkCount(0);
|
||||
@@ -245,8 +257,6 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
// load forward count
|
||||
Count#(Data) exeLdForwardCnt <- mkCount(0);
|
||||
// load/store memory total latency (max 1K cycle latency for 1 Ld/St)
|
||||
LatencyTimer#(LdQSize, 10) ldMemLatTimer <- mkLatencyTimer;
|
||||
LatencyTimer#(SBSize, 10) stMemLatTimer <- mkLatencyTimer;
|
||||
Count#(Data) exeLdMemLat <- mkCount(0);
|
||||
Count#(Data) exeStMemLat <- mkCount(0);
|
||||
// load to use latency: dispatch to resp
|
||||
@@ -265,6 +275,10 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
Count#(Data) exeFenceRelCnt <- mkCount(0);
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
Array #(Reg #(EventsCoreMem)) events_reg <- mkDRegOR (5, unpack (0));
|
||||
`endif
|
||||
|
||||
// reservation station
|
||||
ReservationStationMem rsMem <- mkReservationStationMem;
|
||||
|
||||
@@ -324,12 +338,18 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
if(verbose) begin
|
||||
$display("%t : [Ld resp] ", $time, fshow(id), "; ", fshow(d), "; ", fshow(info));
|
||||
end
|
||||
`ifdef PERF_COUNT
|
||||
// perf: load mem latency
|
||||
let lat <- ldMemLatTimer.done(tag);
|
||||
`ifdef PERF_COUNT
|
||||
if(inIfc.doStats) begin
|
||||
exeLdMemLat.incr(zeroExtend(lat));
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCoreMem events = unpack(0);
|
||||
events.evt_LOAD_WAIT = saturating_truncate(lat);
|
||||
events.evt_MEM_CAP_LOAD_TAG_SET = (d.tag) ? 1 : 0;
|
||||
events_reg[1] <= events;
|
||||
`endif
|
||||
endmethod
|
||||
method Action respLrScAmo(DProcReqId id, MemTaggedData d);
|
||||
@@ -346,18 +366,24 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
$display("[Store resp] idx ", fshow(id),
|
||||
", ", fshow(waitSt));
|
||||
end
|
||||
`ifdef PERF_COUNT
|
||||
// perf: store mem latency
|
||||
let lat <- stMemLatTimer.done(0);
|
||||
`ifdef PERF_COUNT
|
||||
if(inIfc.doStats) begin
|
||||
exeStMemLat.incr(zeroExtend(lat));
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCoreMem events = unpack(0);
|
||||
if (waitSt.shiftedBE == -1) events.evt_MEM_CAP_STORE = 1;
|
||||
events.evt_STORE_WAIT = saturating_truncate(lat);
|
||||
events_reg[2] <= events;
|
||||
`endif
|
||||
// now figure out the data to be written
|
||||
Vector#(LineSzData, ByteEn) be = replicate(replicate(False));
|
||||
Line data = replicate(0);
|
||||
be[waitSt.offset] = waitSt.shiftedBE;
|
||||
data[waitSt.offset] = waitSt.shiftedData;
|
||||
data[waitSt.offset] = waitSt.shiftedData; //XXX I guess this doesn't work with capabilities? Maybe we don't build TSO?
|
||||
return tuple2(unpack(pack(be)), data);
|
||||
endmethod
|
||||
`else
|
||||
@@ -366,12 +392,18 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
let e <- stb.deq(idx); // deq SB
|
||||
lsq.wakeupLdStalledBySB(idx); // wake up loads
|
||||
if(verbose) $display("[Store resp] idx = %x, ", idx, fshow(e));
|
||||
`ifdef PERF_COUNT
|
||||
// perf: store mem latency
|
||||
let lat <- stMemLatTimer.done(idx);
|
||||
`ifdef PERF_COUNT
|
||||
if(inIfc.doStats) begin
|
||||
exeStMemLat.incr(zeroExtend(lat));
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCoreMem events = unpack(0);
|
||||
if (pack(e.byteEn) == -1) events.evt_MEM_CAP_STORE = 1;
|
||||
events.evt_STORE_WAIT = saturating_truncate(lat);
|
||||
events_reg[2] <= events;
|
||||
`endif
|
||||
return tuple2(unpack(pack(e.byteEn)), e.line); // return SB entry
|
||||
endmethod
|
||||
@@ -510,6 +542,11 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
if(x.ldstq_tag matches tagged St .stTag) begin
|
||||
MemTaggedData d = x.mem_func == Amo ? toMemData : shiftData; // XXX don't shift for AMO
|
||||
lsq.updateData(stTag, d);
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCoreMem events = unpack(0);
|
||||
events.evt_MEM_CAP_STORE_TAG_SET = (d.tag) ? 1 : 0;
|
||||
events_reg[4] <= events;
|
||||
`endif
|
||||
end
|
||||
|
||||
CapPipe ddc = cast(inIfc.scaprf_rd(scrAddrDDC));
|
||||
@@ -672,6 +709,10 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
};
|
||||
`else
|
||||
SBSearchRes sbRes = stb.search(info.paddr, info.shiftedBE);
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCoreMem events = unpack(0);
|
||||
if (pack(info.shiftedBE) == -1) events.evt_MEM_CAP_LOAD = 1;
|
||||
`endif
|
||||
// search LSQ
|
||||
LSQIssueLdResult issRes <- lsq.issueLd(info.tag, info.paddr, info.shiftedBE, sbRes);
|
||||
@@ -695,10 +736,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
end
|
||||
else if(issRes == ToCache) begin
|
||||
reqLdQ.enq(tuple2(zeroExtend(info.tag), info.paddr));
|
||||
`ifdef PERF_COUNT
|
||||
// perf: load mem latency
|
||||
ldMemLatTimer.start(info.tag);
|
||||
`endif
|
||||
end
|
||||
else if(issRes matches tagged Stall .stallBy) begin
|
||||
`ifdef PERF_COUNT
|
||||
@@ -716,6 +755,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
else begin
|
||||
doAssert(False, "load is stalled");
|
||||
end
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
events_reg[0] <= events;
|
||||
`endif
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
@@ -1096,10 +1138,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
// we leave deq to resp time
|
||||
// ROB should have already been set to executed
|
||||
if(verbose) $display("[doDeqStQ_St] ", fshow(lsqDeqSt));
|
||||
`ifdef PERF_COUNT
|
||||
// perf: store mem latency
|
||||
stMemLatTimer.start(0);
|
||||
`endif
|
||||
endrule
|
||||
|
||||
`else
|
||||
@@ -1123,10 +1163,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
rule doIssueSB;
|
||||
let {sbIdx, en} <- stb.issue;
|
||||
reqStQ.enq(tuple2(sbIdx, {en.addr, 0}));
|
||||
`ifdef PERF_COUNT
|
||||
// perf: store mem latency
|
||||
stMemLatTimer.start(sbIdx);
|
||||
`endif
|
||||
endrule
|
||||
`endif
|
||||
|
||||
@@ -1286,6 +1324,11 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
if(inIfc.doStats && lsqDeqSt.memFunc == Sc && resp == fromInteger(valueof(ScSuccVal))) begin
|
||||
exeScSuccessCnt.incr(1);
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCoreMem events = unpack(0);
|
||||
events.evt_SC_SUCCESS = 1;
|
||||
events_reg[3] <= events;
|
||||
`endif
|
||||
endrule
|
||||
|
||||
@@ -1518,4 +1561,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
default: 0;
|
||||
endcase);
|
||||
endmethod
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method events = events_reg[0];
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -37,6 +37,101 @@
|
||||
`CSR(MIP, 12'h344)
|
||||
`CSR(MCYCLE, 12'hb00)
|
||||
`CSR(MINSTRET, 12'hb02)
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
`CSR(HPMCOUNTER3, 12'hc03)
|
||||
`CSR(HPMCOUNTER4, 12'hc04)
|
||||
`CSR(HPMCOUNTER5, 12'hc05)
|
||||
`CSR(HPMCOUNTER6, 12'hc06)
|
||||
`CSR(HPMCOUNTER7, 12'hc07)
|
||||
`CSR(HPMCOUNTER8, 12'hc08)
|
||||
`CSR(HPMCOUNTER9, 12'hc09)
|
||||
`CSR(HPMCOUNTER10, 12'hc0a)
|
||||
`CSR(HPMCOUNTER11, 12'hc0b)
|
||||
`CSR(HPMCOUNTER12, 12'hc0c)
|
||||
`CSR(HPMCOUNTER13, 12'hc0d)
|
||||
`CSR(HPMCOUNTER14, 12'hc0e)
|
||||
`CSR(HPMCOUNTER15, 12'hc0f)
|
||||
`CSR(HPMCOUNTER16, 12'hc10)
|
||||
`CSR(HPMCOUNTER17, 12'hc11)
|
||||
`CSR(HPMCOUNTER18, 12'hc12)
|
||||
`CSR(HPMCOUNTER19, 12'hc13)
|
||||
`CSR(HPMCOUNTER20, 12'hc14)
|
||||
`CSR(HPMCOUNTER21, 12'hc15)
|
||||
`CSR(HPMCOUNTER22, 12'hc16)
|
||||
`CSR(HPMCOUNTER23, 12'hc17)
|
||||
`CSR(HPMCOUNTER24, 12'hc18)
|
||||
`CSR(HPMCOUNTER25, 12'hc19)
|
||||
`CSR(HPMCOUNTER26, 12'hc1a)
|
||||
`CSR(HPMCOUNTER27, 12'hc1b)
|
||||
`CSR(HPMCOUNTER28, 12'hc1c)
|
||||
`CSR(HPMCOUNTER29, 12'hc1d)
|
||||
`CSR(HPMCOUNTER30, 12'hc1e)
|
||||
`CSR(HPMCOUNTER31, 12'hc1f)
|
||||
|
||||
`CSR(MHPMCOUNTER3, 12'hb03)
|
||||
`CSR(MHPMCOUNTER4, 12'hb04)
|
||||
`CSR(MHPMCOUNTER5, 12'hb05)
|
||||
`CSR(MHPMCOUNTER6, 12'hb06)
|
||||
`CSR(MHPMCOUNTER7, 12'hb07)
|
||||
`CSR(MHPMCOUNTER8, 12'hb08)
|
||||
`CSR(MHPMCOUNTER9, 12'hb09)
|
||||
`CSR(MHPMCOUNTER10, 12'hb0a)
|
||||
`CSR(MHPMCOUNTER11, 12'hb0b)
|
||||
`CSR(MHPMCOUNTER12, 12'hb0c)
|
||||
`CSR(MHPMCOUNTER13, 12'hb0d)
|
||||
`CSR(MHPMCOUNTER14, 12'hb0e)
|
||||
`CSR(MHPMCOUNTER15, 12'hb0f)
|
||||
`CSR(MHPMCOUNTER16, 12'hb10)
|
||||
`CSR(MHPMCOUNTER17, 12'hb11)
|
||||
`CSR(MHPMCOUNTER18, 12'hb12)
|
||||
`CSR(MHPMCOUNTER19, 12'hb13)
|
||||
`CSR(MHPMCOUNTER20, 12'hb14)
|
||||
`CSR(MHPMCOUNTER21, 12'hb15)
|
||||
`CSR(MHPMCOUNTER22, 12'hb16)
|
||||
`CSR(MHPMCOUNTER23, 12'hb17)
|
||||
`CSR(MHPMCOUNTER24, 12'hb18)
|
||||
`CSR(MHPMCOUNTER25, 12'hb19)
|
||||
`CSR(MHPMCOUNTER26, 12'hb1a)
|
||||
`CSR(MHPMCOUNTER27, 12'hb1b)
|
||||
`CSR(MHPMCOUNTER28, 12'hb1c)
|
||||
`CSR(MHPMCOUNTER29, 12'hb1d)
|
||||
`CSR(MHPMCOUNTER30, 12'hb1e)
|
||||
`CSR(MHPMCOUNTER31, 12'hb1f)
|
||||
|
||||
`CSR(MCOUNTERINHIBIT, 12'h320) // Machine Counter-Inhibit
|
||||
|
||||
`CSR(MHPMEVENT3, 12'h323)
|
||||
`CSR(MHPMEVENT4, 12'h324)
|
||||
`CSR(MHPMEVENT5, 12'h325)
|
||||
`CSR(MHPMEVENT6, 12'h326)
|
||||
`CSR(MHPMEVENT7, 12'h327)
|
||||
`CSR(MHPMEVENT8, 12'h328)
|
||||
`CSR(MHPMEVENT9, 12'h329)
|
||||
`CSR(MHPMEVENT10, 12'h32a)
|
||||
`CSR(MHPMEVENT11, 12'h32b)
|
||||
`CSR(MHPMEVENT12, 12'h32c)
|
||||
`CSR(MHPMEVENT13, 12'h32d)
|
||||
`CSR(MHPMEVENT14, 12'h32e)
|
||||
`CSR(MHPMEVENT15, 12'h32f)
|
||||
`CSR(MHPMEVENT16, 12'h330)
|
||||
`CSR(MHPMEVENT17, 12'h331)
|
||||
`CSR(MHPMEVENT18, 12'h332)
|
||||
`CSR(MHPMEVENT19, 12'h333)
|
||||
`CSR(MHPMEVENT20, 12'h334)
|
||||
`CSR(MHPMEVENT21, 12'h335)
|
||||
`CSR(MHPMEVENT22, 12'h336)
|
||||
`CSR(MHPMEVENT23, 12'h337)
|
||||
`CSR(MHPMEVENT24, 12'h338)
|
||||
`CSR(MHPMEVENT25, 12'h339)
|
||||
`CSR(MHPMEVENT26, 12'h33a)
|
||||
`CSR(MHPMEVENT27, 12'h33b)
|
||||
`CSR(MHPMEVENT28, 12'h33c)
|
||||
`CSR(MHPMEVENT29, 12'h33d)
|
||||
`CSR(MHPMEVENT30, 12'h33e)
|
||||
`CSR(MHPMEVENT31, 12'h33f)
|
||||
`endif // PERFORMANCE_MONITORING
|
||||
|
||||
`CSR(MVENDORID, 12'hf11)
|
||||
`CSR(MARCHID, 12'hf12)
|
||||
`CSR(MIMPID, 12'hf13)
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//
|
||||
// This work was supported by NCSC programme grant 4212611/RFA 15971 ("SafeBet").
|
||||
//-
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
@@ -21,10 +21,10 @@
|
||||
// modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
@@ -52,6 +52,11 @@ import LatencyTimer::*;
|
||||
import HasSpecBits::*;
|
||||
import Vector::*;
|
||||
import Ehr::*;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor::*;
|
||||
import CCTypes::*;
|
||||
import BlueUtils::*;
|
||||
`endif
|
||||
|
||||
export DTlbReq(..);
|
||||
export DTlbResp(..);
|
||||
@@ -86,7 +91,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
// may get page fault: i.e. hit invalid page or
|
||||
// get non-leaf page at last-level page table
|
||||
Maybe#(TlbEntry) entry;
|
||||
Maybe#(TlbEntry) entry;
|
||||
DTlbReqIdx id;
|
||||
} DTlbTransRsFromP deriving(Bits, Eq, FShow);
|
||||
|
||||
@@ -117,6 +122,9 @@ interface DTlb#(type instT);
|
||||
|
||||
// performance
|
||||
interface Perf#(L1TlbPerfType) perf;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events;
|
||||
`endif
|
||||
endinterface
|
||||
|
||||
typedef FullAssocTlb#(DTlbSize) DTlbArray;
|
||||
@@ -199,6 +207,7 @@ module mkDTlb#(
|
||||
Fifo#(1, void) flushRsFromPQ <- mkCFFifo;
|
||||
|
||||
// perf counters
|
||||
LatencyTimer#(DTlbReqNum, 12) latTimer <- mkLatencyTimer; // max latency: 4K cycles
|
||||
Fifo#(1, L1TlbPerfType) perfReqQ <- mkCFFifo;
|
||||
`ifdef PERF_COUNT
|
||||
Fifo#(1, PerfResp#(L1TlbPerfType)) perfRespQ <- mkCFFifo;
|
||||
@@ -211,8 +220,6 @@ module mkDTlb#(
|
||||
Count#(Data) hitUnderMissCnt <- mkCount(0);
|
||||
Count#(Data) allMissCycles <- mkCount(0);
|
||||
|
||||
LatencyTimer#(DTlbReqNum, 12) latTimer <- mkLatencyTimer; // max latency: 4K cycles
|
||||
|
||||
rule doPerf;
|
||||
let t <- toGet(perfReqQ).get;
|
||||
Data d = (case(t)
|
||||
@@ -236,6 +243,9 @@ module mkDTlb#(
|
||||
when(all(isMiss, readVReg(pendWait)), allMissCycles.incr(1));
|
||||
endrule
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
Array #(Reg #(EventsCache)) perf_events <- mkDRegOR (3, unpack (0));
|
||||
`endif
|
||||
|
||||
// do flush: start when all misses resolve
|
||||
Bool noMiss = all(\== (False) , readVReg(pendValid_noMiss));
|
||||
@@ -246,6 +256,11 @@ module mkDTlb#(
|
||||
flushRqToPQ.enq(?);
|
||||
waitFlushP <= True;
|
||||
if(verbose) $display("[DTLB] flush begin");
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache ev = unpack(0);
|
||||
ev.evt_TLB_FLUSH = 1;
|
||||
perf_events[2] <= ev;
|
||||
`endif
|
||||
endrule
|
||||
|
||||
rule doFinishFlush(needFlush && waitFlushP);
|
||||
@@ -333,9 +348,9 @@ module mkDTlb#(
|
||||
ldTransRsFromPQ.deq;
|
||||
end
|
||||
|
||||
`ifdef PERF_COUNT
|
||||
// perf: miss
|
||||
let lat <- latTimer.done(idx);
|
||||
`ifdef PERF_COUNT
|
||||
if(doStats) begin
|
||||
if(isValid(respForOtherReq)) begin
|
||||
missPeerLat.incr(zeroExtend(lat));
|
||||
@@ -347,7 +362,12 @@ module mkDTlb#(
|
||||
end
|
||||
end
|
||||
`endif
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache ev = unpack(0);
|
||||
ev.evt_TLB_MISS_LAT = saturating_truncate(lat);
|
||||
ev.evt_TLB_MISS = 1;
|
||||
perf_events[0] <= ev;
|
||||
`endif
|
||||
// conflict with wrong spec
|
||||
wrongSpec_doPRs_conflict.wset(?);
|
||||
endrule
|
||||
@@ -516,10 +536,8 @@ module mkDTlb#(
|
||||
idx, fshow(r));
|
||||
end
|
||||
end
|
||||
`ifdef PERF_COUNT
|
||||
// perf: miss
|
||||
latTimer.start(idx);
|
||||
`endif
|
||||
end
|
||||
end
|
||||
else begin
|
||||
@@ -534,6 +552,11 @@ module mkDTlb#(
|
||||
if(doStats) begin
|
||||
accessCnt.incr(1);
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache ev = unpack(0);
|
||||
ev.evt_TLB = 1;
|
||||
perf_events[1] <= ev;
|
||||
`endif
|
||||
// conflict with wrong spec
|
||||
wrongSpec_procReq_conflict.wset(?);
|
||||
@@ -623,4 +646,7 @@ module mkDTlb#(
|
||||
`endif
|
||||
endmethod
|
||||
endinterface
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events = perf_events[0];
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -515,17 +515,17 @@ function Maybe#(Trap) checkForException(
|
||||
Bool writes_csr = ((dInst.execFunc == tagged Alu Csrw) || (rs1 != 0) || (imm != 0));
|
||||
Bool read_only = (csr [11:10] == 2'b11);
|
||||
Bool write_deny = (writes_csr && read_only);
|
||||
Bool asr_deny = !getHardPerms(pcc).accessSysRegs && !(
|
||||
//((csr_addr_hpmcounter3 <= csr) && (csr <= csr_addr_hpmcounter31) && writes_csr) // TODO seems these aren't implemented?
|
||||
(csr == pack(csrAddrFFLAGS))
|
||||
|| (csr == pack(csrAddrFRM))
|
||||
|| (csr == pack(csrAddrFCSR))
|
||||
|| (csr == pack(csrAddrCYCLE) && writes_csr)
|
||||
|| (csr == pack(csrAddrINSTRET) && writes_csr));
|
||||
Bool asr_allow = getHardPerms(pcc).accessSysRegs
|
||||
//|| ((csr_addr_hpmcounter3 <= csr) && (csr <= csr_addr_hpmcounter31) && !writes_csr) // TODO seems these aren't implemented?
|
||||
|| (csr == pack(csrAddrFFLAGS))
|
||||
|| (csr == pack(csrAddrFRM))
|
||||
|| (csr == pack(csrAddrFCSR))
|
||||
|| (csr == pack(csrAddrCYCLE) && !writes_csr)
|
||||
|| (csr == pack(csrAddrINSTRET) && !writes_csr);
|
||||
Bool unimplemented = (csr == pack(csrAddrNone)); // Added by Bluespec
|
||||
if (write_deny || !csr_has_priv || unimplemented) begin
|
||||
exception = Valid (Exception (excIllegalInst));
|
||||
end else if (asr_deny) begin
|
||||
end else if (!asr_allow) begin
|
||||
exception = Valid (CapException (CSR_XCapCause {cheri_exc_reg: {1'b1, pack(scrAddrPCC)}, cheri_exc_code: cheriExcPermitASRViolation}));
|
||||
end
|
||||
end
|
||||
@@ -535,11 +535,11 @@ function Maybe#(Trap) checkForException(
|
||||
Bool writes_scr = regs.src1 == Valid (tagged Gpr 0) ? False : True;
|
||||
Bool read_only = (scr == scrAddrPCC);
|
||||
Bool write_deny = (writes_scr && read_only);
|
||||
Bool asr_deny = !getHardPerms(pcc).accessSysRegs && !(
|
||||
scr == scrAddrDDC || scr == scrAddrPCC);
|
||||
Bool asr_allow = getHardPerms(pcc).accessSysRegs ||
|
||||
scr == scrAddrDDC || scr == scrAddrPCC;
|
||||
if(!scr_has_priv || unimplemented || write_deny) begin
|
||||
exception = Valid (Exception (excIllegalInst));
|
||||
end else if (asr_deny) begin
|
||||
end else if (!asr_allow) begin
|
||||
exception = Valid (CapException (CSR_XCapCause {cheri_exc_reg: {1'b1, pack(scrAddrPCC)}, cheri_exc_code: cheriExcPermitASRViolation}));
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//
|
||||
// This work was supported by NCSC programme grant 4212611/RFA 15971 ("SafeBet").
|
||||
//-
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
@@ -21,10 +21,10 @@
|
||||
// modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
@@ -49,6 +49,11 @@ import Cntrs::*;
|
||||
import SafeCounter::*;
|
||||
import CacheUtils::*;
|
||||
import LatencyTimer::*;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor::*;
|
||||
import CCTypes::*;
|
||||
import BlueUtils::*;
|
||||
`endif
|
||||
|
||||
// currently blocking
|
||||
typedef `L1_TLB_SIZE ITlbSize;
|
||||
@@ -60,7 +65,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
// may get page fault: i.e. hit invalid page or
|
||||
// get non-leaf page at last-level page table
|
||||
Maybe#(TlbEntry) entry;
|
||||
Maybe#(TlbEntry) entry;
|
||||
} ITlbRsFromP deriving(Bits, Eq, FShow);
|
||||
|
||||
interface ITlbToParent;
|
||||
@@ -85,6 +90,9 @@ interface ITlb;
|
||||
|
||||
// performance
|
||||
interface Perf#(L1TlbPerfType) perf;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events;
|
||||
`endif
|
||||
endinterface
|
||||
|
||||
typedef FullAssocTlb#(ITlbSize) ITlbArray;
|
||||
@@ -122,6 +130,7 @@ module mkITlb(ITlb::ITlb);
|
||||
Fifo#(1, void) flushRsFromPQ <- mkCFFifo;
|
||||
|
||||
// perf counters
|
||||
LatencyTimer#(2, 12) latTimer <- mkLatencyTimer; // max latency: 4K cycles
|
||||
Fifo#(1, L1TlbPerfType) perfReqQ <- mkCFFifo;
|
||||
`ifdef PERF_COUNT
|
||||
Fifo#(1, PerfResp#(L1TlbPerfType)) perfRespQ <- mkCFFifo;
|
||||
@@ -130,8 +139,6 @@ module mkITlb(ITlb::ITlb);
|
||||
Count#(Data) missCnt <- mkCount(0);
|
||||
Count#(Data) missLat <- mkCount(0);
|
||||
|
||||
LatencyTimer#(2, 12) latTimer <- mkLatencyTimer; // max latency: 4K cycles
|
||||
|
||||
rule doPerf;
|
||||
let t <- toGet(perfReqQ).get;
|
||||
Data d = (case(t)
|
||||
@@ -146,6 +153,9 @@ module mkITlb(ITlb::ITlb);
|
||||
});
|
||||
endrule
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
Array #(Reg #(EventsCache)) perf_events <- mkDRegOR (3, unpack (0));
|
||||
`endif
|
||||
|
||||
// do flush: only start when all misses resolve
|
||||
rule doStartFlush(needFlush && !waitFlushP && !isValid(miss));
|
||||
@@ -154,6 +164,11 @@ module mkITlb(ITlb::ITlb);
|
||||
flushRqToPQ.enq(?);
|
||||
waitFlushP <= True;
|
||||
if(verbose) $display("ITLB %m: flush begin");
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache ev = unpack(0);
|
||||
ev.evt_TLB_FLUSH = 1;
|
||||
perf_events[2] <= ev;
|
||||
`endif
|
||||
endrule
|
||||
|
||||
rule doFinishFlush(needFlush && waitFlushP && !isValid(miss));
|
||||
@@ -172,7 +187,7 @@ module mkITlb(ITlb::ITlb);
|
||||
// search TLB to check whether the PTE is already in TLB; this may
|
||||
// happen for mega/giga pages. We don't want same PTE to occupy >1
|
||||
// TLB entires.
|
||||
|
||||
|
||||
// check permission
|
||||
if(hasVMPermission(vm_info,
|
||||
en.pteType,
|
||||
@@ -206,11 +221,17 @@ module mkITlb(ITlb::ITlb);
|
||||
// miss resolved
|
||||
miss <= Invalid;
|
||||
|
||||
`ifdef PERF_COUNT
|
||||
let lat <- latTimer.done(0);
|
||||
`ifdef PERF_COUNT
|
||||
if(doStats) begin
|
||||
missLat.incr(zeroExtend(lat));
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache ev = unpack(0);
|
||||
ev.evt_TLB_MISS_LAT = saturating_truncate(lat);
|
||||
ev.evt_TLB_MISS = 1;
|
||||
perf_events[0] <= ev;
|
||||
`endif
|
||||
endrule
|
||||
|
||||
@@ -320,8 +341,8 @@ module mkITlb(ITlb::ITlb);
|
||||
if(verbose) begin
|
||||
$display("ITLB %m req (miss): ", fshow(vaddr));
|
||||
end
|
||||
`ifdef PERF_COUNT
|
||||
latTimer.start(0);
|
||||
`ifdef PERF_COUNT
|
||||
if(doStats) begin
|
||||
missCnt.incr(1);
|
||||
end
|
||||
@@ -338,6 +359,11 @@ module mkITlb(ITlb::ITlb);
|
||||
if(doStats) begin
|
||||
accessCnt.incr(1);
|
||||
end
|
||||
`endif
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
EventsCache ev = unpack(0);
|
||||
ev.evt_TLB = 1;
|
||||
perf_events[1] <= ev;
|
||||
`endif
|
||||
endmethod
|
||||
endinterface
|
||||
@@ -387,4 +413,7 @@ module mkITlb(ITlb::ITlb);
|
||||
`endif
|
||||
endmethod
|
||||
endinterface
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events = perf_events[0];
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -178,6 +178,9 @@ interface DCoCache;
|
||||
method Bool flush_done;
|
||||
method Action resetLinkAddr;
|
||||
interface Perf#(L1DPerfType) perf;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events;
|
||||
`endif
|
||||
|
||||
interface ChildCacheToParent#(L1Way, void) to_parent;
|
||||
|
||||
@@ -267,6 +270,9 @@ module mkDCoCache#(L1ProcResp#(DProcReqId) procResp)(DCoCache);
|
||||
`endif
|
||||
endmethod
|
||||
endinterface
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events = cache.events;
|
||||
`endif
|
||||
|
||||
interface to_parent = cache.to_parent;
|
||||
|
||||
@@ -366,6 +372,9 @@ interface ICoCache;
|
||||
method Action flush;
|
||||
method Bool flush_done;
|
||||
interface Perf#(L1IPerfType) perf;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events;
|
||||
`endif
|
||||
|
||||
interface ChildCacheToParent#(L1Way, void) to_parent;
|
||||
|
||||
@@ -436,6 +445,9 @@ module mkICoCache(ICoCache);
|
||||
`endif
|
||||
endmethod
|
||||
endinterface
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events = cache.events;
|
||||
`endif
|
||||
|
||||
interface to_parent = cache.to_parent;
|
||||
|
||||
|
||||
@@ -131,9 +131,9 @@ module mkLLCDmaConnect #(
|
||||
DmaServer#(LLCDmaReqId) llc,
|
||||
// MemLoaderMemClient memLoader, // REPLACED BY AXI4_Slave_interface
|
||||
Vector#(CoreNum, TlbMemClient) tlb
|
||||
)(AXI4_Slave_Synth #(Wd_SId_2x3, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User)) provisos (
|
||||
)(AXI4_Slave #(Wd_SId_2x3, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User)) provisos (
|
||||
Alias#(dmaRqT, DmaRq#(LLCDmaReqId))
|
||||
);
|
||||
Bool verbose = False;
|
||||
@@ -143,8 +143,8 @@ module mkLLCDmaConnect #(
|
||||
// When debugger reads a word, request a line from LLC, and remember dword-in-line here
|
||||
FIFOF #(Bit #(3)) f_dword_in_line <- mkFIFOF;
|
||||
|
||||
// Slave transactor for requests from Debug Module
|
||||
let axi4_slave_xactor <- mkAXI4_Slave_Xactor;
|
||||
// Connector to AXI4 fabric
|
||||
let slavePortShim <- mkAXI4ShimFF;
|
||||
|
||||
// ================================================================
|
||||
// These regs are a 1-location local cache for an LLC Cache Line,
|
||||
@@ -163,10 +163,10 @@ module mkLLCDmaConnect #(
|
||||
// Respond to store-requests from the external client on store-hit
|
||||
rule rl_handle_MemLoader_st_req ( ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
|
||||
|| (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY))
|
||||
&& (fn_addr_is_in_line (axi4_slave_xactor.master.aw.peek.awaddr,
|
||||
&& (fn_addr_is_in_line (slavePortShim.master.aw.peek.awaddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
let wr_addr <- get (axi4_slave_xactor.master.aw);
|
||||
let wr_data <- get (axi4_slave_xactor.master.w);
|
||||
let wr_addr <- get (slavePortShim.master.aw);
|
||||
let wr_data <- get (slavePortShim.master.w);
|
||||
|
||||
// Modify relevant bytes of relevant dword
|
||||
let newLine = setDataAtBE( rg_cacheline_cache_data
|
||||
@@ -178,7 +178,7 @@ module mkLLCDmaConnect #(
|
||||
rg_cacheline_cache_dirty_delay <= '1; // start write-back delay countdown
|
||||
|
||||
// Send response to external client
|
||||
axi4_slave_xactor.master.b.put(AXI4_BFlit{
|
||||
slavePortShim.master.b.put(AXI4_BFlit{
|
||||
bid: wr_addr.awid, // TODO: change uniformly to Fabric_id
|
||||
bresp: OKAY,
|
||||
buser: ?
|
||||
@@ -198,14 +198,14 @@ module mkLLCDmaConnect #(
|
||||
// Responds to load-requests from the external client on load-hit
|
||||
rule rl_handle_MemLoader_ld_req ( ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
|
||||
|| (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY))
|
||||
&& (fn_addr_is_in_line (axi4_slave_xactor.master.ar.peek.araddr,
|
||||
&& (fn_addr_is_in_line (slavePortShim.master.ar.peek.araddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
let rd_addr <- get (axi4_slave_xactor.master.ar);
|
||||
let rd_addr <- get (slavePortShim.master.ar);
|
||||
let dword = getDataAt( rg_cacheline_cache_data
|
||||
, getCLineDataSel(rd_addr.araddr));
|
||||
|
||||
// Send response to external client
|
||||
axi4_slave_xactor.master.r.put(AXI4_RFlit{
|
||||
slavePortShim.master.r.put(AXI4_RFlit{
|
||||
rid: rd_addr.arid,
|
||||
rdata: dword,
|
||||
rresp: OKAY,
|
||||
@@ -255,12 +255,12 @@ module mkLLCDmaConnect #(
|
||||
|
||||
// Initiate writeback if dirty and next request is store-miss
|
||||
rule rl_cacheline_cache_writeback_st_miss ( (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY)
|
||||
&& (! fn_addr_is_in_line (axi4_slave_xactor.master.aw.peek.awaddr,
|
||||
&& (! fn_addr_is_in_line (slavePortShim.master.aw.peek.awaddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_writeback_st_miss.", cur_cycle);
|
||||
$display (" Old line addr %0h", rg_cacheline_cache_addr);
|
||||
$display (" New addr %0h", axi4_slave_xactor.master.aw.peek.awaddr);
|
||||
$display (" New addr %0h", slavePortShim.master.aw.peek.awaddr);
|
||||
end
|
||||
|
||||
fa_writeback;
|
||||
@@ -269,12 +269,12 @@ module mkLLCDmaConnect #(
|
||||
|
||||
// Initiate writeback if dirty and next request is load-miss
|
||||
rule rl_cacheline_cache_writeback_ld_miss ( (rg_cacheline_cache_state == CACHELINE_CACHE_DIRTY)
|
||||
&& (! fn_addr_is_in_line (axi4_slave_xactor.master.ar.peek.araddr,
|
||||
&& (! fn_addr_is_in_line (slavePortShim.master.ar.peek.araddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_writeback_ld_miss.", cur_cycle);
|
||||
$display (" Old line addr %0h", rg_cacheline_cache_addr);
|
||||
$display (" New addr %0h", axi4_slave_xactor.master.aw.peek.awaddr);
|
||||
$display (" New addr %0h", slavePortShim.master.aw.peek.awaddr);
|
||||
end
|
||||
|
||||
fa_writeback;
|
||||
@@ -313,9 +313,9 @@ module mkLLCDmaConnect #(
|
||||
|
||||
// Initiate reload when cacheline_cache is clean on store-miss
|
||||
rule rl_cacheline_cache_reload_req_st ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
|
||||
&& (! fn_addr_is_in_line (axi4_slave_xactor.master.aw.peek.awaddr,
|
||||
&& (! fn_addr_is_in_line (slavePortShim.master.aw.peek.awaddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
let addr = axi4_slave_xactor.master.aw.peek.awaddr;
|
||||
let addr = slavePortShim.master.aw.peek.awaddr;
|
||||
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_reload_req_st for addr %0h", cur_cycle, addr);
|
||||
@@ -327,9 +327,9 @@ module mkLLCDmaConnect #(
|
||||
|
||||
// Initiate reload when cacheline_cache is clean on load-miss
|
||||
rule rl_cacheline_cache_reload_req_ld ( (rg_cacheline_cache_state == CACHELINE_CACHE_CLEAN)
|
||||
&& (! fn_addr_is_in_line (axi4_slave_xactor.master.ar.peek.araddr,
|
||||
&& (! fn_addr_is_in_line (slavePortShim.master.ar.peek.araddr,
|
||||
rg_cacheline_cache_addr)));
|
||||
let addr = axi4_slave_xactor.master.ar.peek.araddr;
|
||||
let addr = slavePortShim.master.ar.peek.araddr;
|
||||
|
||||
if (verbosity >= 2) begin
|
||||
$display ("%0d: %m.rl_cacheline_cache_reload_req_ld for addr %0h", cur_cycle, addr);
|
||||
@@ -424,5 +424,5 @@ module mkLLCDmaConnect #(
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
return axi4_slave_xactor.slaveSynth;
|
||||
return slavePortShim.slave;
|
||||
endmodule
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//
|
||||
// This work was supported by NCSC programme grant 4212611/RFA 15971 ("SafeBet").
|
||||
//-
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
@@ -21,10 +21,10 @@
|
||||
// modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
@@ -254,6 +254,9 @@ interface LLCache;
|
||||
interface Get#(LLCStuck) cRqStuck;
|
||||
// performance
|
||||
interface Perf#(LLCPerfType) perf;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events;
|
||||
`endif
|
||||
endinterface
|
||||
|
||||
`ifdef SECURITY
|
||||
@@ -462,4 +465,7 @@ module mkLLCache(LLCache);
|
||||
`endif
|
||||
endmethod
|
||||
endinterface
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
method EventsCache events = cache.events;
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
@@ -50,7 +50,6 @@ import ISA_Decls_CHERI::*;
|
||||
import GetPut::*;
|
||||
import RVFI_DII_Types::*;
|
||||
`endif
|
||||
import ISA_Decls_CHERI::*;
|
||||
|
||||
typedef `NUM_CORES CoreNum;
|
||||
typedef Bit#(TLog#(CoreNum)) CoreId;
|
||||
@@ -1040,3 +1039,77 @@ function Fmt showInst(Instruction inst);
|
||||
endfunction
|
||||
|
||||
function x addPc(x cap, Bit#(12) inc) provisos (Add#(f, 12, c), CHERICap::CHERICap#(x, a, b, c, d, e)) = setAddrUnsafe(cap, getAddr(cap) + signExtend(inc));
|
||||
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
typedef 128 No_Of_Evts;
|
||||
typedef 8 Report_Width;
|
||||
typedef 64 Counter_Width;
|
||||
typedef 29 No_Of_Ctrs;
|
||||
|
||||
typedef struct {
|
||||
SupCnt evt_REDIRECT;
|
||||
SupCnt evt_TRAP;
|
||||
SupCnt evt_BRANCH;
|
||||
SupCnt evt_JAL;
|
||||
SupCnt evt_JALR;
|
||||
SupCnt evt_AUIPC;
|
||||
SupCnt evt_LOAD;
|
||||
SupCnt evt_STORE;
|
||||
SupCnt evt_LR;
|
||||
SupCnt evt_SC;
|
||||
SupCnt evt_AMO;
|
||||
SupCnt evt_SERIAL_SHIFT;
|
||||
SupCnt evt_INT_MUL_DIV_REM;
|
||||
SupCnt evt_FP;
|
||||
SupCnt evt_SC_SUCCESS;
|
||||
SupCnt evt_LOAD_WAIT;
|
||||
SupCnt evt_STORE_WAIT;
|
||||
SupCnt evt_FENCE;
|
||||
SupCnt evt_F_BUSY_NO_CONSUME; // XXX
|
||||
SupCnt evt_D_BUSY_NO_CONSUME; // XXX
|
||||
SupCnt evt_1_BUSY_NO_CONSUME; // XXX
|
||||
SupCnt evt_2_BUSY_NO_CONSUME; // XXX
|
||||
SupCnt evt_3_BUSY_NO_CONSUME; // XXX
|
||||
SupCnt evt_IMPRECISE_SETBOUND; // XXX
|
||||
SupCnt evt_UNREPRESENTABLE_CAP; // XXX
|
||||
SupCnt evt_MEM_CAP_LOAD;
|
||||
SupCnt evt_MEM_CAP_STORE;
|
||||
SupCnt evt_MEM_CAP_LOAD_TAG_SET;
|
||||
SupCnt evt_MEM_CAP_STORE_TAG_SET;
|
||||
} EventsCore deriving (Bits, FShow);
|
||||
typedef TDiv#(SizeOf#(EventsCore),SizeOf#(SupCnt)) EventsCoreElements;
|
||||
|
||||
typedef Bit#(Report_Width) HpmRpt;
|
||||
typedef struct {
|
||||
HpmRpt evt_REDIRECT;
|
||||
HpmRpt evt_TRAP;
|
||||
HpmRpt evt_BRANCH;
|
||||
HpmRpt evt_JAL;
|
||||
HpmRpt evt_JALR;
|
||||
HpmRpt evt_AUIPC;
|
||||
HpmRpt evt_LOAD;
|
||||
HpmRpt evt_STORE;
|
||||
HpmRpt evt_LR;
|
||||
HpmRpt evt_SC;
|
||||
HpmRpt evt_AMO;
|
||||
HpmRpt evt_SERIAL_SHIFT;
|
||||
HpmRpt evt_INT_MUL_DIV_REM;
|
||||
HpmRpt evt_FP;
|
||||
HpmRpt evt_SC_SUCCESS;
|
||||
HpmRpt evt_LOAD_WAIT;
|
||||
HpmRpt evt_STORE_WAIT;
|
||||
HpmRpt evt_FENCE;
|
||||
HpmRpt evt_F_BUSY_NO_CONSUME; // XXX
|
||||
HpmRpt evt_D_BUSY_NO_CONSUME; // XXX
|
||||
HpmRpt evt_1_BUSY_NO_CONSUME; // XXX
|
||||
HpmRpt evt_2_BUSY_NO_CONSUME; // XXX
|
||||
HpmRpt evt_3_BUSY_NO_CONSUME; // XXX
|
||||
HpmRpt evt_IMPRECISE_SETBOUND; // XXX
|
||||
HpmRpt evt_UNREPRESENTABLE_CAP; // XXX
|
||||
HpmRpt evt_MEM_CAP_LOAD;
|
||||
HpmRpt evt_MEM_CAP_STORE;
|
||||
HpmRpt evt_MEM_CAP_LOAD_TAG_SET;
|
||||
HpmRpt evt_MEM_CAP_STORE_TAG_SET;
|
||||
} EventsCoreMem deriving (Bits, FShow); // Memory needs more space for reporting delays
|
||||
typedef TDiv#(SizeOf#(EventsCoreMem),Report_Width) EventsCoreMemElements;
|
||||
`endif
|
||||
|
||||
@@ -69,11 +69,12 @@ typedef struct {
|
||||
typedef struct {
|
||||
Bool cap_writable;
|
||||
Bool cap_readable;
|
||||
Bool cap_dirty;
|
||||
} PTEUpperType deriving (Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
PTEUpperType pteUpperType;
|
||||
Bit#(8) reserved;
|
||||
Bit#(7) reserved;
|
||||
Ppn ppn;
|
||||
Bit#(2) reserved_sw; // reserved for supervisor software
|
||||
PTEType pteType;
|
||||
@@ -222,12 +223,15 @@ function TlbPermissionCheck hasVMPermission(
|
||||
end
|
||||
end
|
||||
|
||||
Exception excCode = excLoadPageFault; // Unused default. Just choose one valid option.
|
||||
|
||||
// check execute/read/write permission
|
||||
case(access)
|
||||
InstFetch: begin
|
||||
if(!pte_type.executable) begin
|
||||
fault = True;
|
||||
end
|
||||
excCode = excLoadPageFault;
|
||||
end
|
||||
DataLoad: begin
|
||||
// need to consider mstatus.mxr bit
|
||||
@@ -235,34 +239,39 @@ function TlbPermissionCheck hasVMPermission(
|
||||
!(pte_type.executable && vm_info.exeReadable)) begin
|
||||
fault = True;
|
||||
end
|
||||
excCode = excLoadPageFault;
|
||||
end
|
||||
DataStore: begin
|
||||
// store requires page to be both readable and writable
|
||||
if(!(pte_type.readable && pte_type.writable)) begin
|
||||
fault = True;
|
||||
excCode = excStorePageFault;
|
||||
end
|
||||
else if(cap && !pte_upper_type.cap_writable) begin
|
||||
fault = True;
|
||||
excCode = excStoreCapPageFault;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
TlbPermissionCheck ret = TlbPermissionCheck {
|
||||
allowed: !fault,
|
||||
excCode: access == DataStore ? excStorePageFault : excLoadPageFault,
|
||||
excCode: excCode,
|
||||
allowCap: pte_upper_type.cap_readable};
|
||||
|
||||
if (!fault) begin
|
||||
if (cap && access == DataStore && !pte_upper_type.cap_writable) begin
|
||||
// check if accessed or dirty bit needs to be set
|
||||
if(cap && access == DataStore && !pte_upper_type.cap_dirty) begin
|
||||
ret.allowed = False;
|
||||
ret.excCode = excStoreCapPageFault;
|
||||
end else begin
|
||||
// check if accessed or dirty bit needs to be set
|
||||
if(!pte_type.accessed) begin
|
||||
ret.allowed = False;
|
||||
ret.excCode = access == DataStore ? excStorePageFault : excLoadPageFault;
|
||||
end
|
||||
if(access == DataStore && !pte_type.dirty) begin
|
||||
ret.allowed = False;
|
||||
ret.excCode = access == DataStore ? excStorePageFault : excLoadPageFault;
|
||||
end
|
||||
end
|
||||
if(access == DataStore && !pte_type.dirty) begin
|
||||
ret.allowed = False;
|
||||
ret.excCode = excStorePageFault;
|
||||
end
|
||||
if(!pte_type.accessed) begin
|
||||
ret.allowed = False;
|
||||
ret.excCode = access == DataStore ? excStorePageFault : excLoadPageFault;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -293,15 +293,16 @@ module mkP3_Core (P3_Core_IFC);
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
let master0_synth <- toAXI4_Master_Synth(corew.cpu_imem_master);
|
||||
let master1_synth <- toAXI4_Master_Synth(corew.cpu_dmem_master);
|
||||
// ----------------------------------------------------------------
|
||||
// Core CPU interfaces
|
||||
|
||||
// CPU IMem to Fabric master interface
|
||||
interface AXI4_Master_Synth master0 = corew.cpu_imem_master;
|
||||
interface AXI4_Master_Synth master0 = master0_synth;
|
||||
|
||||
// CPU DMem to Fabric master interface
|
||||
interface AXI4_Master_Synth master1 = corew.cpu_dmem_master;
|
||||
interface AXI4_Master_Synth master1 = master1_synth;
|
||||
|
||||
// External interrupts
|
||||
method Action interrupt_reqs (Bit #(N_External_Interrupt_Sources) reqs);
|
||||
|
||||
@@ -2696,6 +2696,26 @@
|
||||
<spirit:fileType>verilogSource</spirit:fileType>
|
||||
<spirit:userFileType>IMPORTED_FILE</spirit:userFileType>
|
||||
</spirit:file>
|
||||
<spirit:file>
|
||||
<spirit:name>hdl/module_capChecksExec.v</spirit:name>
|
||||
<spirit:fileType>verilogSource</spirit:fileType>
|
||||
<spirit:userFileType>IMPORTED_FILE</spirit:userFileType>
|
||||
</spirit:file>
|
||||
<spirit:file>
|
||||
<spirit:name>hdl/module_capChecksMem.v</spirit:name>
|
||||
<spirit:fileType>verilogSource</spirit:fileType>
|
||||
<spirit:userFileType>IMPORTED_FILE</spirit:userFileType>
|
||||
</spirit:file>
|
||||
<spirit:file>
|
||||
<spirit:name>hdl/mkAxiLowPower.v</spirit:name>
|
||||
<spirit:fileType>verilogSource</spirit:fileType>
|
||||
<spirit:userFileType>IMPORTED_FILE</spirit:userFileType>
|
||||
</spirit:file>
|
||||
<spirit:file>
|
||||
<spirit:name>hdl/mkPLIC_16_CoreNumX2_7.v</spirit:name>
|
||||
<spirit:fileType>verilogSource</spirit:fileType>
|
||||
<spirit:userFileType>IMPORTED_FILE</spirit:userFileType>
|
||||
</spirit:file>
|
||||
<spirit:file>
|
||||
<spirit:name>hdl/module_decode.v</spirit:name>
|
||||
<spirit:fileType>verilogSource</spirit:fileType>
|
||||
|
||||
@@ -64,11 +64,30 @@ interface Boot_ROM_IFC;
|
||||
method Action set_addr_map (Fabric_Addr addr_base, Fabric_Addr addr_lim);
|
||||
|
||||
// Main Fabric Reqs/Rsps
|
||||
interface AXI4_Slave_Synth #(Wd_SId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User,
|
||||
Wd_AR_User, Wd_R_User) slave;
|
||||
interface AXI4_Slave #(Wd_SId, Wd_Addr, Wd_Data_Periph, 0, 0, 0, 0, 0)
|
||||
slave;
|
||||
endinterface
|
||||
|
||||
// ================================================================
|
||||
// Some local help-functions
|
||||
|
||||
function Bool fn_addr_is_aligned (Fabric_Addr addr, AXI4_Size arsize);
|
||||
if (arsize == 1) return True;
|
||||
else if (arsize == 2) return (addr [0] == 1'b_0);
|
||||
else if (arsize == 4) return (addr [1:0] == 2'b_00);
|
||||
else if (arsize == 8) return (addr [2:0] == 3'b_000);
|
||||
else return False;
|
||||
endfunction
|
||||
|
||||
function Bool fn_addr_is_in_range (Fabric_Addr base, Fabric_Addr addr, Fabric_Addr lim);
|
||||
return ((base <= addr) && (addr < lim));
|
||||
endfunction
|
||||
|
||||
function Bool fn_addr_is_ok (Fabric_Addr base, Fabric_Addr addr, Fabric_Addr lim, AXI4_Size arsize);
|
||||
return ( fn_addr_is_aligned (addr, arsize)
|
||||
&& fn_addr_is_in_range (base, addr, lim));
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
|
||||
(* synthesize *)
|
||||
@@ -85,30 +104,10 @@ module mkBoot_ROM (Boot_ROM_IFC);
|
||||
// ----------------
|
||||
// Connector to fabric
|
||||
|
||||
AXI4_Slave_Width_Xactor#(Wd_SId, Wd_Addr, Wd_Data_Periph, Wd_Data,
|
||||
Wd_AW_User_Periph, Wd_W_User_Periph, Wd_B_User_Periph, Wd_AR_User_Periph, Wd_R_User_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User) slave_xactor <- mkAXI4_Slave_Zeroing_Xactor;
|
||||
let slavePortShim <- mkAXI4ShimFF;
|
||||
|
||||
// ----------------
|
||||
|
||||
function Bool fn_addr_is_aligned (Fabric_Addr addr);
|
||||
if (valueOf (Wd_Data) == 32)
|
||||
return (addr [1:0] == 2'b_00);
|
||||
else if (valueOf (Wd_Data) == 64)
|
||||
return (addr [2:0] == 3'b_000);
|
||||
else
|
||||
return False;
|
||||
endfunction
|
||||
|
||||
function Bool fn_addr_is_in_range (Fabric_Addr base, Fabric_Addr addr, Fabric_Addr lim);
|
||||
return ((base <= addr) && (addr < lim));
|
||||
endfunction
|
||||
|
||||
function Bool fn_addr_is_ok (Fabric_Addr base, Fabric_Addr addr, Fabric_Addr lim);
|
||||
return ( fn_addr_is_aligned (addr)
|
||||
&& fn_addr_is_in_range (base, addr, lim));
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// BEHAVIOR
|
||||
|
||||
@@ -116,34 +115,37 @@ module mkBoot_ROM (Boot_ROM_IFC);
|
||||
// Handle fabric read requests
|
||||
|
||||
rule rl_process_rd_req (rg_module_ready);
|
||||
let rda <- get(slave_xactor.master.ar);
|
||||
|
||||
let byte_addr = rda.araddr - rg_addr_base;
|
||||
let rda <- get(slavePortShim.master.ar);
|
||||
|
||||
AXI4_Resp rresp = OKAY;
|
||||
Bit #(64) data64 = 0;
|
||||
if (! fn_addr_is_ok (rg_addr_base, rda.araddr, rg_addr_lim)) begin
|
||||
|
||||
if (! fn_addr_is_ok (rg_addr_base, rda.araddr, rg_addr_lim, rda.arsize)) begin
|
||||
rresp = SLVERR;
|
||||
$display ("%0d: ERROR: Boot_ROM.rl_process_rd_req: unrecognized addr", cur_cycle);
|
||||
$display ("%0d: ERROR: Boot_ROM.rl_process_rd_req: unrecognized or misaligned addr",
|
||||
cur_cycle);
|
||||
$display (" ", fshow (rda));
|
||||
end
|
||||
else if (rda.araddr [2:0] == 3'b0) begin
|
||||
Bit #(32) d0 = fn_read_ROM_0 (byte_addr);
|
||||
Bit #(32) d1 = fn_read_ROM_4 (byte_addr + 4);
|
||||
data64 = { d1, d0 };
|
||||
end
|
||||
else begin // ((valueOf (Wd_Data) == 32) && (rda.addr [1:0] == 2'b_00))
|
||||
Bit #(32) d1 = fn_read_ROM_4 (byte_addr);
|
||||
data64 = { 0, d1 };
|
||||
else begin
|
||||
// Byte offset
|
||||
let byte_offset = rda.araddr - rg_addr_base;
|
||||
let rom_addr_0 = (byte_offset & (~ 'b_111));
|
||||
Bit #(32) d0 = fn_read_ROM_0 (rom_addr_0);
|
||||
let rom_addr_4 = (rom_addr_0 | 'b_100);
|
||||
Bit #(32) d4 = fn_read_ROM_4 (rom_addr_4);
|
||||
if ((valueOf (Wd_Data) == 32) && (byte_offset [2] == 1'b_1))
|
||||
data64 = { 0, d4 };
|
||||
else
|
||||
data64 = { d4, d0 };
|
||||
end
|
||||
|
||||
Bit #(Wd_Data) rdata = truncate (data64);
|
||||
let rdr = AXI4_RFlit {rid: rda.arid,
|
||||
rdata: rdata,
|
||||
rresp: rresp,
|
||||
rlast: True,
|
||||
ruser: rda.aruser}; // XXX This requires that Wd_AR_User == Wd_R_User
|
||||
slave_xactor.master.r.put(rdr);
|
||||
Bit #(Wd_Data_Periph) rdata = truncate (data64);
|
||||
AXI4_RFlit#(Wd_SId, Wd_Data_Periph, 0) rdr = AXI4_RFlit {rid: rda.arid,
|
||||
rdata: rdata,
|
||||
rresp: rresp,
|
||||
rlast: True,
|
||||
ruser: 0};
|
||||
slavePortShim.master.r.put(rdr);
|
||||
|
||||
if (verbosity > 0) begin
|
||||
$display ("%0d: Boot_ROM.rl_process_rd_req: ", cur_cycle);
|
||||
@@ -156,20 +158,21 @@ module mkBoot_ROM (Boot_ROM_IFC);
|
||||
// Handle fabric write requests: ignore all of them (this is a ROM)
|
||||
|
||||
rule rl_process_wr_req (rg_module_ready);
|
||||
let wra <- get(slave_xactor.master.aw);
|
||||
let wrd <- get(slave_xactor.master.w);
|
||||
let wra <- get(slavePortShim.master.aw);
|
||||
let wrd <- get(slavePortShim.master.w);
|
||||
|
||||
AXI4_Resp bresp = OKAY;
|
||||
if (! fn_addr_is_ok (rg_addr_base, wra.awaddr, rg_addr_lim)) begin
|
||||
if (! fn_addr_is_ok (rg_addr_base, wra.awaddr, rg_addr_lim, wra.awsize)) begin
|
||||
bresp = SLVERR;
|
||||
$display ("%0d: ERROR: Boot_ROM.rl_process_wr_req: unrecognized addr", cur_cycle);
|
||||
$display ("%0d: ERROR: Boot_ROM.rl_process_wr_req: unrecognized or misaligned addr",
|
||||
cur_cycle);
|
||||
$display (" ", fshow (wra));
|
||||
end
|
||||
|
||||
let wrr = AXI4_BFlit {bid: wra.awid,
|
||||
bresp: bresp,
|
||||
buser: wra.awuser}; // XXX This requires that Wd_AW_User == Wd_B_User
|
||||
slave_xactor.master.b.put(wrr);
|
||||
AXI4_BFlit#(Wd_SId, 0) wrr = AXI4_BFlit {bid: wra.awid,
|
||||
bresp: bresp,
|
||||
buser: 0};
|
||||
slavePortShim.master.b.put(wrr);
|
||||
|
||||
if (verbosity > 0) begin
|
||||
$display ("%0d: Boot_ROM.rl_process_wr_req; ignoring all writes", cur_cycle);
|
||||
@@ -206,14 +209,13 @@ module mkBoot_ROM (Boot_ROM_IFC);
|
||||
rg_addr_base <= addr_base;
|
||||
rg_addr_lim <= addr_lim;
|
||||
rg_module_ready <= True;
|
||||
slave_xactor.clear;
|
||||
if (verbosity > 0) begin
|
||||
$display ("%0d: Boot_ROM.set_addr_map: base 0x%0h lim 0x%0h", cur_cycle, addr_base, addr_lim);
|
||||
end
|
||||
endmethod
|
||||
|
||||
// Main Fabric Reqs/Rsps
|
||||
interface slave = slave_xactor.slaveSynth;
|
||||
interface slave = slavePortShim.slave;
|
||||
endmodule
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -207,8 +207,8 @@ interface Mem_Controller_IFC;
|
||||
method Action set_addr_map (Fabric_Addr addr_base, Fabric_Addr addr_lim);
|
||||
|
||||
// Main Fabric Reqs/Rsps
|
||||
interface AXI4_Slave_Synth #(Wd_SId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User) slave;
|
||||
interface AXI4_Slave #(Wd_SId, Wd_Addr, Wd_Data, 0, 0, 0, 0, 0)
|
||||
slave;
|
||||
|
||||
// To raw memory (outside the SoC)
|
||||
interface MemoryClient #(Bits_per_Raw_Mem_Addr, Bits_per_Raw_Mem_Word) to_raw_mem;
|
||||
@@ -269,9 +269,7 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF;
|
||||
|
||||
// Communication with fabric
|
||||
AXI4_Slave_Width_Xactor#(Wd_SId, Wd_Addr, Wd_Data_Periph, Wd_Data,
|
||||
Wd_AW_User_Periph, Wd_W_User_Periph, Wd_B_User_Periph, Wd_AR_User_Periph, Wd_R_User_Periph,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User) slave_xactor <- mkAXI4_Slave_Zeroing_Xactor;
|
||||
let slavePortShim <- mkAXI4ShimFF;
|
||||
|
||||
// Requests merged from the (WrA, WrD) and RdA channels
|
||||
FIFOF #(Req) f_reqs <- mkPipelineFIFOF;
|
||||
@@ -304,7 +302,7 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
|
||||
function Action fa_reset_actions;
|
||||
action
|
||||
slave_xactor.clear;
|
||||
slavePortShim.clear;
|
||||
f_raw_mem_reqs.clear;
|
||||
f_raw_mem_rsps.clear;
|
||||
rg_status <= 0;
|
||||
@@ -345,7 +343,7 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
// Merge requests into a single queue, prioritizing reads over writes
|
||||
|
||||
rule rl_merge_rd_req;
|
||||
let rda <- get(slave_xactor.master.ar);
|
||||
let rda <- get(slavePortShim.master.ar);
|
||||
let req = Req {req_op: REQ_OP_RD,
|
||||
id: rda.arid,
|
||||
addr: rda.araddr,
|
||||
@@ -370,8 +368,8 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
|
||||
(* descending_urgency = "rl_merge_rd_req, rl_merge_wr_req" *)
|
||||
rule rl_merge_wr_req;
|
||||
let wra <- get(slave_xactor.master.aw);
|
||||
let wrd <- get(slave_xactor.master.w);
|
||||
let wra <- get(slavePortShim.master.aw);
|
||||
let wrd <- get(slavePortShim.master.w);
|
||||
let req = Req {req_op: REQ_OP_WR,
|
||||
id: wra.awid,
|
||||
addr: wra.awaddr,
|
||||
@@ -504,8 +502,8 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
rdata: rdata,
|
||||
rresp: OKAY,
|
||||
rlast: True,
|
||||
ruser: f_reqs.first.user}; // XXX This requires that Wd_AR_User == Wd_R_User
|
||||
slave_xactor.master.r.put(rdr);
|
||||
ruser: 0'b0};
|
||||
slavePortShim.master.r.put(rdr);
|
||||
f_reqs.deq;
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
@@ -546,8 +544,8 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
|
||||
let wrr = AXI4_BFlit {bid: f_reqs.first.id,
|
||||
bresp: OKAY,
|
||||
buser: f_reqs.first.user}; // XXX This requires that Wd_AW_User == Wd_B_User
|
||||
slave_xactor.master.b.put(wrr);
|
||||
buser: 0'b0};
|
||||
slavePortShim.master.b.put(wrr);
|
||||
f_reqs.deq;
|
||||
|
||||
if (cfg_verbosity > 1) begin
|
||||
@@ -616,8 +614,8 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
rdata: rdata, // for debugging only
|
||||
rresp: SLVERR,
|
||||
rlast: True,
|
||||
ruser: f_reqs.first.user}; // XXX This requires that Wd_AR_User == Wd_R_User
|
||||
slave_xactor.master.r.put(rdr);
|
||||
ruser: 0'b0};
|
||||
slavePortShim.master.r.put(rdr);
|
||||
f_reqs.deq;
|
||||
|
||||
$write ("%0d: ERROR: Mem_Controller:", cur_cycle);
|
||||
@@ -635,8 +633,8 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
&& (f_reqs.first.req_op == REQ_OP_WR));
|
||||
let wrr = AXI4_BFlit {bid: f_reqs.first.id,
|
||||
bresp: SLVERR,
|
||||
buser: f_reqs.first.user}; // XXX This requires that Wd_AW_User == Wd_B_User
|
||||
slave_xactor.master.b.put(wrr);
|
||||
buser: 0'b0};
|
||||
slavePortShim.master.b.put(wrr);
|
||||
f_reqs.deq;
|
||||
|
||||
$write ("%0d: ERROR: Mem_Controller:", cur_cycle);
|
||||
@@ -671,7 +669,7 @@ module mkMem_Controller (Mem_Controller_IFC);
|
||||
endmethod
|
||||
|
||||
// Main Fabric Reqs/Rsps
|
||||
interface slave = slave_xactor.slaveSynth;
|
||||
interface slave = slavePortShim.slave;
|
||||
|
||||
// To raw memory (outside the SoC)
|
||||
interface to_raw_mem = toGPClient (f_raw_mem_reqs, f_raw_mem_rsps);
|
||||
|
||||
@@ -153,16 +153,14 @@ module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
// SoC Boot ROM
|
||||
Boot_ROM_IFC boot_rom <- mkBoot_ROM;
|
||||
// AXI4 Deburster in front of Boot_ROM
|
||||
AXI4_Shim#(Wd_SId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User)
|
||||
boot_rom_axi4_deburster <- mkBurstToNoBurst;
|
||||
AXI4_Shim#(Wd_SId, Wd_Addr, Wd_Data, 0, 0, 0, 0, 0)
|
||||
boot_rom_axi4_deburster <- mkBurstToNoBurst;
|
||||
|
||||
// SoC Memory
|
||||
Mem_Controller_IFC mem0_controller <- mkMem_Controller;
|
||||
// AXI4 Deburster in front of SoC Memory
|
||||
AXI4_Shim#(Wd_SId, Wd_Addr, Wd_Data,
|
||||
Wd_AW_User, Wd_W_User, Wd_B_User, Wd_AR_User, Wd_R_User)
|
||||
mem0_controller_axi4_deburster <- mkBurstToNoBurst;
|
||||
AXI4_Shim#(Wd_SId, Wd_Addr, Wd_Data, 0, 0, 0, 0, 0)
|
||||
mem0_controller_axi4_deburster <- mkBurstToNoBurst;
|
||||
|
||||
// SoC IPs
|
||||
UART_IFC uart0 <- mkUART;
|
||||
@@ -176,9 +174,9 @@ module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
// SoC fabric master connections
|
||||
// Note: see 'SoC_Map' for 'master_num' definitions
|
||||
|
||||
Vector#(Num_Masters, AXI4_Master_Synth #(TAdd#(Wd_MId,1), Wd_Addr, Wd_Data,
|
||||
0, 0, 0, 0, 0))
|
||||
master_vector = newVector;
|
||||
Vector#(Num_Masters, AXI4_Master #(TAdd#(Wd_MId,1), Wd_Addr, Wd_Data,
|
||||
0, 0, 0, 0, 0))
|
||||
master_vector = newVector;
|
||||
|
||||
// CPU IMem master to fabric
|
||||
master_vector[imem_master_num] = corew.cpu_imem_master;
|
||||
@@ -190,30 +188,28 @@ module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
// SoC fabric slave connections
|
||||
// Note: see 'SoC_Map' for 'slave_num' definitions
|
||||
|
||||
Vector#(Num_Slaves, AXI4_Slave_Synth #(Wd_SId, Wd_Addr, Wd_Data,
|
||||
0, 0, 0, 0, 0))
|
||||
slave_vector = newVector;
|
||||
Vector#(Num_Slaves, Range#(Wd_Addr)) route_vector = newVector;
|
||||
Vector#(Num_Slaves, AXI4_Slave #(Wd_SId, Wd_Addr, Wd_Data,
|
||||
0, 0, 0, 0, 0))
|
||||
slave_vector = newVector;
|
||||
Vector#(Num_Slaves, Range#(Wd_Addr)) route_vector = newVector;
|
||||
|
||||
// Fabric to Boot ROM
|
||||
let br <- fromAXI4_Slave_Synth(boot_rom.slave);
|
||||
mkConnection(boot_rom_axi4_deburster.master, br);
|
||||
slave_vector[boot_rom_slave_num] <- toAXI4_Slave_Synth(zeroSlaveUserFields(boot_rom_axi4_deburster.slave));
|
||||
mkConnection(boot_rom_axi4_deburster.master, boot_rom.slave);
|
||||
slave_vector[boot_rom_slave_num] = boot_rom_axi4_deburster.slave;
|
||||
route_vector[boot_rom_slave_num] = soc_map.m_boot_rom_addr_range;
|
||||
|
||||
// Fabric to Mem Controller
|
||||
let mem <- fromAXI4_Slave_Synth(mem0_controller.slave);
|
||||
mkConnection(mem0_controller_axi4_deburster.master, mem);
|
||||
slave_vector[mem0_controller_slave_num] <- toAXI4_Slave_Synth(zeroSlaveUserFields(mem0_controller_axi4_deburster.slave));
|
||||
mkConnection(mem0_controller_axi4_deburster.master, mem0_controller.slave);
|
||||
slave_vector[mem0_controller_slave_num] = mem0_controller_axi4_deburster.slave;
|
||||
route_vector[mem0_controller_slave_num] = soc_map.m_mem0_controller_addr_range;
|
||||
|
||||
// Fabric to UART0
|
||||
slave_vector[uart0_slave_num] <- toAXI4_Slave_Synth(zeroSlaveUserFields(uart0.slave));
|
||||
slave_vector[uart0_slave_num] = zeroSlaveUserFields(uart0.slave);
|
||||
route_vector[uart0_slave_num] = soc_map.m_uart0_addr_range;
|
||||
|
||||
`ifdef INCLUDE_ACCEL0
|
||||
// Fabric to accel0
|
||||
slave_vector[accel0_slave_num] <- liftAXI4_Slave_Synth(zeroSlaveUserFields, accel0.slave);
|
||||
slave_vector[accel0_slave_num] = zeroSlaveUserFields (accel0.slave);
|
||||
route_vector[accel0_slave_num] = soc_map.m_accel0_addr_range;
|
||||
`endif
|
||||
|
||||
@@ -225,8 +221,8 @@ module mkSoC_Top #(Reset dm_power_on_reset)
|
||||
`endif
|
||||
|
||||
// SoC Fabric
|
||||
let bus <- mkAXI4Bus_Synth (routeFromMappingTable(route_vector),
|
||||
master_vector, slave_vector);
|
||||
let bus <- mkAXI4Bus (routeFromMappingTable(route_vector),
|
||||
master_vector, slave_vector);
|
||||
|
||||
// ----------------
|
||||
// Connect interrupt sources for CPU external interrupt request inputs.
|
||||
|
||||
Reference in New Issue
Block a user